@gajae-code/coding-agent 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -0
- package/dist/types/append-only-mode.d.ts +31 -0
- package/dist/types/capability/rule.d.ts +8 -0
- package/dist/types/cli/completion-cli.d.ts +41 -0
- package/dist/types/cli/config-cli.d.ts +1 -0
- package/dist/types/cli/fixture-report.d.ts +20 -0
- package/dist/types/cli/fixture-report.test.d.ts +1 -0
- package/dist/types/cli/nofile-limit.d.ts +11 -0
- package/dist/types/cli/notify-cli.d.ts +7 -0
- package/dist/types/cli/update-cli.d.ts +22 -0
- package/dist/types/cli.d.ts +124 -1
- package/dist/types/commands/completion.d.ts +29 -0
- package/dist/types/commands/config.d.ts +3 -0
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/file-lock.d.ts +7 -6
- package/dist/types/config/keybindings.d.ts +2 -2
- package/dist/types/config/model-profile-activation.d.ts +6 -0
- package/dist/types/config/settings-schema.d.ts +105 -1
- package/dist/types/config/settings.d.ts +8 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/export/ttsr.d.ts +14 -3
- package/dist/types/extensibility/extensions/runner.d.ts +2 -1
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +39 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +10 -1
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +17 -2
- package/dist/types/gjc-runtime/session-state-sidecar.d.ts +7 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +3 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +28 -1
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +42 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +120 -13
- package/dist/types/goals/runtime.d.ts +1 -0
- package/dist/types/hooks/native-skill-hook.d.ts +12 -0
- package/dist/types/main.d.ts +4 -1
- package/dist/types/modes/components/assistant-message.d.ts +5 -1
- package/dist/types/modes/components/model-selector.d.ts +4 -0
- package/dist/types/modes/components/queued-message-selector.d.ts +12 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +9 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +5 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -3
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/print-mode.d.ts +13 -1
- package/dist/types/modes/prompt-action-autocomplete.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-types.d.ts +14 -0
- package/dist/types/modes/shared/agent-wire/event-contract.d.ts +19 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +23 -1
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +1 -0
- package/dist/types/notifications/config.d.ts +14 -1
- package/dist/types/notifications/daemon-paths.d.ts +1 -0
- package/dist/types/notifications/index.d.ts +6 -3
- package/dist/types/notifications/lifecycle-commands.d.ts +11 -3
- package/dist/types/notifications/telegram-daemon.d.ts +23 -3
- package/dist/types/notifications/telegram-reference.d.ts +0 -5
- package/dist/types/notifications/threaded-render.d.ts +6 -0
- package/dist/types/runtime-api-key.d.ts +7 -0
- package/dist/types/sdk.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +53 -1
- package/dist/types/session/agent-storage.d.ts +1 -0
- package/dist/types/session/file-mention-pruning.d.ts +8 -0
- package/dist/types/session/messages.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +17 -1
- package/dist/types/skill-state/active-state.d.ts +18 -1
- package/dist/types/system-prompt.d.ts +18 -2
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/fork-context-budget.d.ts +7 -0
- package/dist/types/task/token-log.d.ts +30 -0
- package/dist/types/task/token-log.test.d.ts +1 -0
- package/dist/types/tools/bisect.d.ts +81 -0
- package/dist/types/tools/computer.d.ts +2 -2
- package/dist/types/tools/index.d.ts +1 -0
- package/dist/types/tools/search.d.ts +2 -2
- package/dist/types/utils/file-mentions.d.ts +14 -0
- package/dist/types/utils/git.d.ts +32 -0
- package/dist/types/web/scrapers/youtube.d.ts +8 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +8 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +50 -0
- package/dist/types/workflow/workflow-intent-report-schema.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-report.d.ts +48 -0
- package/package.json +7 -7
- package/src/append-only-mode.ts +58 -0
- package/src/autoresearch/prompt.md +1 -1
- package/src/autoresearch/tools/log-experiment.ts +1 -1
- package/src/capability/rule.ts +9 -0
- package/src/cli/completion-cli.ts +234 -0
- package/src/cli/config-cli.ts +61 -9
- package/src/cli/fast-help.ts +1 -0
- package/src/cli/fixture-report.test.ts +230 -0
- package/src/cli/fixture-report.ts +171 -0
- package/src/cli/nofile-limit.ts +48 -0
- package/src/cli/notify-cli.ts +91 -7
- package/src/cli/update-cli.ts +85 -9
- package/src/cli.ts +29 -1
- package/src/commands/completion.ts +84 -0
- package/src/commands/config.ts +2 -0
- package/src/commands/contribution-prep.ts +1 -1
- package/src/commands/deep-interview.ts +2 -1
- package/src/config/file-lock.ts +73 -34
- package/src/config/keybindings.ts +2 -2
- package/src/config/model-profile-activation.ts +65 -0
- package/src/config/model-registry.ts +14 -2
- package/src/config/settings-schema.ts +68 -1
- package/src/config/settings.ts +22 -0
- package/src/coordinator-mcp/server.ts +34 -8
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +50 -18
- package/src/defaults/gjc/skills/ralplan/SKILL.md +40 -99
- package/src/defaults/gjc/skills/team/SKILL.md +17 -14
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +59 -4
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +30 -0
- package/src/defaults/gjc-defaults.ts +9 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/index.ts +1 -0
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +60 -2
- package/src/export/ttsr.ts +96 -18
- package/src/extensibility/extensions/runner.ts +183 -219
- package/src/extensibility/extensions/types.ts +9 -0
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +156 -44
- package/src/gjc-runtime/deep-interview-ambiguity.ts +206 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +62 -8
- package/src/gjc-runtime/deep-interview-runtime.ts +210 -2
- package/src/gjc-runtime/deep-interview-state.ts +44 -2
- package/src/gjc-runtime/session-state-sidecar.ts +263 -20
- package/src/gjc-runtime/state-runtime.ts +12 -2
- package/src/gjc-runtime/state-writer.ts +15 -0
- package/src/gjc-runtime/team-runtime.ts +187 -15
- package/src/gjc-runtime/ultragoal-guard.ts +55 -66
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +315 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1663 -159
- package/src/gjc-runtime/workflow-manifest.generated.json +113 -2
- package/src/gjc-runtime/workflow-manifest.ts +74 -1
- package/src/goals/runtime.ts +10 -2
- package/src/hindsight/backend.ts +1 -3
- package/src/hooks/native-skill-hook.ts +124 -4
- package/src/internal-urls/docs-index.generated.ts +16 -7
- package/src/main.ts +95 -43
- package/src/memories/index.ts +12 -1
- package/src/modes/components/assistant-message.ts +241 -82
- package/src/modes/components/custom-editor.ts +1 -0
- package/src/modes/components/model-selector.ts +54 -11
- package/src/modes/components/queued-message-selector.ts +92 -0
- package/src/modes/components/settings-selector.ts +4 -0
- package/src/modes/components/status-line.ts +167 -54
- package/src/modes/components/tool-execution.ts +44 -19
- package/src/modes/components/welcome.ts +160 -44
- package/src/modes/controllers/command-controller.ts +40 -4
- package/src/modes/controllers/event-controller.ts +66 -47
- package/src/modes/controllers/extension-ui-controller.ts +4 -10
- package/src/modes/controllers/input-controller.ts +180 -18
- package/src/modes/controllers/selector-controller.ts +122 -27
- package/src/modes/interactive-mode.ts +51 -16
- package/src/modes/print-mode.ts +43 -4
- package/src/modes/prompt-action-autocomplete.ts +21 -20
- package/src/modes/rpc/rpc-mode.ts +29 -3
- package/src/modes/rpc/rpc-types.ts +9 -0
- package/src/modes/shared/agent-wire/command-validation.ts +4 -0
- package/src/modes/shared/agent-wire/event-contract.ts +22 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +82 -0
- package/src/modes/shared/agent-wire/scopes.ts +1 -0
- package/src/modes/types.ts +1 -0
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +19 -6
- package/src/notifications/config.ts +25 -5
- package/src/notifications/daemon-paths.ts +2 -0
- package/src/notifications/index.ts +117 -14
- package/src/notifications/lifecycle-commands.ts +37 -7
- package/src/notifications/lifecycle-orchestrator.ts +19 -6
- package/src/notifications/telegram-daemon-cli.ts +2 -2
- package/src/notifications/telegram-daemon-control.ts +5 -3
- package/src/notifications/telegram-daemon.ts +302 -51
- package/src/notifications/telegram-reference.ts +0 -16
- package/src/notifications/threaded-render.ts +17 -1
- package/src/prompts/agents/architect.md +19 -10
- package/src/prompts/agents/critic.md +16 -18
- package/src/prompts/agents/executor.md +14 -11
- package/src/prompts/agents/planner.md +18 -13
- package/src/prompts/ci-green-request.md +3 -8
- package/src/prompts/goals/goal-continuation.md +0 -5
- package/src/prompts/goals/goal-mode-active.md +0 -5
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/plan-mode-subagent.md +3 -3
- package/src/prompts/system/project-prompt.md +0 -13
- package/src/prompts/system/subagent-system-prompt.md +3 -2
- package/src/prompts/system/system-prompt.md +29 -19
- package/src/prompts/system/volatile-project-context.md +10 -0
- package/src/prompts/system/web-search.md +4 -7
- package/src/prompts/tools/apply-patch.md +6 -0
- package/src/prompts/tools/ast-edit.md +1 -0
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/bisect.md +22 -0
- package/src/prompts/tools/browser.md +1 -1
- package/src/prompts/tools/computer.md +2 -2
- package/src/prompts/tools/cron.md +0 -2
- package/src/prompts/tools/eval.md +2 -2
- package/src/prompts/tools/find.md +1 -1
- package/src/prompts/tools/github.md +6 -6
- package/src/prompts/tools/goal.md +1 -3
- package/src/prompts/tools/image-gen.md +12 -5
- package/src/prompts/tools/irc.md +5 -4
- package/src/prompts/tools/job.md +2 -2
- package/src/prompts/tools/lsp.md +1 -1
- package/src/prompts/tools/monitor.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/replace.md +2 -21
- package/src/prompts/tools/rewind.md +1 -1
- package/src/prompts/tools/search-tool-bm25.md +1 -11
- package/src/prompts/tools/search.md +1 -1
- package/src/prompts/tools/skill.md +3 -2
- package/src/prompts/tools/ssh.md +2 -1
- package/src/prompts/tools/subagent.md +2 -2
- package/src/prompts/tools/task.md +4 -5
- package/src/prompts/tools/todo-write.md +1 -1
- package/src/prompts/tools/vim.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/prompts/tools/write.md +8 -2
- package/src/runtime-api-key.ts +16 -0
- package/src/sdk.ts +52 -28
- package/src/session/agent-session.ts +951 -132
- package/src/session/agent-storage.ts +4 -0
- package/src/session/file-mention-pruning.ts +64 -0
- package/src/session/messages.ts +4 -0
- package/src/session/session-manager.ts +103 -4
- package/src/skill-state/active-state.ts +141 -5
- package/src/skill-state/deep-interview-mutation-guard.ts +67 -3
- package/src/slash-commands/builtin-registry.ts +218 -71
- package/src/system-prompt.ts +57 -16
- package/src/task/executor.ts +132 -24
- package/src/task/fork-context-advisory.ts +2 -7
- package/src/task/fork-context-budget.ts +9 -0
- package/src/task/index.ts +13 -6
- package/src/task/output-manager.ts +20 -8
- package/src/task/receipt.ts +26 -7
- package/src/task/token-log.test.ts +188 -0
- package/src/task/token-log.ts +179 -0
- package/src/tools/bisect.ts +367 -0
- package/src/tools/computer.ts +246 -43
- package/src/tools/index.ts +3 -0
- package/src/tools/output-meta.ts +116 -4
- package/src/tools/search.ts +8 -2
- package/src/tools/skill.ts +15 -0
- package/src/tools/telegram-send.ts +6 -0
- package/src/utils/file-mentions.ts +39 -7
- package/src/utils/git.ts +73 -0
- package/src/web/scrapers/youtube.ts +24 -12
- package/src/workflow/workflow-intent-diff.ts +29 -6
- package/src/workflow/workflow-intent-report-consumer.ts +221 -0
- package/src/workflow/workflow-intent-report-schema.ts +129 -0
- package/src/workflow/workflow-intent-report.ts +135 -0
|
@@ -21,6 +21,25 @@ export interface WelcomeComponentOptions {
|
|
|
21
21
|
collapseChangelog?: boolean;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
const WELCOME_STATIC_RIGHT_ROWS_EXCLUDING_DYNAMIC_SECTIONS = 9;
|
|
25
|
+
const DEFAULT_WHATS_NEW_ROWS = 3;
|
|
26
|
+
const MAX_WHATS_NEW_ROWS = 12;
|
|
27
|
+
const NEWLINE_FLOW_KEY =
|
|
28
|
+
process.platform === "win32" ? { key: "alt+enter", label: "newline" } : { key: "ctrl+j", label: "newline" };
|
|
29
|
+
|
|
30
|
+
const FLOW_KEY_ITEMS: ReadonlyArray<{ key: string; label: string }> = [
|
|
31
|
+
{ key: "/", label: "commands" },
|
|
32
|
+
{ key: "#", label: "actions" },
|
|
33
|
+
{ key: "!", label: "shell" },
|
|
34
|
+
{ key: "$", label: "python" },
|
|
35
|
+
{ key: "?", label: "keymap" },
|
|
36
|
+
{ key: "ctrl+l", label: "model" },
|
|
37
|
+
{ key: "shift+tab", label: "reasoning" },
|
|
38
|
+
{ key: "tab", label: "complete" },
|
|
39
|
+
NEWLINE_FLOW_KEY,
|
|
40
|
+
{ key: "ctrl+c", label: "clear" },
|
|
41
|
+
];
|
|
42
|
+
|
|
24
43
|
/**
|
|
25
44
|
* GJC-native launch surface with compact command affordances, project
|
|
26
45
|
* signals, and a claw/talon mark without copying another agent shell.
|
|
@@ -97,7 +116,6 @@ export class WelcomeComponent implements Component {
|
|
|
97
116
|
}
|
|
98
117
|
const targetContentRows = targetRows === undefined ? undefined : Math.max(0, targetRows - 2);
|
|
99
118
|
const dualContentWidth = boxWidth - 3; // 3 = │ + │ + │
|
|
100
|
-
const preferredLeftCol = 40;
|
|
101
119
|
const minLeftCol = 20; // logo mark plus GJC identity labels
|
|
102
120
|
const minRightCol = 24;
|
|
103
121
|
const modelPill = this.#pill(theme.icon.model || "model", this.modelName, "statusLineModel");
|
|
@@ -112,10 +130,12 @@ export class WelcomeComponent implements Component {
|
|
|
112
130
|
visibleWidth(modelPill),
|
|
113
131
|
visibleWidth(providerPill),
|
|
114
132
|
);
|
|
115
|
-
const
|
|
133
|
+
const evenLeftCol = Math.floor(dualContentWidth / 2);
|
|
134
|
+
const maxLeftColWithRightMinimum = Math.max(1, dualContentWidth - minRightCol);
|
|
135
|
+
const desiredLeftCol = Math.max(leftMinContentWidth, evenLeftCol);
|
|
116
136
|
const dualLeftCol =
|
|
117
137
|
dualContentWidth >= minRightCol + 1
|
|
118
|
-
? Math.min(desiredLeftCol,
|
|
138
|
+
? Math.min(desiredLeftCol, maxLeftColWithRightMinimum)
|
|
119
139
|
: Math.max(1, dualContentWidth - 1);
|
|
120
140
|
const dualRightCol = Math.max(1, dualContentWidth - dualLeftCol);
|
|
121
141
|
const showRightColumn = dualLeftCol >= leftMinContentWidth && dualRightCol >= minRightCol;
|
|
@@ -142,26 +162,6 @@ export class WelcomeComponent implements Component {
|
|
|
142
162
|
|
|
143
163
|
const rightColumnWidth = showRightColumn ? rightCol : leftCol;
|
|
144
164
|
const separator = buildSeparator(rightColumnWidth);
|
|
145
|
-
const changelogBudget = Math.max(1, Math.min(6, Math.floor((targetContentRows ?? 18) * 0.3)));
|
|
146
|
-
|
|
147
|
-
const sessionLines: string[] = [];
|
|
148
|
-
if (this.recentSessions.length === 0) {
|
|
149
|
-
sessionLines.push(` ${theme.fg("dim", "No saved trails")}`);
|
|
150
|
-
} else {
|
|
151
|
-
const bulletPrefix = ` ${theme.md.bullet} `;
|
|
152
|
-
const prefixWidth = visibleWidth(bulletPrefix);
|
|
153
|
-
for (const session of this.recentSessions.slice(0, 3)) {
|
|
154
|
-
const timeSuffixRaw = ` (${session.timeAgo})`;
|
|
155
|
-
const timeWidth = visibleWidth(timeSuffixRaw);
|
|
156
|
-
const nameBudget = Math.max(1, rightColumnWidth - prefixWidth - timeWidth);
|
|
157
|
-
const nameVis = visibleWidth(session.name);
|
|
158
|
-
const name = nameVis > nameBudget ? truncateToWidth(session.name, nameBudget) : session.name;
|
|
159
|
-
sessionLines.push(
|
|
160
|
-
`${theme.fg("dim", bulletPrefix)}${theme.fg("muted", name)}${theme.fg("dim", timeSuffixRaw)}`,
|
|
161
|
-
);
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
165
|
const lspLines: string[] = [];
|
|
166
166
|
if (this.lspServers.length === 0) {
|
|
167
167
|
lspLines.push(` ${theme.fg("dim", "No LSP servers")}`);
|
|
@@ -178,25 +178,31 @@ export class WelcomeComponent implements Component {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
+
const flowPreferredRows = this.#flowKeyRows(rightColumnWidth).length;
|
|
182
|
+
const changelogRowLimit = this.#whatsNewRowLimit(targetContentRows, lspLines.length, flowPreferredRows);
|
|
183
|
+
const changelogLines = this.#whatsNewLines(rightColumnWidth, changelogRowLimit);
|
|
184
|
+
const flowRowLimit = this.#flowKeyRowLimit(
|
|
185
|
+
targetContentRows,
|
|
186
|
+
changelogLines.length,
|
|
187
|
+
lspLines.length,
|
|
188
|
+
rightColumnWidth,
|
|
189
|
+
);
|
|
190
|
+
const flowLines = this.#flowKeyLines(rightColumnWidth, flowRowLimit);
|
|
191
|
+
const sessionLimit = this.#sessionTrailLimit(
|
|
192
|
+
targetContentRows,
|
|
193
|
+
changelogLines.length,
|
|
194
|
+
lspLines.length,
|
|
195
|
+
flowLines.length,
|
|
196
|
+
);
|
|
197
|
+
const sessionLines = this.#sessionTrailLines(rightColumnWidth, sessionLimit);
|
|
198
|
+
|
|
181
199
|
const rightLines = [
|
|
182
200
|
"",
|
|
183
201
|
` ${theme.bold(theme.fg("accent", "What's New"))}`,
|
|
184
|
-
...
|
|
202
|
+
...changelogLines,
|
|
185
203
|
separator,
|
|
186
204
|
` ${theme.bold(theme.fg("accent", "Flow keys"))}`,
|
|
187
|
-
|
|
188
|
-
"dim",
|
|
189
|
-
"#",
|
|
190
|
-
)}${theme.fg("muted", " actions")}`,
|
|
191
|
-
` ${theme.fg("dim", "!")}${theme.fg("muted", " shell")} ${theme.fg("dim", "·")} ${theme.fg("dim", "$")}${theme.fg(
|
|
192
|
-
"muted",
|
|
193
|
-
" python",
|
|
194
|
-
)}`,
|
|
195
|
-
` ${theme.fg("dim", "?")}${theme.fg("muted", " keymap")} ${theme.fg("dim", "·")} ${theme.fg(
|
|
196
|
-
"dim",
|
|
197
|
-
"ctrl+l",
|
|
198
|
-
)}${theme.fg("muted", " model")}`,
|
|
199
|
-
` ${theme.fg("dim", "shift+tab")}${theme.fg("muted", " reasoning")}`,
|
|
205
|
+
...flowLines,
|
|
200
206
|
separator,
|
|
201
207
|
` ${theme.bold(theme.fg("accent", "Project pulse"))}`,
|
|
202
208
|
...lspLines,
|
|
@@ -315,7 +321,118 @@ export class WelcomeComponent implements Component {
|
|
|
315
321
|
return [...Array.from({ length: topPad }, () => ""), ...clipped, ...Array.from({ length: bottomPad }, () => "")];
|
|
316
322
|
}
|
|
317
323
|
|
|
318
|
-
#
|
|
324
|
+
#flowKeyItemText(item: { key: string; label: string }): string {
|
|
325
|
+
return `${theme.fg("dim", item.key)}${theme.fg("muted", ` ${item.label}`)}`;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
#flowKeyRows(width: number): string[] {
|
|
329
|
+
const contentWidth = Math.max(1, width - 1);
|
|
330
|
+
const separator = ` ${theme.fg("dim", "·")} `;
|
|
331
|
+
const rows: string[] = [];
|
|
332
|
+
let current = "";
|
|
333
|
+
for (const item of FLOW_KEY_ITEMS) {
|
|
334
|
+
const segment = this.#flowKeyItemText(item);
|
|
335
|
+
const next = current ? `${current}${separator}${segment}` : segment;
|
|
336
|
+
if (current && visibleWidth(next) > contentWidth) {
|
|
337
|
+
rows.push(` ${current}`);
|
|
338
|
+
current = segment;
|
|
339
|
+
} else {
|
|
340
|
+
current = next;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
if (current) rows.push(` ${current}`);
|
|
344
|
+
return rows.length > 0 ? rows : [` ${theme.fg("dim", "No flow keys")}`];
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
#flowKeyLines(width: number, maxRows: number): string[] {
|
|
348
|
+
const rows = this.#flowKeyRows(width);
|
|
349
|
+
const rowLimit = Math.max(1, Math.floor(maxRows));
|
|
350
|
+
if (rows.length <= rowLimit) return rows;
|
|
351
|
+
if (rowLimit === 1) {
|
|
352
|
+
const firstItem = FLOW_KEY_ITEMS[0];
|
|
353
|
+
const firstSegment = firstItem ? this.#flowKeyItemText(firstItem) : theme.fg("dim", "keys");
|
|
354
|
+
return [this.#fitToWidth(` ${firstSegment} ${theme.fg("dim", "· … ")}${theme.bold("/help")}`, width)];
|
|
355
|
+
}
|
|
356
|
+
return [...rows.slice(0, rowLimit - 1), ` ${theme.fg("dim", `… ${theme.bold("/help")} for more`)}`];
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
#flowKeyRowLimit(
|
|
360
|
+
targetContentRows: number | undefined,
|
|
361
|
+
changelogLineCount: number,
|
|
362
|
+
lspLineCount: number,
|
|
363
|
+
rightColumnWidth: number,
|
|
364
|
+
): number {
|
|
365
|
+
const preferredRows = this.#flowKeyRows(rightColumnWidth).length;
|
|
366
|
+
if (targetContentRows === undefined) return preferredRows;
|
|
367
|
+
|
|
368
|
+
const sessionBaselineRows = this.recentSessions.length === 0 ? 1 : Math.min(3, this.recentSessions.length);
|
|
369
|
+
const availableRows =
|
|
370
|
+
targetContentRows -
|
|
371
|
+
WELCOME_STATIC_RIGHT_ROWS_EXCLUDING_DYNAMIC_SECTIONS -
|
|
372
|
+
changelogLineCount -
|
|
373
|
+
lspLineCount -
|
|
374
|
+
sessionBaselineRows;
|
|
375
|
+
return Math.max(1, Math.min(preferredRows, availableRows));
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
#whatsNewRowLimit(targetContentRows: number | undefined, lspLineCount: number, flowLineCount: number): number {
|
|
379
|
+
if (targetContentRows === undefined) return 5;
|
|
380
|
+
|
|
381
|
+
const sessionBaselineRows = this.recentSessions.length === 0 ? 1 : Math.min(3, this.recentSessions.length);
|
|
382
|
+
const dynamicRows = Math.max(
|
|
383
|
+
1,
|
|
384
|
+
targetContentRows - WELCOME_STATIC_RIGHT_ROWS_EXCLUDING_DYNAMIC_SECTIONS - flowLineCount - lspLineCount,
|
|
385
|
+
);
|
|
386
|
+
const rowsAfterBaselineSessions = Math.max(1, dynamicRows - sessionBaselineRows);
|
|
387
|
+
const spareRows = Math.max(0, rowsAfterBaselineSessions - DEFAULT_WHATS_NEW_ROWS);
|
|
388
|
+
return Math.max(
|
|
389
|
+
1,
|
|
390
|
+
Math.min(MAX_WHATS_NEW_ROWS, rowsAfterBaselineSessions, DEFAULT_WHATS_NEW_ROWS + Math.floor(spareRows / 2)),
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
#sessionTrailLimit(
|
|
395
|
+
targetContentRows: number | undefined,
|
|
396
|
+
changelogLineCount: number,
|
|
397
|
+
lspLineCount: number,
|
|
398
|
+
flowLineCount: number,
|
|
399
|
+
): number {
|
|
400
|
+
if (this.recentSessions.length === 0) return 0;
|
|
401
|
+
|
|
402
|
+
const defaultLimit = Math.min(3, this.recentSessions.length);
|
|
403
|
+
if (targetContentRows === undefined) return defaultLimit;
|
|
404
|
+
|
|
405
|
+
const rowsWithDefaultTrail =
|
|
406
|
+
WELCOME_STATIC_RIGHT_ROWS_EXCLUDING_DYNAMIC_SECTIONS +
|
|
407
|
+
changelogLineCount +
|
|
408
|
+
flowLineCount +
|
|
409
|
+
lspLineCount +
|
|
410
|
+
defaultLimit;
|
|
411
|
+
const extraRows = Math.max(0, targetContentRows - rowsWithDefaultTrail);
|
|
412
|
+
return Math.min(this.recentSessions.length, defaultLimit + extraRows);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
#sessionTrailLines(rightColumnWidth: number, limit: number): string[] {
|
|
416
|
+
if (this.recentSessions.length === 0) {
|
|
417
|
+
return [` ${theme.fg("dim", "No saved trails")}`];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const bulletPrefix = ` ${theme.md.bullet} `;
|
|
421
|
+
const prefixWidth = visibleWidth(bulletPrefix);
|
|
422
|
+
const lines: string[] = [];
|
|
423
|
+
for (const session of this.recentSessions.slice(0, limit)) {
|
|
424
|
+
const timeSuffixRaw = ` (${session.timeAgo})`;
|
|
425
|
+
const timeWidth = visibleWidth(timeSuffixRaw);
|
|
426
|
+
const nameBudget = Math.max(1, rightColumnWidth - prefixWidth - timeWidth);
|
|
427
|
+
const nameVis = visibleWidth(session.name);
|
|
428
|
+
const name = nameVis > nameBudget ? truncateToWidth(session.name, nameBudget) : session.name;
|
|
429
|
+
lines.push(`${theme.fg("dim", bulletPrefix)}${theme.fg("muted", name)}${theme.fg("dim", timeSuffixRaw)}`);
|
|
430
|
+
}
|
|
431
|
+
return lines;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
#whatsNewLines(width: number, maxRows: number): string[] {
|
|
435
|
+
const rowLimit = Math.max(1, Math.floor(maxRows));
|
|
319
436
|
const changelog = this.options.changelogMarkdown?.trim();
|
|
320
437
|
if (!changelog) {
|
|
321
438
|
return [` ${theme.fg("dim", "Ready for your next prompt")}`];
|
|
@@ -326,25 +443,25 @@ export class WelcomeComponent implements Component {
|
|
|
326
443
|
return [
|
|
327
444
|
` ${theme.fg("muted", `Updated to v${version}`)}`,
|
|
328
445
|
` ${theme.fg("dim", `Use ${theme.bold("/changelog")} for details`)}`,
|
|
329
|
-
];
|
|
446
|
+
].slice(0, rowLimit);
|
|
330
447
|
}
|
|
331
448
|
|
|
332
|
-
const itemLimit = Math.max(1, Math.floor(maxItems));
|
|
333
449
|
const items = this.#changelogItems(changelog);
|
|
334
450
|
if (items.length === 0) {
|
|
335
451
|
return [
|
|
336
452
|
` ${theme.fg("muted", `Updated to v${version}`)}`,
|
|
337
453
|
` ${theme.fg("dim", `Use ${theme.bold("/changelog")} for details`)}`,
|
|
338
|
-
];
|
|
454
|
+
].slice(0, rowLimit);
|
|
339
455
|
}
|
|
340
456
|
|
|
341
457
|
const prefix = ` ${theme.md.bullet} `;
|
|
342
458
|
const textWidth = Math.max(1, width - visibleWidth(prefix));
|
|
343
|
-
const
|
|
459
|
+
const visibleItemCount = items.length > rowLimit ? Math.max(1, rowLimit - 1) : rowLimit;
|
|
460
|
+
const visibleItems = items.slice(0, visibleItemCount).map(item => {
|
|
344
461
|
const text = visibleWidth(item) > textWidth ? truncateToWidth(item, textWidth) : item;
|
|
345
462
|
return `${theme.fg("dim", prefix)}${theme.fg("muted", text)}`;
|
|
346
463
|
});
|
|
347
|
-
if (items.length > visibleItems.length) {
|
|
464
|
+
if (items.length > visibleItems.length && visibleItems.length < rowLimit) {
|
|
348
465
|
visibleItems.push(` ${theme.fg("dim", `… ${theme.bold("/changelog")} for full notes`)}`);
|
|
349
466
|
}
|
|
350
467
|
return visibleItems;
|
|
@@ -472,7 +589,6 @@ interface ShineConfig {
|
|
|
472
589
|
/** Center of the shine band along the diagonal, in [0, 1]. */
|
|
473
590
|
pos: number;
|
|
474
591
|
}
|
|
475
|
-
|
|
476
592
|
/**
|
|
477
593
|
* Apply a multi-stop diagonal gradient (bottom-left → top-right) plus an
|
|
478
594
|
* optional sliding shine band across multi-line art. `phase` (0..1) shifts the
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@gajae-code/tui";
|
|
14
14
|
import { formatDuration, Snowflake, setProjectDir } from "@gajae-code/utils";
|
|
15
15
|
import { $ } from "bun";
|
|
16
|
+
import { resolveAppendOnlyMode } from "../../append-only-mode";
|
|
16
17
|
import { jobElapsedMs } from "../../async";
|
|
17
18
|
import { reset as resetCapabilities } from "../../capability";
|
|
18
19
|
import { clearClaudePluginRootsCache } from "../../discovery/helpers";
|
|
@@ -400,7 +401,7 @@ export class CommandController {
|
|
|
400
401
|
{
|
|
401
402
|
const setting = this.ctx.settings.get("provider.appendOnlyContext") ?? "auto";
|
|
402
403
|
const provider = this.ctx.session.model?.provider;
|
|
403
|
-
const mode = setting
|
|
404
|
+
const mode = resolveAppendOnlyMode(setting, provider ?? "");
|
|
404
405
|
const activeLabel = mode ? theme.fg("success", "active") : theme.fg("dim", "inactive");
|
|
405
406
|
const settingLabel = setting === "auto" ? `${setting} (${provider ?? "?"})` : setting;
|
|
406
407
|
info += `${theme.fg("dim", "Append-Only:")} ${activeLabel} (setting: ${settingLabel})\n`;
|
|
@@ -540,7 +541,7 @@ export class CommandController {
|
|
|
540
541
|
const title = showFull ? "Full Changelog" : "Recent Changes";
|
|
541
542
|
const hint = showFull
|
|
542
543
|
? ""
|
|
543
|
-
: `\n\n${theme.fg("dim", "Use")} ${theme.bold("/changelog full")} ${theme.fg("dim", "to view the complete changelog.")}`;
|
|
544
|
+
: `\n\n${theme.fg("dim", "Use")} ${theme.bold("/changelog --full")} ${theme.fg("dim", "to view the complete changelog.")}`;
|
|
544
545
|
|
|
545
546
|
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
546
547
|
this.ctx.chatContainer.addChild(new DynamicBorder());
|
|
@@ -926,8 +927,7 @@ export class CommandController {
|
|
|
926
927
|
this.ctx.streamingMessage = undefined;
|
|
927
928
|
this.ctx.pendingTools.clear();
|
|
928
929
|
|
|
929
|
-
this.ctx.chatContainer.addChild(new
|
|
930
|
-
this.ctx.chatContainer.addChild(new Text(`${theme.fg("accent", `${theme.status.success} ${label}`)}`, 1, 1));
|
|
930
|
+
this.ctx.chatContainer.addChild(new Text(`${theme.fg("accent", `${theme.status.success} ${label}`)}`, 1, 0));
|
|
931
931
|
await this.ctx.reloadTodos();
|
|
932
932
|
this.ctx.ui.requestRender();
|
|
933
933
|
}
|
|
@@ -936,6 +936,42 @@ export class CommandController {
|
|
|
936
936
|
await this.#runNewSessionFlow();
|
|
937
937
|
}
|
|
938
938
|
|
|
939
|
+
async handleContextClearCommand(): Promise<void> {
|
|
940
|
+
if (this.ctx.loadingAnimation) {
|
|
941
|
+
this.ctx.loadingAnimation.stop();
|
|
942
|
+
this.ctx.loadingAnimation = undefined;
|
|
943
|
+
}
|
|
944
|
+
this.ctx.statusContainer.clear();
|
|
945
|
+
|
|
946
|
+
if (this.ctx.session.isCompacting) {
|
|
947
|
+
this.ctx.session.abortCompaction();
|
|
948
|
+
while (this.ctx.session.isCompacting) {
|
|
949
|
+
await Bun.sleep(10);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
if (!(await this.ctx.session.clearContext())) return;
|
|
953
|
+
setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
|
|
954
|
+
|
|
955
|
+
this.ctx.statusLine.invalidate();
|
|
956
|
+
this.ctx.statusLine.setSessionStartTime(Date.now());
|
|
957
|
+
this.ctx.updateEditorTopBorder();
|
|
958
|
+
this.ctx.updateEditorBorderColor();
|
|
959
|
+
this.ctx.ui.requestRender();
|
|
960
|
+
|
|
961
|
+
this.ctx.chatContainer.clear();
|
|
962
|
+
this.ctx.pendingMessagesContainer.clear();
|
|
963
|
+
this.ctx.compactionQueuedMessages = [];
|
|
964
|
+
this.ctx.streamingComponent = undefined;
|
|
965
|
+
this.ctx.streamingMessage = undefined;
|
|
966
|
+
this.ctx.pendingTools.clear();
|
|
967
|
+
|
|
968
|
+
this.ctx.chatContainer.addChild(
|
|
969
|
+
new Text(`${theme.fg("accent", `${theme.status.success} Context cleared`)}`, 1, 0),
|
|
970
|
+
);
|
|
971
|
+
await this.ctx.reloadTodos();
|
|
972
|
+
this.ctx.ui.requestRender();
|
|
973
|
+
}
|
|
974
|
+
|
|
939
975
|
async handleDropCommand(): Promise<void> {
|
|
940
976
|
if (!this.ctx.sessionManager.getSessionFile()) {
|
|
941
977
|
this.ctx.showError("Nothing to drop (in-memory session)");
|
|
@@ -24,10 +24,20 @@ import type { ResolveToolDetails } from "../../tools/resolve";
|
|
|
24
24
|
import { interruptHint } from "../shared";
|
|
25
25
|
import { buildAbortDisplayMessage } from "../utils/abort-message";
|
|
26
26
|
import { ringTerminalBell } from "../utils/terminal-bell";
|
|
27
|
+
import { argsWithPartialJson } from "../utils/ui-helpers";
|
|
27
28
|
|
|
28
29
|
type AgentSessionEventKind = AgentSessionEvent["type"];
|
|
29
30
|
|
|
30
31
|
const IRC_MESSAGE_VISIBLE_TTL_MS = 10_000;
|
|
32
|
+
|
|
33
|
+
/** Test-only performance counters for advisory baseline tests. */
|
|
34
|
+
export const __eventControllerPerfCounters = {
|
|
35
|
+
messageUpdateContentVisits: 0,
|
|
36
|
+
reset(): void {
|
|
37
|
+
this.messageUpdateContentVisits = 0;
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
|
|
31
41
|
const COMPLETION_NOTIFY_COMMAND_TIMEOUT_MS = 10_000;
|
|
32
42
|
|
|
33
43
|
interface CompletionNotifyPayload {
|
|
@@ -100,6 +110,8 @@ export class EventController {
|
|
|
100
110
|
#lastAssistantComponent: AssistantMessageComponent | undefined = undefined;
|
|
101
111
|
#idleCompactionTimer?: NodeJS.Timeout;
|
|
102
112
|
#ircExpiryTimers = new Map<string, NodeJS.Timeout>();
|
|
113
|
+
#toolIntentCache = new Map<string, { args: unknown; intent: string | undefined }>();
|
|
114
|
+
#thinkingContentIndices = new Set<number>();
|
|
103
115
|
#handlers: AgentSessionEventHandlers;
|
|
104
116
|
|
|
105
117
|
constructor(private ctx: InteractiveModeContext) {
|
|
@@ -307,12 +319,14 @@ export class EventController {
|
|
|
307
319
|
} else if (event.message.role === "assistant") {
|
|
308
320
|
this.#lastThinkingCount = 0;
|
|
309
321
|
this.#resetReadGroup();
|
|
322
|
+
this.#toolIntentCache.clear();
|
|
323
|
+
this.#thinkingContentIndices.clear();
|
|
310
324
|
this.ctx.streamingComponent = new AssistantMessageComponent(undefined, this.ctx.hideThinkingBlock, () =>
|
|
311
325
|
this.ctx.ui.requestRender(),
|
|
312
326
|
);
|
|
313
327
|
this.ctx.streamingMessage = event.message;
|
|
314
328
|
this.ctx.chatContainer.addChild(this.ctx.streamingComponent);
|
|
315
|
-
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage);
|
|
329
|
+
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage, { streaming: true });
|
|
316
330
|
this.ctx.ui.requestRender();
|
|
317
331
|
}
|
|
318
332
|
}
|
|
@@ -375,46 +389,53 @@ export class EventController {
|
|
|
375
389
|
async #handleMessageUpdate(event: Extract<AgentSessionEvent, { type: "message_update" }>): Promise<void> {
|
|
376
390
|
if (this.ctx.streamingComponent && event.message.role === "assistant") {
|
|
377
391
|
this.ctx.streamingMessage = event.message;
|
|
378
|
-
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage);
|
|
379
|
-
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
392
|
+
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage, { streaming: true });
|
|
393
|
+
const contentIndex = event.assistantMessageEvent?.contentIndex;
|
|
394
|
+
const changedContent =
|
|
395
|
+
typeof contentIndex === "number" && contentIndex >= 0
|
|
396
|
+
? this.ctx.streamingMessage.content[contentIndex]
|
|
397
|
+
: undefined;
|
|
398
|
+
const contentsToProcess = changedContent ? [changedContent] : this.ctx.streamingMessage.content;
|
|
399
|
+
|
|
400
|
+
if (changedContent?.type === "thinking" && changedContent.thinking.trim()) {
|
|
401
|
+
if (typeof contentIndex === "number") this.#thinkingContentIndices.add(contentIndex);
|
|
402
|
+
const thinkingCount = this.#thinkingContentIndices.size;
|
|
403
|
+
if (thinkingCount > this.#lastThinkingCount) {
|
|
404
|
+
this.#resetReadGroup();
|
|
405
|
+
this.#lastThinkingCount = thinkingCount;
|
|
406
|
+
}
|
|
407
|
+
} else if (!changedContent) {
|
|
408
|
+
const thinkingCount = this.ctx.streamingMessage.content.filter(
|
|
409
|
+
content => content.type === "thinking" && content.thinking.trim(),
|
|
410
|
+
).length;
|
|
411
|
+
if (thinkingCount > this.#lastThinkingCount) {
|
|
412
|
+
this.#resetReadGroup();
|
|
413
|
+
this.#lastThinkingCount = thinkingCount;
|
|
414
|
+
}
|
|
386
415
|
}
|
|
387
416
|
|
|
388
|
-
for (const content of
|
|
417
|
+
for (const content of contentsToProcess) {
|
|
418
|
+
__eventControllerPerfCounters.messageUpdateContentVisits += 1;
|
|
389
419
|
if (content.type !== "toolCall") continue;
|
|
390
420
|
if (content.name === "read") {
|
|
391
|
-
if (!readArgsHaveTarget(content.arguments))
|
|
392
|
-
// Args still streaming — defer until path is parseable so we can route to the
|
|
393
|
-
// read group (regular files) vs ToolExecutionComponent (internal URLs).
|
|
394
|
-
// Creating either component now would lock the read into the wrong shape.
|
|
395
|
-
continue;
|
|
396
|
-
}
|
|
421
|
+
if (!readArgsHaveTarget(content.arguments)) continue;
|
|
397
422
|
if (!readArgsTargetInternalUrl(content.arguments)) {
|
|
398
423
|
this.#trackReadToolCall(content.id, content.arguments);
|
|
399
424
|
const component = this.ctx.pendingTools.get(content.id);
|
|
400
|
-
if (component)
|
|
401
|
-
|
|
402
|
-
} else {
|
|
425
|
+
if (component) component.updateArgs(content.arguments, content.id);
|
|
426
|
+
else {
|
|
403
427
|
const group = this.#getReadGroup();
|
|
404
428
|
group.updateArgs(content.arguments, content.id);
|
|
405
429
|
this.ctx.pendingTools.set(content.id, group);
|
|
406
430
|
}
|
|
407
431
|
continue;
|
|
408
432
|
}
|
|
409
|
-
// Internal URL read falls through to ToolExecutionComponent below.
|
|
410
433
|
}
|
|
411
434
|
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
? { ...content.arguments, __partialJson: content.partialJson }
|
|
417
|
-
: content.arguments;
|
|
435
|
+
const renderArgs = argsWithPartialJson(
|
|
436
|
+
content.arguments,
|
|
437
|
+
"partialJson" in content ? content.partialJson : undefined,
|
|
438
|
+
);
|
|
418
439
|
if (!this.ctx.pendingTools.has(content.id)) {
|
|
419
440
|
this.#resetReadGroup();
|
|
420
441
|
this.ctx.chatContainer.addChild(new Text("", 0, 0));
|
|
@@ -437,32 +458,30 @@ export class EventController {
|
|
|
437
458
|
this.ctx.chatContainer.addChild(component);
|
|
438
459
|
this.ctx.pendingTools.set(content.id, component);
|
|
439
460
|
} else {
|
|
440
|
-
|
|
441
|
-
if (component) {
|
|
442
|
-
component.updateArgs(renderArgs, content.id);
|
|
443
|
-
}
|
|
461
|
+
this.ctx.pendingTools.get(content.id)?.updateArgs(renderArgs, content.id);
|
|
444
462
|
}
|
|
445
|
-
}
|
|
446
463
|
|
|
447
|
-
// Update working message with intent from streamed tool arguments
|
|
448
|
-
for (const content of this.ctx.streamingMessage.content) {
|
|
449
|
-
if (content.type !== "toolCall") continue;
|
|
450
464
|
const args = content.arguments;
|
|
451
465
|
if (!args || typeof args !== "object") continue;
|
|
466
|
+
let intent: string | undefined;
|
|
452
467
|
if (INTENT_FIELD in args) {
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
468
|
+
intent = String(args[INTENT_FIELD]);
|
|
469
|
+
} else {
|
|
470
|
+
const cached = this.#toolIntentCache.get(content.id);
|
|
471
|
+
if (cached?.args === args) intent = cached.intent;
|
|
472
|
+
else {
|
|
473
|
+
const tool = this.ctx.session.getToolByName(content.name);
|
|
474
|
+
if (typeof tool?.intent === "function") {
|
|
475
|
+
try {
|
|
476
|
+
intent = tool.intent(args as never)?.trim();
|
|
477
|
+
} catch {
|
|
478
|
+
// intent function must never break the UI
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
this.#toolIntentCache.set(content.id, { args, intent });
|
|
462
482
|
}
|
|
463
|
-
} catch {
|
|
464
|
-
// intent function must never break the UI
|
|
465
483
|
}
|
|
484
|
+
if (intent) this.#updateWorkingMessageFromIntent(intent);
|
|
466
485
|
}
|
|
467
486
|
|
|
468
487
|
this.ctx.ui.requestRender();
|
|
@@ -495,9 +514,9 @@ export class EventController {
|
|
|
495
514
|
// display only — does NOT mutate the persisted message's stopReason
|
|
496
515
|
// (the marker on errorMessage drives replay-side suppression).
|
|
497
516
|
const msgWithoutAbort = { ...this.ctx.streamingMessage, stopReason: "stop" as const };
|
|
498
|
-
this.ctx.streamingComponent.updateContent(msgWithoutAbort);
|
|
517
|
+
this.ctx.streamingComponent.updateContent(msgWithoutAbort, { streaming: false });
|
|
499
518
|
} else {
|
|
500
|
-
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage);
|
|
519
|
+
this.ctx.streamingComponent.updateContent(this.ctx.streamingMessage, { streaming: false });
|
|
501
520
|
}
|
|
502
521
|
|
|
503
522
|
if (this.ctx.streamingMessage.stopReason !== "aborted" && this.ctx.streamingMessage.stopReason !== "error") {
|
|
@@ -191,9 +191,8 @@ export class ExtensionUiController {
|
|
|
191
191
|
this.ctx.streamingMessage = undefined;
|
|
192
192
|
this.ctx.pendingTools.clear();
|
|
193
193
|
|
|
194
|
-
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
195
194
|
this.ctx.chatContainer.addChild(
|
|
196
|
-
new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1,
|
|
195
|
+
new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 0),
|
|
197
196
|
);
|
|
198
197
|
await this.ctx.reloadTodos();
|
|
199
198
|
this.ctx.ui.requestRender();
|
|
@@ -299,15 +298,14 @@ export class ExtensionUiController {
|
|
|
299
298
|
}
|
|
300
299
|
|
|
301
300
|
#rebuildHookWidgets(): void {
|
|
302
|
-
this.#renderHookWidgetContainer(this.ctx.hookWidgetContainerAbove, this.#hookWidgetsAbove, true
|
|
303
|
-
this.#renderHookWidgetContainer(this.ctx.hookWidgetContainerBelow, this.#hookWidgetsBelow, false
|
|
301
|
+
this.#renderHookWidgetContainer(this.ctx.hookWidgetContainerAbove, this.#hookWidgetsAbove, true);
|
|
302
|
+
this.#renderHookWidgetContainer(this.ctx.hookWidgetContainerBelow, this.#hookWidgetsBelow, false);
|
|
304
303
|
this.ctx.ui.requestRender();
|
|
305
304
|
}
|
|
306
305
|
|
|
307
306
|
#renderHookWidgetContainer(
|
|
308
307
|
container: Container,
|
|
309
308
|
widgets: Map<string, ExtensionUiComponent>,
|
|
310
|
-
spacerWhenEmpty: boolean,
|
|
311
309
|
leadingSpacer: boolean,
|
|
312
310
|
): void {
|
|
313
311
|
// Detach (not dispose): hook widgets are persistent instances owned by the
|
|
@@ -317,9 +315,6 @@ export class ExtensionUiController {
|
|
|
317
315
|
container.detachAll();
|
|
318
316
|
|
|
319
317
|
if (widgets.size === 0) {
|
|
320
|
-
if (spacerWhenEmpty) {
|
|
321
|
-
container.addChild(new Spacer(1));
|
|
322
|
-
}
|
|
323
318
|
return;
|
|
324
319
|
}
|
|
325
320
|
|
|
@@ -434,9 +429,8 @@ export class ExtensionUiController {
|
|
|
434
429
|
this.ctx.streamingMessage = undefined;
|
|
435
430
|
this.ctx.pendingTools.clear();
|
|
436
431
|
|
|
437
|
-
this.ctx.chatContainer.addChild(new Spacer(1));
|
|
438
432
|
this.ctx.chatContainer.addChild(
|
|
439
|
-
new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1,
|
|
433
|
+
new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 0),
|
|
440
434
|
);
|
|
441
435
|
await this.ctx.reloadTodos();
|
|
442
436
|
this.ctx.ui.requestRender();
|