@oh-my-pi/pi-coding-agent 15.9.67 → 15.10.1
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 +136 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/dry-balance-cli.d.ts +15 -1
- package/dist/types/cli/gallery-cli.d.ts +43 -0
- package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
- package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
- package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
- package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
- package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
- package/dist/types/cli/gallery-screenshot.d.ts +35 -0
- package/dist/types/commands/gallery.d.ts +47 -0
- package/dist/types/commit/analysis/conventional.d.ts +2 -2
- package/dist/types/commit/analysis/summary.d.ts +2 -2
- package/dist/types/commit/changelog/generate.d.ts +2 -2
- package/dist/types/commit/changelog/index.d.ts +2 -2
- package/dist/types/commit/map-reduce/index.d.ts +3 -3
- package/dist/types/commit/map-reduce/map-phase.d.ts +2 -2
- package/dist/types/commit/map-reduce/reduce-phase.d.ts +2 -2
- package/dist/types/commit/model-selection.d.ts +10 -4
- package/dist/types/config/api-key-resolver.d.ts +34 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-id-affixes.d.ts +2 -0
- package/dist/types/config/model-registry.d.ts +25 -2
- package/dist/types/config/settings-schema.d.ts +41 -6
- package/dist/types/dap/config.d.ts +14 -1
- package/dist/types/dap/types.d.ts +10 -0
- package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
- package/dist/types/lsp/types.d.ts +10 -0
- package/dist/types/lsp/utils.d.ts +3 -2
- package/dist/types/main.d.ts +3 -2
- package/dist/types/memory-backend/index.d.ts +2 -1
- package/dist/types/memory-backend/resolve.d.ts +1 -1
- package/dist/types/memory-backend/types.d.ts +1 -1
- package/dist/types/modes/components/chat-block.d.ts +64 -0
- package/dist/types/modes/components/custom-editor.d.ts +5 -1
- package/dist/types/modes/components/overlay-box.d.ts +17 -0
- package/dist/types/modes/components/plan-review-overlay.d.ts +59 -0
- package/dist/types/modes/components/plan-toc.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +18 -0
- package/dist/types/modes/components/transcript-container.d.ts +11 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/event-controller.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +0 -1
- package/dist/types/modes/controllers/input-controller.d.ts +1 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +22 -0
- package/dist/types/modes/controllers/tan-command-controller.d.ts +6 -0
- package/dist/types/modes/index.d.ts +5 -4
- package/dist/types/modes/interactive-mode.d.ts +16 -6
- package/dist/types/modes/setup-version.d.ts +11 -0
- package/dist/types/modes/setup-wizard/index.d.ts +2 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
- package/dist/types/modes/theme/theme.d.ts +1 -1
- package/dist/types/modes/types.d.ts +19 -6
- package/dist/types/modes/utils/copy-targets.d.ts +21 -1
- package/dist/types/plan-mode/approved-plan.d.ts +27 -8
- package/dist/types/plan-mode/plan-protection.d.ts +4 -4
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +21 -0
- package/dist/types/session/messages.d.ts +12 -0
- package/dist/types/session/session-manager.d.ts +3 -1
- package/dist/types/slash-commands/types.d.ts +4 -6
- package/dist/types/task/executor.d.ts +14 -0
- package/dist/types/task/index.d.ts +1 -0
- package/dist/types/task/render.d.ts +3 -2
- package/dist/types/telemetry-export.d.ts +1 -1
- package/dist/types/tools/archive-reader.d.ts +5 -0
- package/dist/types/tools/ast-edit.d.ts +3 -0
- package/dist/types/tools/ast-grep.d.ts +3 -0
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/eval-render.d.ts +1 -8
- package/dist/types/tools/fetch.d.ts +15 -7
- package/dist/types/tools/find.d.ts +8 -4
- package/dist/types/tools/grouped-file-output.d.ts +95 -12
- package/dist/types/tools/memory-render.d.ts +4 -1
- package/dist/types/tools/plan-mode-guard.d.ts +8 -9
- package/dist/types/tools/render-utils.d.ts +13 -9
- package/dist/types/tools/renderers.d.ts +16 -2
- package/dist/types/tools/search.d.ts +5 -1
- package/dist/types/tools/sqlite-reader.d.ts +1 -0
- package/dist/types/tools/todo.d.ts +3 -2
- package/dist/types/tools/write.d.ts +5 -0
- package/dist/types/tui/output-block.d.ts +16 -4
- package/dist/types/tui/status-line.d.ts +3 -0
- package/dist/types/utils/enhanced-paste.d.ts +20 -0
- package/dist/types/web/scrapers/github.d.ts +22 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -1
- package/dist/types/web/search/providers/perplexity.d.ts +8 -1
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +9 -9
- package/scripts/dev-launch +42 -0
- package/scripts/dev-launch-preload.ts +19 -0
- package/src/auto-thinking/classifier.ts +5 -1
- package/src/cli/args.ts +2 -2
- package/src/cli/dry-balance-cli.ts +52 -17
- package/src/cli/gallery-cli.ts +226 -0
- package/src/cli/gallery-fixtures/agentic.ts +292 -0
- package/src/cli/gallery-fixtures/codeintel.ts +188 -0
- package/src/cli/gallery-fixtures/edit.ts +194 -0
- package/src/cli/gallery-fixtures/fs.ts +153 -0
- package/src/cli/gallery-fixtures/index.ts +40 -0
- package/src/cli/gallery-fixtures/interaction.ts +49 -0
- package/src/cli/gallery-fixtures/memory.ts +81 -0
- package/src/cli/gallery-fixtures/misc.ts +250 -0
- package/src/cli/gallery-fixtures/search.ts +213 -0
- package/src/cli/gallery-fixtures/shell.ts +167 -0
- package/src/cli/gallery-fixtures/types.ts +41 -0
- package/src/cli/gallery-fixtures/web.ts +158 -0
- package/src/cli/gallery-screenshot.ts +279 -0
- package/src/cli-commands.ts +1 -0
- package/src/commands/gallery.ts +52 -0
- package/src/commands/launch.ts +1 -1
- package/src/commit/analysis/conventional.ts +2 -2
- package/src/commit/analysis/summary.ts +2 -2
- package/src/commit/changelog/generate.ts +2 -2
- package/src/commit/changelog/index.ts +2 -2
- package/src/commit/map-reduce/index.ts +3 -3
- package/src/commit/map-reduce/map-phase.ts +2 -2
- package/src/commit/map-reduce/reduce-phase.ts +2 -2
- package/src/commit/model-selection.ts +33 -9
- package/src/commit/pipeline.ts +4 -4
- package/src/config/api-key-resolver.ts +58 -0
- package/src/config/keybindings.ts +15 -6
- package/src/config/model-equivalence.ts +35 -12
- package/src/config/model-id-affixes.ts +39 -22
- package/src/config/model-registry.ts +41 -18
- package/src/config/settings-schema.ts +28 -5
- package/src/config/settings.ts +31 -2
- package/src/dap/client.ts +14 -16
- package/src/dap/config.ts +41 -2
- package/src/dap/defaults.json +1 -0
- package/src/dap/session.ts +1 -0
- package/src/dap/types.ts +10 -0
- package/src/debug/index.ts +40 -54
- package/src/edit/renderer.ts +111 -119
- package/src/eval/__tests__/agent-bridge.test.ts +75 -32
- package/src/eval/__tests__/llm-bridge.test.ts +90 -31
- package/src/eval/agent-bridge.ts +34 -7
- package/src/eval/llm-bridge.ts +8 -3
- package/src/extensibility/extensions/runner.ts +1 -0
- package/src/extensibility/plugins/doctor.ts +0 -1
- package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
- package/src/goals/tools/goal-tool.ts +37 -27
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/lsp/client.ts +104 -55
- package/src/lsp/types.ts +10 -0
- package/src/lsp/utils.ts +3 -2
- package/src/main.ts +53 -56
- package/src/memories/index.ts +12 -5
- package/src/memory-backend/index.ts +13 -1
- package/src/memory-backend/resolve.ts +3 -5
- package/src/memory-backend/types.ts +1 -1
- package/src/mnemopi/backend.ts +5 -1
- package/src/modes/acp/acp-agent.ts +33 -26
- package/src/modes/components/assistant-message.ts +2 -9
- package/src/modes/components/chat-block.ts +111 -0
- package/src/modes/components/copy-selector.ts +1 -44
- package/src/modes/components/custom-editor.ts +33 -1
- package/src/modes/components/custom-message.ts +1 -3
- package/src/modes/components/execution-shared.ts +1 -2
- package/src/modes/components/hook-message.ts +1 -3
- package/src/modes/components/overlay-box.ts +108 -0
- package/src/modes/components/plan-review-overlay.ts +799 -0
- package/src/modes/components/plan-toc.ts +138 -0
- package/src/modes/components/read-tool-group.ts +20 -4
- package/src/modes/components/skill-message.ts +0 -1
- package/src/modes/components/status-line.ts +3 -5
- package/src/modes/components/tips.txt +1 -0
- package/src/modes/components/todo-reminder.ts +0 -2
- package/src/modes/components/tool-execution.ts +115 -90
- package/src/modes/components/transcript-container.ts +84 -24
- package/src/modes/components/user-message.ts +1 -2
- package/src/modes/controllers/command-controller-shared.ts +7 -6
- package/src/modes/controllers/command-controller.ts +70 -57
- package/src/modes/controllers/event-controller.ts +41 -40
- package/src/modes/controllers/extension-ui-controller.ts +10 -73
- package/src/modes/controllers/input-controller.ts +135 -122
- package/src/modes/controllers/mcp-command-controller.ts +69 -60
- package/src/modes/controllers/selector-controller.ts +25 -27
- package/src/modes/controllers/streaming-reveal.ts +212 -0
- package/src/modes/controllers/tan-command-controller.ts +173 -0
- package/src/modes/index.ts +5 -4
- package/src/modes/interactive-mode.ts +171 -82
- package/src/modes/setup-version.ts +11 -0
- package/src/modes/setup-wizard/index.ts +3 -2
- package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/theme/theme-schema.json +1 -1
- package/src/modes/theme/theme.ts +8 -4
- package/src/modes/types.ts +19 -8
- package/src/modes/utils/context-usage.ts +10 -6
- package/src/modes/utils/copy-targets.ts +133 -27
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +44 -46
- package/src/plan-mode/approved-plan.ts +66 -43
- package/src/plan-mode/plan-protection.ts +4 -4
- package/src/prompts/system/background-tan-dispatch.md +8 -0
- package/src/prompts/system/plan-mode-active.md +67 -58
- package/src/prompts/system/plan-mode-approved.md +1 -1
- package/src/sdk.ts +32 -60
- package/src/session/agent-session.ts +89 -13
- package/src/session/messages.ts +26 -0
- package/src/session/session-manager.ts +13 -5
- package/src/slash-commands/builtin-registry.ts +37 -10
- package/src/slash-commands/helpers/usage-report.ts +2 -0
- package/src/slash-commands/types.ts +4 -6
- package/src/task/executor.ts +25 -4
- package/src/task/index.ts +4 -0
- package/src/task/render.ts +212 -148
- package/src/telemetry-export.ts +25 -7
- package/src/tools/archive-reader.ts +64 -0
- package/src/tools/ask.ts +119 -164
- package/src/tools/ast-edit.ts +98 -71
- package/src/tools/ast-grep.ts +37 -43
- package/src/tools/bash.ts +50 -6
- package/src/tools/debug.ts +20 -8
- package/src/tools/eval-backends.ts +6 -17
- package/src/tools/eval-render.ts +21 -18
- package/src/tools/eval.ts +5 -4
- package/src/tools/fetch.ts +391 -91
- package/src/tools/find.ts +44 -30
- package/src/tools/gh-renderer.ts +81 -42
- package/src/tools/grouped-file-output.ts +272 -48
- package/src/tools/image-gen.ts +150 -103
- package/src/tools/inspect-image-renderer.ts +63 -41
- package/src/tools/inspect-image.ts +8 -1
- package/src/tools/job.ts +3 -4
- package/src/tools/memory-render.ts +4 -1
- package/src/tools/plan-mode-guard.ts +21 -39
- package/src/tools/read.ts +23 -16
- package/src/tools/render-utils.ts +38 -40
- package/src/tools/renderers.ts +16 -1
- package/src/tools/report-tool-issue.ts +1 -1
- package/src/tools/resolve.ts +14 -0
- package/src/tools/search-tool-bm25.ts +36 -23
- package/src/tools/search.ts +189 -95
- package/src/tools/sqlite-reader.ts +9 -12
- package/src/tools/todo.ts +138 -59
- package/src/tools/write.ts +100 -60
- package/src/tui/output-block.ts +60 -13
- package/src/tui/status-line.ts +5 -1
- package/src/utils/commit-message-generator.ts +9 -1
- package/src/utils/enhanced-paste.ts +202 -0
- package/src/utils/title-generator.ts +2 -1
- package/src/web/scrapers/github.ts +255 -3
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/anthropic.ts +25 -19
- package/src/web/search/providers/exa.ts +11 -3
- package/src/web/search/providers/kimi.ts +28 -17
- package/src/web/search/providers/parallel.ts +35 -24
- package/src/web/search/providers/perplexity.ts +199 -51
- package/src/web/search/providers/synthetic.ts +8 -6
- package/src/web/search/providers/tavily.ts +9 -8
- package/src/web/search/providers/zai.ts +8 -6
- package/src/web/search/render.ts +39 -54
- package/src/web/search/types.ts +5 -1
- package/dist/types/eval/__tests__/shared-executors.test.d.ts +0 -1
- package/src/eval/__tests__/shared-executors.test.ts +0 -609
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
modelsAreEqual,
|
|
21
21
|
type UsageReport,
|
|
22
22
|
} from "@oh-my-pi/pi-ai";
|
|
23
|
-
import type { Component, EditorTheme, SlashCommand } from "@oh-my-pi/pi-tui";
|
|
23
|
+
import type { Component, EditorTheme, LoaderMessageColorFn, OverlayHandle, SlashCommand } from "@oh-my-pi/pi-tui";
|
|
24
24
|
import {
|
|
25
25
|
Container,
|
|
26
26
|
clearRenderCache,
|
|
@@ -65,12 +65,7 @@ import { BUILTIN_SLASH_COMMANDS, loadSlashCommands } from "../extensibility/slas
|
|
|
65
65
|
import type { Goal, GoalModeState } from "../goals/state";
|
|
66
66
|
import { resolveLocalUrlToPath } from "../internal-urls";
|
|
67
67
|
import { LSP_STARTUP_EVENT_CHANNEL, type LspStartupEvent } from "../lsp/startup-events";
|
|
68
|
-
import {
|
|
69
|
-
humanizePlanTitle,
|
|
70
|
-
type PlanApprovalDetails,
|
|
71
|
-
renameApprovedPlanFile,
|
|
72
|
-
resolvePlanTitle,
|
|
73
|
-
} from "../plan-mode/approved-plan";
|
|
68
|
+
import { humanizePlanTitle, type PlanApprovalDetails, resolveApprovedPlan } from "../plan-mode/approved-plan";
|
|
74
69
|
import planModeApprovedPrompt from "../prompts/system/plan-mode-approved.md" with { type: "text" };
|
|
75
70
|
import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compact-instructions.md" with {
|
|
76
71
|
type: "text",
|
|
@@ -94,6 +89,7 @@ import { getSessionAccentAnsi, getSessionAccentHex } from "../utils/session-colo
|
|
|
94
89
|
import { popTerminalTitle, pushTerminalTitle, setSessionTerminalTitle } from "../utils/title-generator";
|
|
95
90
|
import type { AssistantMessageComponent } from "./components/assistant-message";
|
|
96
91
|
import type { BashExecutionComponent } from "./components/bash-execution";
|
|
92
|
+
import { ChatBlock, type ChatBlockHost } from "./components/chat-block";
|
|
97
93
|
import { CustomEditor } from "./components/custom-editor";
|
|
98
94
|
import { DynamicBorder } from "./components/dynamic-border";
|
|
99
95
|
import { ErrorBannerComponent } from "./components/error-banner";
|
|
@@ -101,6 +97,7 @@ import type { EvalExecutionComponent } from "./components/eval-execution";
|
|
|
101
97
|
import type { HookEditorComponent } from "./components/hook-editor";
|
|
102
98
|
import type { HookInputComponent } from "./components/hook-input";
|
|
103
99
|
import type { HookSelectorComponent, HookSelectorSlider } from "./components/hook-selector";
|
|
100
|
+
import { PlanReviewOverlay } from "./components/plan-review-overlay";
|
|
104
101
|
import { StatusLineComponent } from "./components/status-line";
|
|
105
102
|
import type { ToolExecutionHandle } from "./components/tool-execution";
|
|
106
103
|
import { TranscriptContainer } from "./components/transcript-container";
|
|
@@ -114,6 +111,7 @@ import { MCPCommandController } from "./controllers/mcp-command-controller";
|
|
|
114
111
|
import { OmfgController } from "./controllers/omfg-controller";
|
|
115
112
|
import { SelectorController } from "./controllers/selector-controller";
|
|
116
113
|
import { SSHCommandController } from "./controllers/ssh-command-controller";
|
|
114
|
+
import { TanCommandController } from "./controllers/tan-command-controller";
|
|
117
115
|
import { TodoCommandController } from "./controllers/todo-command-controller";
|
|
118
116
|
import {
|
|
119
117
|
consumeLoopLimitIteration,
|
|
@@ -273,7 +271,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
273
271
|
statusLine: StatusLineComponent;
|
|
274
272
|
|
|
275
273
|
isInitialized = false;
|
|
276
|
-
isBackgrounded = false;
|
|
277
274
|
isBashMode = false;
|
|
278
275
|
toolOutputExpanded = false;
|
|
279
276
|
todoExpanded = false;
|
|
@@ -341,12 +338,14 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
341
338
|
#planModePreviousModelState: { model: Model; thinkingLevel?: ThinkingLevel } | undefined;
|
|
342
339
|
#pendingModelSwitch: { model: Model; thinkingLevel?: ThinkingLevel } | undefined;
|
|
343
340
|
#planModeHasEntered = false;
|
|
344
|
-
#
|
|
341
|
+
#planReviewOverlay: PlanReviewOverlay | undefined;
|
|
342
|
+
#planReviewOverlayHandle: OverlayHandle | undefined;
|
|
345
343
|
readonly lspServers: LspStartupServerInfo[] | undefined = undefined;
|
|
346
344
|
mcpManager?: import("../mcp").MCPManager;
|
|
347
345
|
readonly #toolUiContextSetter: (uiContext: ExtensionUIContext, hasUI: boolean) => void;
|
|
348
346
|
|
|
349
347
|
readonly #btwController: BtwController;
|
|
348
|
+
readonly #tanCommandController: TanCommandController;
|
|
350
349
|
readonly #omfgController: OmfgController;
|
|
351
350
|
readonly #commandController: CommandController;
|
|
352
351
|
readonly #todoCommandController: TodoCommandController;
|
|
@@ -365,6 +364,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
365
364
|
#eventBus?: EventBus;
|
|
366
365
|
#eventBusUnsubscribers: Array<() => void> = [];
|
|
367
366
|
#welcomeComponent?: WelcomeComponent;
|
|
367
|
+
readonly #chatHost: ChatBlockHost = { requestRender: () => this.ui.requestRender() };
|
|
368
368
|
|
|
369
369
|
constructor(
|
|
370
370
|
session: AgentSession,
|
|
@@ -470,6 +470,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
470
470
|
|
|
471
471
|
this.#uiHelpers = new UiHelpers(this);
|
|
472
472
|
this.#btwController = new BtwController(this);
|
|
473
|
+
this.#tanCommandController = new TanCommandController(this);
|
|
473
474
|
this.#omfgController = new OmfgController(this);
|
|
474
475
|
this.#extensionUiController = new ExtensionUiController(this);
|
|
475
476
|
this.#eventController = new EventController(this);
|
|
@@ -599,8 +600,9 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
599
600
|
// Load initial todos
|
|
600
601
|
await this.#loadTodoList();
|
|
601
602
|
|
|
602
|
-
// Start the UI
|
|
603
|
-
|
|
603
|
+
// Start the UI. Cold `omp` launch opts into clearing on the first paint so
|
|
604
|
+
// the initial welcome frame does not append over the previous run's scrollback.
|
|
605
|
+
this.ui.start({ clearScrollback: options.clearInitialTerminalHistory === true });
|
|
604
606
|
pushTerminalTitle();
|
|
605
607
|
setSessionTerminalTitle(this.sessionManager.getSessionName(), this.sessionManager.getCwd());
|
|
606
608
|
this.updateEditorBorderColor();
|
|
@@ -1522,22 +1524,15 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1522
1524
|
if (!state?.enabled) {
|
|
1523
1525
|
throw new ToolError("Plan mode is not active.");
|
|
1524
1526
|
}
|
|
1525
|
-
const planFilePath =
|
|
1526
|
-
const planContent = await this.#readPlanFile(planFilePath);
|
|
1527
|
-
if (planContent === null) {
|
|
1528
|
-
throw new ToolError(
|
|
1529
|
-
`Plan file not found at ${planFilePath}. Write the finalized plan to ${planFilePath} before requesting approval.`,
|
|
1530
|
-
);
|
|
1531
|
-
}
|
|
1532
|
-
const normalized = resolvePlanTitle({
|
|
1527
|
+
const { planFilePath, title } = await resolveApprovedPlan({
|
|
1533
1528
|
suppliedTitle: extra?.title,
|
|
1534
|
-
|
|
1535
|
-
|
|
1529
|
+
statePlanFilePath: state.planFilePath,
|
|
1530
|
+
readPlan: url => this.#readPlanFile(url),
|
|
1531
|
+
listPlanFiles: () => this.#listLocalPlanFiles(),
|
|
1536
1532
|
});
|
|
1537
1533
|
const details: PlanApprovalDetails = {
|
|
1538
1534
|
planFilePath,
|
|
1539
|
-
|
|
1540
|
-
title: normalized.title,
|
|
1535
|
+
title,
|
|
1541
1536
|
planExists: true,
|
|
1542
1537
|
};
|
|
1543
1538
|
return {
|
|
@@ -1677,22 +1672,87 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1677
1672
|
}
|
|
1678
1673
|
}
|
|
1679
1674
|
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1675
|
+
/** `local://` URLs of plan files in the session-local root, newest first.
|
|
1676
|
+
* A fallback for `resolveApprovedPlan` when the agent dropped `extra.title`,
|
|
1677
|
+
* so the plan it wrote is still found by scanning recent `*-plan.md` files. */
|
|
1678
|
+
async #listLocalPlanFiles(): Promise<string[]> {
|
|
1679
|
+
const localRoot = this.#resolvePlanFilePath("local://");
|
|
1680
|
+
try {
|
|
1681
|
+
const entries = await fs.readdir(localRoot, { withFileTypes: true });
|
|
1682
|
+
const plans = await Promise.all(
|
|
1683
|
+
entries
|
|
1684
|
+
.filter(entry => entry.isFile() && /plan\.md$/i.test(entry.name))
|
|
1685
|
+
.map(async name => {
|
|
1686
|
+
const stat = await fs.stat(path.join(localRoot, name.name)).catch(() => null);
|
|
1687
|
+
return { url: `local://${name.name}`, mtime: stat?.mtimeMs ?? 0 };
|
|
1688
|
+
}),
|
|
1689
|
+
);
|
|
1690
|
+
return plans.sort((a, b) => b.mtime - a.mtime).map(plan => plan.url);
|
|
1691
|
+
} catch {
|
|
1692
|
+
return [];
|
|
1693
1693
|
}
|
|
1694
|
-
|
|
1694
|
+
}
|
|
1695
|
+
|
|
1696
|
+
showPlanReview(
|
|
1697
|
+
planContent: string,
|
|
1698
|
+
title: string,
|
|
1699
|
+
options: string[],
|
|
1700
|
+
dialogOptions?: {
|
|
1701
|
+
helpText?: string;
|
|
1702
|
+
disabledIndices?: number[];
|
|
1703
|
+
onExternalEditor?: () => void;
|
|
1704
|
+
onPlanEdited?: (content: string) => void;
|
|
1705
|
+
onFeedbackChange?: (feedback: string) => void;
|
|
1706
|
+
initialIndex?: number;
|
|
1707
|
+
},
|
|
1708
|
+
extra?: { slider?: HookSelectorSlider },
|
|
1709
|
+
): Promise<string | undefined> {
|
|
1710
|
+
this.#hidePlanReview();
|
|
1711
|
+
const { promise, resolve } = Promise.withResolvers<string | undefined>();
|
|
1712
|
+
let settled = false;
|
|
1713
|
+
const finish = (choice: string | undefined): void => {
|
|
1714
|
+
if (settled) return;
|
|
1715
|
+
settled = true;
|
|
1716
|
+
this.#hidePlanReview();
|
|
1717
|
+
this.ui.requestRender();
|
|
1718
|
+
resolve(choice);
|
|
1719
|
+
};
|
|
1720
|
+
const overlay = new PlanReviewOverlay(
|
|
1721
|
+
planContent,
|
|
1722
|
+
{
|
|
1723
|
+
promptTitle: title,
|
|
1724
|
+
options,
|
|
1725
|
+
disabledIndices: dialogOptions?.disabledIndices,
|
|
1726
|
+
helpText: dialogOptions?.helpText,
|
|
1727
|
+
initialIndex: dialogOptions?.initialIndex,
|
|
1728
|
+
slider: extra?.slider,
|
|
1729
|
+
externalEditorLabel: this.keybindings.getDisplayString("app.editor.external") || undefined,
|
|
1730
|
+
},
|
|
1731
|
+
{
|
|
1732
|
+
onPick: choice => finish(choice),
|
|
1733
|
+
onCancel: () => finish(undefined),
|
|
1734
|
+
onExternalEditor: dialogOptions?.onExternalEditor,
|
|
1735
|
+
onPlanEdited: dialogOptions?.onPlanEdited,
|
|
1736
|
+
onFeedbackChange: dialogOptions?.onFeedbackChange,
|
|
1737
|
+
},
|
|
1738
|
+
);
|
|
1739
|
+
this.#planReviewOverlay = overlay;
|
|
1740
|
+
this.#planReviewOverlayHandle = this.ui.showOverlay(overlay, {
|
|
1741
|
+
anchor: "bottom-center",
|
|
1742
|
+
width: "100%",
|
|
1743
|
+
maxHeight: "100%",
|
|
1744
|
+
margin: 0,
|
|
1745
|
+
fullscreen: true,
|
|
1746
|
+
});
|
|
1747
|
+
this.ui.setFocus(overlay);
|
|
1695
1748
|
this.ui.requestRender();
|
|
1749
|
+
return promise;
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
#hidePlanReview(): void {
|
|
1753
|
+
this.#planReviewOverlayHandle?.hide();
|
|
1754
|
+
this.#planReviewOverlayHandle = undefined;
|
|
1755
|
+
this.#planReviewOverlay = undefined;
|
|
1696
1756
|
}
|
|
1697
1757
|
|
|
1698
1758
|
#getEditorTerminalPath(): string | null {
|
|
@@ -1714,14 +1774,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1714
1774
|
}
|
|
1715
1775
|
}
|
|
1716
1776
|
|
|
1717
|
-
#getPlanReviewHelpText(): string {
|
|
1718
|
-
const externalEditorKey = this.keybindings.getDisplayString("app.editor.external");
|
|
1719
|
-
if (!externalEditorKey) {
|
|
1720
|
-
return "up/down navigate enter select esc cancel";
|
|
1721
|
-
}
|
|
1722
|
-
return `up/down navigate enter select ${externalEditorKey.toLowerCase()} open in editor esc cancel`;
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
1777
|
#getPlanApprovalContextUsage(): ContextUsage | undefined {
|
|
1726
1778
|
const executionModel = this.#planModePreviousModelState?.model ?? this.session.model;
|
|
1727
1779
|
const contextWindow = executionModel?.contextWindow;
|
|
@@ -1780,7 +1832,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1780
1832
|
});
|
|
1781
1833
|
if (result !== null) {
|
|
1782
1834
|
await Bun.write(resolvedPath, result);
|
|
1783
|
-
this.#
|
|
1835
|
+
this.#planReviewOverlay?.setPlanContent(result);
|
|
1784
1836
|
this.showStatus("Plan updated in external editor.");
|
|
1785
1837
|
}
|
|
1786
1838
|
} catch (error) {
|
|
@@ -1812,19 +1864,12 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1812
1864
|
planContent: string,
|
|
1813
1865
|
options: {
|
|
1814
1866
|
planFilePath: string;
|
|
1815
|
-
finalPlanFilePath: string;
|
|
1816
1867
|
title: string;
|
|
1817
1868
|
preserveContext?: boolean;
|
|
1818
1869
|
compactBeforeExecute?: boolean;
|
|
1819
1870
|
executionModel?: ResolvedRoleModel;
|
|
1820
1871
|
},
|
|
1821
1872
|
): Promise<void> {
|
|
1822
|
-
await renameApprovedPlanFile({
|
|
1823
|
-
planFilePath: options.planFilePath,
|
|
1824
|
-
finalPlanFilePath: options.finalPlanFilePath,
|
|
1825
|
-
getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
|
|
1826
|
-
getSessionId: () => this.sessionManager.getSessionId(),
|
|
1827
|
-
});
|
|
1828
1873
|
const previousTools = this.#planModePreviousTools ?? this.session.getActiveToolNames();
|
|
1829
1874
|
|
|
1830
1875
|
// Mark the pending abort caused by the plan-mode → compaction transition as
|
|
@@ -1843,8 +1888,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1843
1888
|
if (!options.preserveContext) {
|
|
1844
1889
|
await this.handleClearCommand();
|
|
1845
1890
|
// The new session has a fresh local:// root — persist the approved plan there
|
|
1846
|
-
// so `local://<
|
|
1847
|
-
const newLocalPath = resolveLocalUrlToPath(options.
|
|
1891
|
+
// so `local://<slug>-plan.md` resolves correctly in the execution session.
|
|
1892
|
+
const newLocalPath = resolveLocalUrlToPath(options.planFilePath, {
|
|
1848
1893
|
getArtifactsDir: () => this.sessionManager.getArtifactsDir(),
|
|
1849
1894
|
getSessionId: () => this.sessionManager.getSessionId(),
|
|
1850
1895
|
});
|
|
@@ -1858,7 +1903,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1858
1903
|
// Cancellation skips the synthetic-prompt dispatch (operator's explicit
|
|
1859
1904
|
// abort is honored); failure proceeds best-effort — approval intent stands.
|
|
1860
1905
|
const compactionPrompt = prompt.render(planModeCompactInstructionsPrompt, {
|
|
1861
|
-
planFilePath: options.
|
|
1906
|
+
planFilePath: options.planFilePath,
|
|
1862
1907
|
});
|
|
1863
1908
|
// Pin the plan reference path BEFORE compaction so any user messages
|
|
1864
1909
|
// queued during the compaction await (which `handleCompactCommand`
|
|
@@ -1866,7 +1911,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1866
1911
|
// approved plan in `#buildPlanReferenceMessage`. Reassignment after
|
|
1867
1912
|
// the try/finally is idempotent and kept for the !compactBeforeExecute
|
|
1868
1913
|
// branch.
|
|
1869
|
-
this.session.setPlanReferencePath(options.
|
|
1914
|
+
this.session.setPlanReferencePath(options.planFilePath);
|
|
1870
1915
|
compactOutcome = await this.handleCompactCommand(compactionPrompt);
|
|
1871
1916
|
}
|
|
1872
1917
|
} finally {
|
|
@@ -1882,7 +1927,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1882
1927
|
if (previousTools.length > 0) {
|
|
1883
1928
|
await this.session.setActiveToolsByName(previousTools);
|
|
1884
1929
|
}
|
|
1885
|
-
this.session.setPlanReferencePath(options.
|
|
1930
|
+
this.session.setPlanReferencePath(options.planFilePath);
|
|
1886
1931
|
|
|
1887
1932
|
if (compactOutcome === "cancelled") {
|
|
1888
1933
|
// Explicit abort: honor it. `executeCompaction` already surfaced
|
|
@@ -1919,7 +1964,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
1919
1964
|
this.session.markPlanReferenceSent();
|
|
1920
1965
|
const planModePrompt = prompt.render(planModeApprovedPrompt, {
|
|
1921
1966
|
planContent,
|
|
1922
|
-
|
|
1967
|
+
planFilePath: options.planFilePath,
|
|
1923
1968
|
contextPreserved: options.preserveContext === true,
|
|
1924
1969
|
});
|
|
1925
1970
|
await this.session.prompt(planModePrompt, { synthetic: true });
|
|
@@ -2209,7 +2254,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2209
2254
|
return;
|
|
2210
2255
|
}
|
|
2211
2256
|
|
|
2212
|
-
this.#renderPlanPreview(planContent, { append: true });
|
|
2213
2257
|
const contextUsage = this.#getPlanApprovalContextUsage();
|
|
2214
2258
|
const keepContextLabel = this.#formatKeepContextLabel(contextUsage);
|
|
2215
2259
|
const keepContextDisabled = this.#isKeepContextDisabled(contextUsage);
|
|
@@ -2239,23 +2283,40 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2239
2283
|
},
|
|
2240
2284
|
}
|
|
2241
2285
|
: undefined;
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
const
|
|
2286
|
+
// The overlay now owns the dynamic, focus-aware help line; the caller only
|
|
2287
|
+
// supplies the trailing cancel hint.
|
|
2288
|
+
const helpText = "esc cancel";
|
|
2289
|
+
// In-overlay edits (section deletes/undo) and section annotations. Deletes
|
|
2290
|
+
// update `editedContent` (and mirror to disk); annotations build `feedback`
|
|
2291
|
+
// that the Refine branch re-prompts the model with.
|
|
2292
|
+
let editedContent: string | undefined;
|
|
2293
|
+
let feedback = "";
|
|
2294
|
+
|
|
2295
|
+
const choice = await this.showPlanReview(
|
|
2296
|
+
planContent,
|
|
2245
2297
|
"Plan mode - next step",
|
|
2246
2298
|
["Approve and execute", "Approve and compact context", keepContextLabel, "Refine plan"],
|
|
2247
2299
|
{
|
|
2248
2300
|
helpText,
|
|
2249
2301
|
onExternalEditor: () => void this.#openPlanInExternalEditor(planFilePath),
|
|
2302
|
+
onPlanEdited: content => {
|
|
2303
|
+
editedContent = content;
|
|
2304
|
+
void Bun.write(this.#resolvePlanFilePath(planFilePath), content);
|
|
2305
|
+
},
|
|
2306
|
+
onFeedbackChange: value => {
|
|
2307
|
+
feedback = value;
|
|
2308
|
+
},
|
|
2250
2309
|
disabledIndices: keepContextDisabled ? [PLAN_KEEP_CONTEXT_OPTION_INDEX] : undefined,
|
|
2251
2310
|
},
|
|
2252
2311
|
{ slider },
|
|
2253
2312
|
);
|
|
2254
2313
|
|
|
2255
2314
|
if (choice === "Approve and execute" || choice === "Approve and compact context" || choice === keepContextLabel) {
|
|
2256
|
-
const finalPlanFilePath = details.finalPlanFilePath || planFilePath;
|
|
2257
2315
|
try {
|
|
2258
|
-
|
|
2316
|
+
// Prefer in-overlay edits (already in memory) over a disk re-read; the
|
|
2317
|
+
// `onPlanEdited` write is fire-and-forget, so reading the file here could
|
|
2318
|
+
// race ahead of it.
|
|
2319
|
+
const latestPlanContent = editedContent ?? (await this.#readPlanFile(planFilePath));
|
|
2259
2320
|
if (!latestPlanContent) {
|
|
2260
2321
|
this.showError(`Plan file not found at ${planFilePath}`);
|
|
2261
2322
|
return;
|
|
@@ -2273,7 +2334,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2273
2334
|
cycle && selectedTierIndex !== cycle.currentIndex ? cycle.models[selectedTierIndex] : undefined;
|
|
2274
2335
|
await this.#approvePlan(latestPlanContent, {
|
|
2275
2336
|
planFilePath,
|
|
2276
|
-
finalPlanFilePath,
|
|
2277
2337
|
title: details.title,
|
|
2278
2338
|
preserveContext: choice !== "Approve and execute",
|
|
2279
2339
|
compactBeforeExecute: choice === "Approve and compact context",
|
|
@@ -2286,6 +2346,16 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2286
2346
|
}
|
|
2287
2347
|
return;
|
|
2288
2348
|
}
|
|
2349
|
+
|
|
2350
|
+
if (choice === "Refine plan") {
|
|
2351
|
+
// Section annotations entered in the overlay become a refinement prompt
|
|
2352
|
+
// re-submitted to the model. With no annotations, fall back to today's
|
|
2353
|
+
// behavior: close the overlay and let the operator type their own.
|
|
2354
|
+
if (feedback.trim() && this.onInputCallback) {
|
|
2355
|
+
this.onInputCallback(this.startPendingSubmission({ text: feedback }));
|
|
2356
|
+
}
|
|
2357
|
+
return;
|
|
2358
|
+
}
|
|
2289
2359
|
}
|
|
2290
2360
|
|
|
2291
2361
|
/**
|
|
@@ -2439,9 +2509,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2439
2509
|
initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void {
|
|
2440
2510
|
this.#extensionUiController.initializeHookRunner(uiContext, hasUI);
|
|
2441
2511
|
}
|
|
2442
|
-
createBackgroundUiContext(): ExtensionUIContext {
|
|
2443
|
-
return this.#extensionUiController.createBackgroundUiContext();
|
|
2444
|
-
}
|
|
2445
2512
|
|
|
2446
2513
|
setEditorComponent(
|
|
2447
2514
|
factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined,
|
|
@@ -2483,12 +2550,26 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2483
2550
|
this.ui.requestRender();
|
|
2484
2551
|
}
|
|
2485
2552
|
|
|
2486
|
-
//
|
|
2487
|
-
|
|
2488
|
-
|
|
2553
|
+
// UI helpers
|
|
2554
|
+
present(content: Component | readonly Component[]): void {
|
|
2555
|
+
if (Array.isArray(content)) {
|
|
2556
|
+
for (const item of content) this.#mountChatChild(item);
|
|
2557
|
+
} else {
|
|
2558
|
+
this.#mountChatChild(content as Component);
|
|
2559
|
+
}
|
|
2560
|
+
this.ui.requestRender();
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2563
|
+
#mountChatChild(item: Component): void {
|
|
2564
|
+
this.chatContainer.addChild(item);
|
|
2565
|
+
if (item instanceof ChatBlock) item.mount(this.#chatHost);
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
resetTranscript(): void {
|
|
2569
|
+
this.chatContainer.dispose();
|
|
2570
|
+
this.chatContainer.clear();
|
|
2489
2571
|
}
|
|
2490
2572
|
|
|
2491
|
-
// UI helpers
|
|
2492
2573
|
showStatus(message: string, options?: { dim?: boolean }): void {
|
|
2493
2574
|
this.#uiHelpers.showStatus(message, options);
|
|
2494
2575
|
}
|
|
@@ -2508,7 +2589,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2508
2589
|
}
|
|
2509
2590
|
|
|
2510
2591
|
showPinnedError(message: string): void {
|
|
2511
|
-
if (this.isBackgrounded) return;
|
|
2512
2592
|
this.errorBannerContainer.clear();
|
|
2513
2593
|
this.errorBannerContainer.addChild(new ErrorBannerComponent(message));
|
|
2514
2594
|
this.ui.requestRender();
|
|
@@ -2579,13 +2659,18 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2579
2659
|
ensureLoadingAnimation(): void {
|
|
2580
2660
|
if (!this.loadingAnimation) {
|
|
2581
2661
|
this.statusContainer.clear();
|
|
2662
|
+
const messageColorFn = ((message: string) =>
|
|
2663
|
+
renderWorkingMessage(message, this.#getWorkingMessageAccent())) as LoaderMessageColorFn & {
|
|
2664
|
+
animated: true;
|
|
2665
|
+
};
|
|
2666
|
+
messageColorFn.animated = true;
|
|
2582
2667
|
this.loadingAnimation = new Loader(
|
|
2583
2668
|
this.ui,
|
|
2584
2669
|
spinner => {
|
|
2585
2670
|
const accent = this.#getWorkingMessageAccent();
|
|
2586
2671
|
return accent ? `${accent.main}${spinner}\x1b[39m` : theme.fg("accent", spinner);
|
|
2587
2672
|
},
|
|
2588
|
-
|
|
2673
|
+
messageColorFn,
|
|
2589
2674
|
this.#defaultWorkingMessage,
|
|
2590
2675
|
getSymbolTheme().spinnerFrames,
|
|
2591
2676
|
);
|
|
@@ -2737,7 +2822,7 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2737
2822
|
this.#omfgController.dispose();
|
|
2738
2823
|
this.#extensionUiController.clearExtensionTerminalInputListeners();
|
|
2739
2824
|
this.clearPinnedError();
|
|
2740
|
-
this.#
|
|
2825
|
+
this.#hidePlanReview();
|
|
2741
2826
|
}
|
|
2742
2827
|
|
|
2743
2828
|
handleClearCommand(): Promise<void> {
|
|
@@ -2745,6 +2830,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2745
2830
|
return this.#commandController.handleClearCommand();
|
|
2746
2831
|
}
|
|
2747
2832
|
|
|
2833
|
+
handleFreshCommand(): Promise<void> {
|
|
2834
|
+
return this.#commandController.handleFreshCommand();
|
|
2835
|
+
}
|
|
2836
|
+
|
|
2748
2837
|
handleDropCommand(): Promise<void> {
|
|
2749
2838
|
this.#prepareSessionSwitch();
|
|
2750
2839
|
return this.#commandController.handleDropCommand();
|
|
@@ -2844,8 +2933,8 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2844
2933
|
}
|
|
2845
2934
|
}
|
|
2846
2935
|
|
|
2847
|
-
showDebugSelector(): void {
|
|
2848
|
-
this.#selectorController.showDebugSelector();
|
|
2936
|
+
async showDebugSelector(): Promise<void> {
|
|
2937
|
+
await this.#selectorController.showDebugSelector();
|
|
2849
2938
|
}
|
|
2850
2939
|
|
|
2851
2940
|
showSessionObserver(): void {
|
|
@@ -2980,10 +3069,6 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2980
3069
|
this.#inputController.handleDequeue();
|
|
2981
3070
|
}
|
|
2982
3071
|
|
|
2983
|
-
handleBackgroundCommand(): void {
|
|
2984
|
-
this.#inputController.handleBackgroundCommand();
|
|
2985
|
-
}
|
|
2986
|
-
|
|
2987
3072
|
handleImagePaste(): Promise<boolean> {
|
|
2988
3073
|
return this.#inputController.handleImagePaste();
|
|
2989
3074
|
}
|
|
@@ -2992,6 +3077,10 @@ export class InteractiveMode implements InteractiveModeContext {
|
|
|
2992
3077
|
return this.#btwController.start(question);
|
|
2993
3078
|
}
|
|
2994
3079
|
|
|
3080
|
+
handleTanCommand(work: string): Promise<void> {
|
|
3081
|
+
return this.#tanCommandController.start(work);
|
|
3082
|
+
}
|
|
3083
|
+
|
|
2995
3084
|
hasActiveBtw(): boolean {
|
|
2996
3085
|
return this.#btwController.hasActiveRequest();
|
|
2997
3086
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Setup version the wizard advances a fresh install to. Bump it whenever a new
|
|
3
|
+
* setup scene lands (or an existing scene raises its `minVersion`).
|
|
4
|
+
*
|
|
5
|
+
* Kept in its own dependency-free module so the cold-launch gate in `main.ts`
|
|
6
|
+
* can answer "is the stored setup version stale?" without statically importing
|
|
7
|
+
* the full wizard — every scene (sign-in/OAuth, web search, theme previews) plus
|
|
8
|
+
* the overlay component and their TUI deps. MUST equal `max(scene.minVersion)`
|
|
9
|
+
* across `ALL_SCENES`; the `setup-wizard` barrel and test suite guard it.
|
|
10
|
+
*/
|
|
11
|
+
export const CURRENT_SETUP_VERSION = 1;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Settings } from "../../config/settings";
|
|
2
|
+
import { CURRENT_SETUP_VERSION } from "../setup-version";
|
|
2
3
|
import type { InteractiveModeContext } from "../types";
|
|
3
4
|
import { glyphSetupScene } from "./scenes/glyph";
|
|
4
5
|
import { providersSetupScene } from "./scenes/providers";
|
|
@@ -8,14 +9,14 @@ import { SetupWizardComponent } from "./wizard-overlay";
|
|
|
8
9
|
|
|
9
10
|
export type { SetupScene, SetupSceneController, SetupSceneHost, SetupSceneResult } from "./scenes/types";
|
|
10
11
|
|
|
12
|
+
export { CURRENT_SETUP_VERSION };
|
|
13
|
+
|
|
11
14
|
export const ALL_SCENES = [
|
|
12
15
|
providersSetupScene,
|
|
13
16
|
glyphSetupScene,
|
|
14
17
|
themeSetupScene,
|
|
15
18
|
] as const satisfies readonly SetupScene[];
|
|
16
19
|
|
|
17
|
-
export const CURRENT_SETUP_VERSION = ALL_SCENES.reduce((max, scene) => Math.max(max, scene.minVersion), 0);
|
|
18
|
-
|
|
19
20
|
export interface SetupSceneSelectionOptions {
|
|
20
21
|
resuming?: boolean;
|
|
21
22
|
isTTY?: boolean;
|
|
@@ -19,7 +19,8 @@ type Availability = "checking" | boolean;
|
|
|
19
19
|
/**
|
|
20
20
|
* "Web search" panel: picks the provider the web_search tool should prefer and
|
|
21
21
|
* reports whether the highlighted provider is ready to use given current
|
|
22
|
-
* credentials (env keys or OAuth sign-ins from the Sign in tab)
|
|
22
|
+
* credentials (env keys or OAuth sign-ins from the Sign in tab) or an
|
|
23
|
+
* unauthenticated fallback.
|
|
23
24
|
*/
|
|
24
25
|
export class WebSearchTab implements SetupTab {
|
|
25
26
|
readonly id = "web-search";
|
|
@@ -91,7 +92,7 @@ export class WebSearchTab implements SetupTab {
|
|
|
91
92
|
let ready = false;
|
|
92
93
|
try {
|
|
93
94
|
const provider = await getSearchProvider(id);
|
|
94
|
-
ready = await provider.
|
|
95
|
+
ready = await provider.isExplicitlyAvailable(this.host.ctx.session.modelRegistry.authStorage);
|
|
95
96
|
} catch {
|
|
96
97
|
ready = false;
|
|
97
98
|
}
|
|
@@ -406,7 +406,7 @@
|
|
|
406
406
|
}
|
|
407
407
|
},
|
|
408
408
|
"spinnerFrames": {
|
|
409
|
-
"description": "Override the spinner frames. Use a flat array to set both `status` and `activity`, or an object to override each independently. Frames are advanced ~12.5fps for status spinners and ~
|
|
409
|
+
"description": "Override the spinner frames. Use a flat array to set both `status` and `activity`, or an object to override each independently. Frames are advanced ~12.5fps for status spinners and ~30fps for activity spinners.",
|
|
410
410
|
"oneOf": [
|
|
411
411
|
{
|
|
412
412
|
"type": "array",
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -95,6 +95,7 @@ export type SymbolKey =
|
|
|
95
95
|
| "icon.pause"
|
|
96
96
|
| "icon.loop"
|
|
97
97
|
| "icon.folder"
|
|
98
|
+
| "icon.search"
|
|
98
99
|
| "icon.scratchFolder"
|
|
99
100
|
| "icon.file"
|
|
100
101
|
| "icon.git"
|
|
@@ -264,6 +265,7 @@ const UNICODE_SYMBOLS: SymbolMap = {
|
|
|
264
265
|
"icon.pause": "⏸",
|
|
265
266
|
"icon.loop": "↻",
|
|
266
267
|
"icon.folder": "📁",
|
|
268
|
+
"icon.search": "🔍",
|
|
267
269
|
"icon.scratchFolder": "🗑",
|
|
268
270
|
"icon.file": "📄",
|
|
269
271
|
"icon.git": "⎇",
|
|
@@ -488,6 +490,7 @@ const NERD_SYMBOLS: SymbolMap = {
|
|
|
488
490
|
"icon.loop": "\uf021",
|
|
489
491
|
// pick: | alt:
|
|
490
492
|
"icon.folder": "\uf115",
|
|
493
|
+
"icon.search": "\uf002",
|
|
491
494
|
// pick: | alt:
|
|
492
495
|
"icon.scratchFolder": "\uf014",
|
|
493
496
|
// pick: | alt:
|
|
@@ -701,6 +704,7 @@ const ASCII_SYMBOLS: SymbolMap = {
|
|
|
701
704
|
"icon.pause": "||",
|
|
702
705
|
"icon.loop": "loop",
|
|
703
706
|
"icon.folder": "[D]",
|
|
707
|
+
"icon.search": "[/]",
|
|
704
708
|
"icon.scratchFolder": "[T]",
|
|
705
709
|
"icon.file": "[F]",
|
|
706
710
|
"icon.git": "git:",
|
|
@@ -2439,10 +2443,10 @@ function getHighlightColors(t: Theme): NativeHighlightColors {
|
|
|
2439
2443
|
* switch (which always reassigns `theme`) must invalidate every entry.
|
|
2440
2444
|
*
|
|
2441
2445
|
* Why this exists: animated tool blocks (eval/bash) repaint their box on every
|
|
2442
|
-
* ~
|
|
2443
|
-
* Without memoization each frame re-
|
|
2444
|
-
* Rust FFI — ~26ms for 100 lines, ~40ms for 150 —
|
|
2445
|
-
* budget and starving the spinner/render timers (the "TUI freeze").
|
|
2446
|
+
* ~33ms border-shimmer frame, and markdown re-lexes on every streamed delta.
|
|
2447
|
+
* Without memoization each frame can re-tokenize an unchanged code body through
|
|
2448
|
+
* the Rust FFI — ~26ms for 100 lines, ~40ms for 150 — consuming or overrunning
|
|
2449
|
+
* the 33ms frame budget and starving the spinner/render timers (the "TUI freeze").
|
|
2446
2450
|
*/
|
|
2447
2451
|
const HIGHLIGHT_CACHE_MAX = 256;
|
|
2448
2452
|
const highlightCache = new LRUCache<string, string>({ max: HIGHLIGHT_CACHE_MAX });
|