diff --git a/media/main.css b/media/main.css
index ef6b80c..e6c47fa 100644
--- a/media/main.css
+++ b/media/main.css
@@ -375,7 +375,7 @@ body {
gap: 6px;
width: 100%;
padding: 6px 8px;
- border: 1px solid var(--vscode-input-border, rgba(128, 128, 128, 0.35));
+ border: 1px solid transparent;
border-radius: 4px;
background-color: var(--vscode-button-secondaryBackground);
color: var(--vscode-button-secondaryForeground);
@@ -392,6 +392,12 @@ body {
.option-btn:hover {
background-color: var(--vscode-button-secondaryHoverBackground);
border-color: var(--vscode-contrastBorder, rgba(128, 128, 128, 0.3));
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.09);
+}
+
+.option-btn:not(:disabled):active {
+ transform: scale(0.99);
+ transition: transform 0.05s ease, background-color 0.05s ease;
}
.option-btn:focus-visible {
@@ -401,11 +407,9 @@ body {
.option-btn.selected {
border-color: var(--vscode-button-background, #0078d4);
- border-left: 3px solid var(--vscode-button-background, #0078d4);
- background-color: color-mix(in srgb, var(--vscode-button-background, #0078d4) 20%, transparent);
+ border-left: 2px solid var(--vscode-button-background, #0078d4);
+ background-color: color-mix(in srgb, var(--vscode-button-background, #0078d4) 11%, transparent);
color: var(--vscode-foreground);
- padding-left: 8px;
- /* compensate for thicker left border */
}
/* === OPTION BUTTON NEW LAYOUT === */
@@ -644,6 +648,221 @@ body[data-ask-user-options-tooltip="native"] .option-btn-tooltip {
/* Hide separator to save space */
}
+/* =============================================
+ Quick-action buttons (above response input)
+ ============================================= */
+
+.quick-actions-container {
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+ margin-top: 10px;
+}
+
+.quick-actions-container.hidden {
+ display: none;
+}
+
+/* Collapse header — always visible, houses chevron toggle */
+.quick-actions-header {
+ display: flex;
+ justify-content: flex-end;
+ margin-bottom: 2px;
+}
+
+.quick-actions-toggle {
+ width: 20px;
+ height: 16px;
+ padding: 0;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
+ border: none;
+ border-radius: 3px;
+ color: var(--vscode-descriptionForeground);
+ opacity: 0.35;
+ cursor: pointer;
+ transition: opacity 0.15s ease, background 0.15s ease;
+}
+
+.quick-actions-container:hover .quick-actions-toggle,
+.quick-actions-toggle:focus-visible {
+ opacity: 0.75;
+}
+
+.quick-actions-toggle:hover {
+ opacity: 1;
+ background: var(--vscode-toolbar-hoverBackground);
+}
+
+.quick-actions-toggle .codicon {
+ font-size: 11px;
+ transition: transform 0.18s ease;
+}
+
+.quick-actions-container.collapsed .quick-actions-toggle .codicon {
+ transform: rotate(-90deg);
+}
+
+/* Content wrapper — rows + collapse animation */
+.quick-actions-content {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+ overflow: hidden;
+ max-height: 400px;
+ transition: max-height 0.22s ease, opacity 0.18s ease;
+}
+
+.quick-actions-container.collapsed .quick-actions-content {
+ max-height: 0;
+ opacity: 0;
+ pointer-events: none;
+}
+
+@keyframes quickActionsIn {
+ from {
+ opacity: 0;
+ transform: translateY(5px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+/* Each row animates in independently when it becomes visible */
+.quick-actions-row {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 5px;
+ align-items: center;
+}
+
+.quick-actions-row.hidden,
+.quick-actions-row:empty {
+ display: none;
+}
+
+.quick-actions-row:not(.hidden):not(:empty) {
+ animation: quickActionsIn 0.18s cubic-bezier(0.4, 0, 0.2, 1) both;
+}
+
+/* ── Button base ── */
+
+.quick-action-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ height: 24px;
+ padding: 0 10px;
+ border-radius: 3px;
+ border: 1px solid transparent;
+ font-family: var(--vscode-font-family);
+ font-size: calc(var(--vscode-font-size) - 1px);
+ line-height: 1;
+ cursor: pointer;
+ user-select: none;
+ flex-shrink: 0;
+ max-width: 260px;
+ transition: background 0.12s ease, border-color 0.12s ease,
+ color 0.12s ease, opacity 0.12s ease;
+}
+
+.quick-action-btn:focus-visible {
+ outline: 1px solid var(--vscode-focusBorder);
+ outline-offset: 2px;
+}
+
+/* Text span — handles overflow gracefully */
+.quick-action-text {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ line-height: 1.4;
+}
+
+/* ── Default quick-reply buttons — secondary button style ── */
+
+.quick-action-btn.default {
+ background: var(--vscode-button-secondaryBackground);
+ color: var(--vscode-button-secondaryForeground);
+ border-color: transparent;
+}
+
+.quick-action-btn.default:hover {
+ background: var(--vscode-button-secondaryHoverBackground);
+}
+
+/* ── Manage quick-actions gear button ── */
+
+.quick-actions-manage-btn {
+ margin-left: auto;
+ flex-shrink: 0;
+ width: 20px;
+ height: 20px;
+ padding: 0;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ background: transparent;
+ border: none;
+ border-radius: 4px;
+ color: var(--vscode-descriptionForeground);
+ opacity: 0;
+ cursor: pointer;
+ transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
+}
+
+.quick-actions-row:hover .quick-actions-manage-btn,
+.quick-actions-manage-btn:focus-visible {
+ opacity: 0.7;
+}
+
+.quick-actions-manage-btn:hover,
+.quick-actions-manage-btn:focus-visible {
+ background: var(--vscode-toolbar-hoverBackground);
+ color: var(--vscode-foreground);
+ opacity: 1;
+}
+
+.quick-actions-manage-btn .codicon {
+ font-size: 13px;
+}
+
+/* Pressed state */
+.quick-action-btn:active {
+ opacity: 0.8;
+}
+
+/* ── Empty state hint — shown when no defaults are configured ── */
+
+.quick-actions-empty-hint {
+ display: inline-flex;
+ align-items: center;
+ gap: 4px;
+ padding: 0;
+ background: transparent;
+ border: none;
+ font-family: var(--vscode-font-family);
+ font-size: calc(var(--vscode-font-size) - 1px);
+ color: var(--vscode-descriptionForeground);
+ cursor: pointer;
+ opacity: 0.6;
+ transition: opacity 0.12s ease, color 0.12s ease;
+}
+
+.quick-actions-empty-hint:hover {
+ opacity: 1;
+ color: var(--vscode-foreground);
+}
+
+.quick-actions-empty-hint .codicon {
+ font-size: 12px;
+}
+
/* Response section - fixed at bottom */
.response-section {
flex-shrink: 0;
@@ -1039,8 +1258,8 @@ button:disabled {
/* Fix: Limit height and enable scrolling when many attachments are added */
max-height: var(--chips-container-max-height);
overflow-y: auto;
- border-top-left-radius: 8px;
- border-top-right-radius: 8px;
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
}
/* Monaco-style scrollbar for chips container */
diff --git a/media/webview.html b/media/webview.html
index 44c9009..9321a99 100644
--- a/media/webview.html
+++ b/media/webview.html
@@ -144,8 +144,20 @@
+
+
-
@@ -300,12 +312,17 @@
debugMockAskUserMultiStepLongText: "{{debugMockAskUserMultiStepLongText}}",
debugMockPlanReview: "{{debugMockPlanReview}}",
debugMockWalkthroughReview: "{{debugMockWalkthroughReview}}",
+ manageQuickActions: "{{manageQuickActions}}",
+ addQuickAction: "{{addQuickAction}}",
+ configureQuickActions: "{{configureQuickActions}}",
};
window.__CONFIG__ = {
historyTimeDisplay: "{{historyTimeDisplay}}",
askUserOptionsLayout: "{{askUserOptionsLayout}}",
askUserOptionsTooltip: "{{askUserOptionsTooltip}}",
enableToolDebug: "{{enableToolDebug}}" === "true",
+ quickActionDefaults: {{quickActionDefaults}},
+ showQuickActions: "{{showQuickActions}}" === "true",
};
diff --git a/package.json b/package.json
index 33c96d5..ee1e21e 100644
--- a/package.json
+++ b/package.json
@@ -159,6 +159,21 @@
"default": false,
"title": "%config.enableToolDebug.title%",
"markdownDescription": "%config.enableToolDebug.description%"
+ },
+ "seamless-agent.quickActionDefaults": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "default": [],
+ "title": "%config.quickActionDefaults.title%",
+ "markdownDescription": "%config.quickActionDefaults.description%"
+ },
+ "seamless-agent.showQuickActions": {
+ "type": "boolean",
+ "default": true,
+ "title": "%config.showQuickActions.title%",
+ "markdownDescription": "%config.showQuickActions.description%"
}
}
},
diff --git a/package.nls.json b/package.nls.json
index a28c127..e69e8b9 100644
--- a/package.nls.json
+++ b/package.nls.json
@@ -76,6 +76,10 @@
"config.historyTimeDisplay.description": "Choose how timestamps are shown in history items: relative, absolute (ISO 8601), or hybrid (relative under 7 days, ISO after).",
"config.enableToolDebug.title": "Enable Tool Debug",
"config.enableToolDebug.description": "Show a debug tab in the webview for testing mock tool calls without starting a real conversation.",
+ "config.quickActionDefaults.title": "Quick Action Defaults",
+ "config.quickActionDefaults.description": "Quick-action buttons shown above the response input when answering agent questions. Each item becomes a clickable button for one-click responses. Empty by default — add your own labels to enable.",
+ "config.showQuickActions.title": "Show Quick Actions",
+ "config.showQuickActions.description": "Show the quick-action buttons above the response input. When disabled, the quick-action panel is hidden entirely. You can also collapse it per-session using the chevron button.",
"planReview.button.acknowledge": "Acknowledge",
"planReview.button.continue": "Continue",
"planReview.button.done": "Done",
@@ -136,5 +140,9 @@
"debug.mockAskUserMultiStep": "Multi-Step Question",
"debug.mockAskUserMultiStepLongText": "Multi-Step Long Text Options",
"debug.mockPlanReview": "Plan Review",
- "debug.mockWalkthroughReview": "Walkthrough Review"
+ "debug.mockWalkthroughReview": "Walkthrough Review",
+ "webview.toggleQuickActions": "Toggle quick actions",
+ "webview.manageQuickActions": "Manage quick actions",
+ "webview.addQuickAction": "Add quick action",
+ "webview.configureQuickActions": "Configure quick-action buttons"
}
diff --git a/package.nls.pt-br.json b/package.nls.pt-br.json
index e06e79f..77eea48 100644
--- a/package.nls.pt-br.json
+++ b/package.nls.pt-br.json
@@ -68,6 +68,10 @@
"config.historyTimeDisplay.description": "Escolha como os horários aparecem no histórico: relativo, absoluto (ISO 8601) ou híbrido (relativo até 7 dias, ISO após).",
"config.enableToolDebug.title": "Ativar Depuração de Ferramentas",
"config.enableToolDebug.description": "Exibe uma aba de depuração para testar chamadas de ferramentas simuladas sem iniciar uma conversa real.",
+ "config.quickActionDefaults.title": "Ações Rápidas Padrão",
+ "config.quickActionDefaults.description": "Botões de ação rápida exibidos acima da entrada de resposta ao responder perguntas do agente. Cada item se torna um botão clicável para respostas com um clique. Vazio por padrão — adicione seus próprios rótulos para ativar.",
+ "config.showQuickActions.title": "Mostrar Ações Rápidas",
+ "config.showQuickActions.description": "Mostra botões de ações rápidas acima do campo de entrada quando disponíveis. Desative para ocultar esses botões.",
"planReview.button.acknowledge": "Confirmar",
"planReview.button.continue": "Continuar",
"planReview.button.done": "Concluído",
diff --git a/package.nls.pt.json b/package.nls.pt.json
index 9c2f946..4516d92 100644
--- a/package.nls.pt.json
+++ b/package.nls.pt.json
@@ -68,6 +68,10 @@
"config.historyTimeDisplay.description": "Escolha como os horários aparecem no histórico: relativo, absoluto (ISO 8601) ou híbrido (relativo até 7 dias, ISO após).",
"config.enableToolDebug.title": "Ativar Depuração de Ferramentas",
"config.enableToolDebug.description": "Exibe uma aba de depuração para testar chamadas de ferramentas simuladas sem iniciar uma conversa real.",
+ "config.quickActionDefaults.title": "Ações Rápidas Predefinidas",
+ "config.quickActionDefaults.description": "Botões de ação rápida apresentados acima da entrada de resposta ao responder perguntas do agente. Cada item torna-se um botão clicável para respostas com um clique. Vazio por predefinição — adicione os seus próprios rótulos para ativar.",
+ "config.showQuickActions.title": "Mostrar Ações Rápidas",
+ "config.showQuickActions.description": "Controla se os botões de ações rápidas são mostrados acima da entrada de resposta ao interagir com o agente.",
"planReview.button.acknowledge": "Confirmar",
"planReview.button.continue": "Continuar",
"planReview.button.done": "Concluído",
diff --git a/src/localization.ts b/src/localization.ts
index dead4e5..badd902 100644
--- a/src/localization.ts
+++ b/src/localization.ts
@@ -185,6 +185,12 @@ export const strings = {
get debugMockPlanReview() { return localize('debug.mockPlanReview'); },
get debugMockWalkthroughReview() { return localize('debug.mockWalkthroughReview'); },
+ // Quick actions
+ get toggleQuickActions() { return localize('webview.toggleQuickActions'); },
+ get manageQuickActions() { return localize('webview.manageQuickActions'); },
+ get addQuickAction() { return localize('webview.addQuickAction'); },
+ get configureQuickActions() { return localize('webview.configureQuickActions'); },
+
// Errors
get noSuchInteraction() { return localize('error.noSuchInteraction'); },
};
diff --git a/src/webview/main.ts b/src/webview/main.ts
index c9d331c..a39868c 100644
--- a/src/webview/main.ts
+++ b/src/webview/main.ts
@@ -169,12 +169,17 @@ declare global {
debugMockAskUserMultiStepLongText: string;
debugMockPlanReview: string;
debugMockWalkthroughReview: string;
+ manageQuickActions: string;
+ addQuickAction: string;
+ configureQuickActions: string;
};
__CONFIG__: {
historyTimeDisplay: 'relative' | 'absolute' | 'hybrid';
askUserOptionsLayout: 'expanded' | 'compact';
askUserOptionsTooltip: 'native' | 'custom';
enableToolDebug: boolean;
+ quickActionDefaults: string[];
+ showQuickActions: boolean;
};
}
}
@@ -266,6 +271,18 @@ function applyAskUserOptionsTooltipMode(): void {
const cancelBtn = document.getElementById('cancel-btn');
const srAnnounce = document.getElementById('sr-announce');
const optionsContainer = document.getElementById('options-container');
+ const quickActionsContainer = document.getElementById('quick-actions-container');
+ const quickActionsDefault = document.getElementById('quick-actions-default');
+
+ // Session-level collapsed state (persists across question re-renders)
+ let quickActionsCollapsed = false;
+ document.getElementById('quick-actions-toggle')?.addEventListener('click', (e) => {
+ e.stopPropagation();
+ quickActionsCollapsed = !quickActionsCollapsed;
+ quickActionsContainer?.classList.toggle('collapsed', quickActionsCollapsed);
+ const toggleEl = document.getElementById('quick-actions-toggle');
+ if (toggleEl) toggleEl.setAttribute('aria-expanded', String(!quickActionsCollapsed));
+ });
// Apply option layout mode early so all rendered buttons follow the selected setting.
applyAskUserOptionsLayoutMode();
@@ -1102,6 +1119,9 @@ function applyAskUserOptionsTooltipMode(): void {
// Render option buttons if provided
renderOptions(options, multiSelect);
+ // Render quick-action buttons (default quick-reply buttons)
+ renderQuickActions();
+
// Hide ALL other views
homeView?.classList.add('hidden');
requestList?.classList.add('hidden');
@@ -2285,6 +2305,114 @@ function applyAskUserOptionsTooltipMode(): void {
updateChipsDisplay();
}
+ // ================================
+ // Quick-action buttons
+ // ================================
+
+ /**
+ * Render quick-action buttons for the current question.
+ * Shows configurable one-click reply labels.
+ */
+ function renderQuickActions(): void {
+ if (!quickActionsContainer || !quickActionsDefault) return;
+ if (window.__CONFIG__?.showQuickActions === false) {
+ quickActionsContainer.classList.add('hidden');
+ return;
+ }
+
+ clearChildren(quickActionsDefault);
+
+ const defaults: string[] = Array.isArray(window.__CONFIG__?.quickActionDefaults)
+ ? window.__CONFIG__.quickActionDefaults
+ : [];
+
+ // ── Default quick-reply buttons ──
+ for (const label of defaults) {
+ const btn = document.createElement('button');
+ btn.type = 'button';
+ btn.className = 'quick-action-btn default';
+ btn.setAttribute('aria-label', label);
+ btn.title = label;
+
+ const textSpan = document.createElement('span');
+ textSpan.className = 'quick-action-text';
+ textSpan.textContent = label;
+ btn.appendChild(textSpan);
+
+ btn.addEventListener('click', () => {
+ btn.style.opacity = '0.5';
+ btn.style.pointerEvents = 'none';
+ setTimeout(() => submitQuickAction(label), 80);
+ });
+ quickActionsDefault.appendChild(btn);
+ }
+
+ // ── Manage button — gear icon fades in on hover ──
+ const manageBtn = document.createElement('button');
+ manageBtn.type = 'button';
+ manageBtn.className = 'quick-actions-manage-btn';
+ manageBtn.setAttribute('aria-label', window.__STRINGS__?.manageQuickActions || 'Manage quick actions');
+ manageBtn.title = window.__STRINGS__?.manageQuickActions || 'Manage quick actions';
+ const gearIcon = document.createElement('span');
+ gearIcon.className = 'codicon codicon-settings-gear';
+ gearIcon.setAttribute('aria-hidden', 'true');
+ manageBtn.appendChild(gearIcon);
+ manageBtn.addEventListener('click', () => {
+ vscode.postMessage({ type: 'openSettings', query: 'seamless-agent.quickActionDefaults' });
+ });
+
+ if (defaults.length === 0) {
+ // Empty state: show a subtle "add quick action" link
+ const emptyHint = document.createElement('button');
+ emptyHint.type = 'button';
+ emptyHint.className = 'quick-actions-empty-hint';
+ emptyHint.title = window.__STRINGS__?.configureQuickActions || 'Configure quick-action buttons';
+ const addIcon = document.createElement('span');
+ addIcon.className = 'codicon codicon-add';
+ addIcon.setAttribute('aria-hidden', 'true');
+ const hintText = document.createElement('span');
+ hintText.textContent = window.__STRINGS__?.addQuickAction || 'Add quick action';
+ emptyHint.appendChild(addIcon);
+ emptyHint.appendChild(hintText);
+ emptyHint.addEventListener('click', () => {
+ vscode.postMessage({ type: 'openSettings', query: 'seamless-agent.quickActionDefaults' });
+ });
+ quickActionsDefault.appendChild(emptyHint);
+ } else {
+ quickActionsDefault.appendChild(manageBtn);
+ }
+
+ quickActionsContainer.classList.remove('hidden');
+ quickActionsContainer.classList.toggle('collapsed', quickActionsCollapsed);
+ }
+
+ /**
+ * Submit a quick-action response immediately.
+ */
+ function submitQuickAction(text: string): void {
+ if (!currentRequestId) return;
+
+ // Save to input history
+ inputHistoryManager.addToHistory(text);
+ resetRequestState();
+
+ vscode.postMessage({
+ type: 'submit',
+ response: text,
+ requestId: currentRequestId,
+ attachments: currentAttachments,
+ });
+
+ draftResponses.delete(currentRequestId);
+ currentAttachments = [];
+
+ // Reset stepper if active
+ if (activeOptionsStepper) {
+ activeOptionsStepper.destroy();
+ activeOptionsStepper = null;
+ }
+ }
+
/**
* Reset request state: clears input history navigation, and optionally attachments and autocomplete
* @param options.attachments - Whether to also clear attachments (default: false)
@@ -3425,6 +3553,18 @@ function applyAskUserOptionsTooltipMode(): void {
} else if (message.key === 'askUserOptionsTooltip') {
window.__CONFIG__.askUserOptionsTooltip = normalizeAskUserOptionsTooltip(message.value);
applyAskUserOptionsTooltipMode();
+ } else if (message.key === 'quickActionDefaults') {
+ window.__CONFIG__.quickActionDefaults = Array.isArray(message.value) ? message.value : [];
+ renderQuickActions();
+ } else if (message.key === 'showQuickActions') {
+ const showQuickActions = !!message.value;
+ window.__CONFIG__.showQuickActions = showQuickActions;
+ if (showQuickActions) {
+ quickActionsContainer?.classList.remove('hidden');
+ renderQuickActions();
+ } else {
+ quickActionsContainer?.classList.add('hidden');
+ }
}
break;
}
diff --git a/src/webview/types.ts b/src/webview/types.ts
index f639422..759f580 100644
--- a/src/webview/types.ts
+++ b/src/webview/types.ts
@@ -163,7 +163,7 @@ export type ToWebviewMessage = | {
| {
type: 'updateConfig';
key: string;
- value: boolean | string | number;
+ value: boolean | string | number | string[];
}
| {
type: 'clear'
@@ -299,7 +299,8 @@ export type FromWebviewMessage = | {
mockType: 'askUser' | 'askUserOptions' | 'askUserMultiStep' | 'askUserMultiStepLongText' | 'planReview' | 'walkthroughReview';
}
| {
- type: 'openSettings'
+ type: 'openSettings';
+ query?: string;
};
diff --git a/src/webview/webviewProvider.ts b/src/webview/webviewProvider.ts
index a7377cb..dac0794 100644
--- a/src/webview/webviewProvider.ts
+++ b/src/webview/webviewProvider.ts
@@ -153,6 +153,26 @@ export class AgentInteractionProvider implements vscode.WebviewViewProvider {
value: askUserOptionsTooltip,
} as ToWebviewMessage);
}
+
+ if (event.affectsConfiguration('seamless-agent.quickActionDefaults')) {
+ const config = vscode.workspace.getConfiguration('seamless-agent');
+ const quickActionDefaults = config.get('quickActionDefaults', []);
+ webviewView.webview.postMessage({
+ type: 'updateConfig',
+ key: 'quickActionDefaults',
+ value: quickActionDefaults,
+ } as ToWebviewMessage);
+ }
+
+ if (event.affectsConfiguration('seamless-agent.showQuickActions')) {
+ const config = vscode.workspace.getConfiguration('seamless-agent');
+ const showQuickActions = config.get('showQuickActions', true);
+ webviewView.webview.postMessage({
+ type: 'updateConfig',
+ key: 'showQuickActions',
+ value: showQuickActions,
+ } as ToWebviewMessage);
+ }
}, undefined, []);
// Always show home view first (which includes pending requests and recent sessions)
@@ -548,7 +568,8 @@ export class AgentInteractionProvider implements vscode.WebviewViewProvider {
this._handleDebugMockToolCall(message.mockType);
break;
case 'openSettings':
- vscode.commands.executeCommand('workbench.action.openSettings', '@ext:jraylan.seamless-agent');
+ vscode.commands.executeCommand('workbench.action.openSettings',
+ message.query ?? '@ext:jraylan.seamless-agent');
break;
}
}
@@ -1467,6 +1488,8 @@ export class AgentInteractionProvider implements vscode.WebviewViewProvider {
? rawAskUserOptionsTooltip
: 'native';
const enableToolDebug = config.get('enableToolDebug', false);
+ const quickActionDefaults = config.get('quickActionDefaults', []);
+ const showQuickActions = config.get('showQuickActions', true);
// Replace placeholders
const replacements: Record