@gajae-code/coding-agent 0.11.6 → 0.11.8
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 +92 -0
- package/dist/types/capability/index.d.ts +10 -20
- package/dist/types/capability/types.d.ts +3 -0
- package/dist/types/cli/args.d.ts +0 -2
- package/dist/types/commands/daemon.d.ts +2 -2
- package/dist/types/commands/sdk.d.ts +20 -2
- package/dist/types/config/keybindings.d.ts +34 -4
- package/dist/types/config/model-profile-activation.d.ts +4 -3
- package/dist/types/config/model-profile-contract.d.ts +38 -0
- package/dist/types/config/settings-schema.d.ts +70 -7
- package/dist/types/edit/modes/patch.d.ts +13 -0
- package/dist/types/edit/path-mutation-lock.d.ts +15 -0
- package/dist/types/eval/py/executor.d.ts +1 -1
- package/dist/types/eval/py/runner-artifact.d.ts +8 -0
- package/dist/types/eval/py/tool-bridge.d.ts +1 -2
- package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +6 -5
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +20 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +43 -5
- package/dist/types/main.d.ts +32 -1
- package/dist/types/modes/components/btw-panel.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
- package/dist/types/modes/components/tool-status-header.d.ts +4 -2
- package/dist/types/modes/components/welcome.d.ts +2 -0
- package/dist/types/modes/controllers/btw-controller.d.ts +5 -0
- package/dist/types/modes/controllers/command-controller.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
- package/dist/types/modes/interactive-mode.d.ts +7 -2
- package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
- package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
- package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
- package/dist/types/modes/types.d.ts +4 -0
- package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
- package/dist/types/runtime-mcp/content-limits.d.ts +7 -0
- package/dist/types/runtime-mcp/manager.d.ts +1 -1
- package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
- package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
- package/dist/types/sdk/broker/broker.d.ts +2 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -1
- package/dist/types/sdk/bus/config-commands.d.ts +2 -2
- package/dist/types/sdk/bus/config.d.ts +2 -0
- package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
- package/dist/types/sdk/bus/index.d.ts +26 -1
- package/dist/types/sdk/bus/lifecycle-commands.d.ts +5 -4
- package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
- package/dist/types/sdk/bus/notification-service.d.ts +34 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +18 -3
- package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
- package/dist/types/sdk/bus/telegram-daemon.d.ts +189 -4
- package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
- package/dist/types/sdk/bus/topic-registry.d.ts +88 -2
- package/dist/types/sdk/client/discovery.d.ts +2 -0
- package/dist/types/sdk/client/liveness.d.ts +7 -0
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +1 -1
- package/dist/types/sdk/host/query/handlers.d.ts +9 -0
- package/dist/types/sdk/index.d.ts +2 -0
- package/dist/types/sdk/prompt-status.d.ts +88 -0
- package/dist/types/sdk/session-directory.d.ts +1 -1
- package/dist/types/sdk/startup-capability.d.ts +3 -0
- package/dist/types/sdk/transport/auth-preface.d.ts +9 -0
- package/dist/types/sdk/transport/index.d.ts +12 -0
- package/dist/types/sdk/transport/relay.d.ts +43 -0
- package/dist/types/sdk/transport/serve-cli.d.ts +4 -0
- package/dist/types/sdk/transport/socket.d.ts +7 -0
- package/dist/types/sdk/transport/stdio.d.ts +3 -0
- package/dist/types/session/agent-session.d.ts +30 -5
- package/dist/types/session/btw-contract.d.ts +16 -0
- package/dist/types/session/internal/managed-session-scope.d.ts +32 -9
- package/dist/types/session/internal/managed-session-storage.d.ts +27 -10
- package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
- package/dist/types/session/session-manager.d.ts +25 -4
- package/dist/types/session/session-storage.d.ts +18 -0
- package/dist/types/setup/credential-import.d.ts +5 -1
- package/dist/types/setup/provider-onboarding.d.ts +2 -0
- package/dist/types/ssh/utils.d.ts +1 -0
- package/dist/types/task/discovery.d.ts +3 -1
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/receipt.d.ts +2 -0
- package/dist/types/task/types.d.ts +94 -0
- package/dist/types/tools/ask.d.ts +454 -174
- package/dist/types/tools/fetch.d.ts +5 -8
- package/dist/types/tools/image-gen.d.ts +63 -1
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/skill-discovery.d.ts +7 -0
- package/dist/types/tools/sqlite-reader.d.ts +7 -0
- package/dist/types/utils/prompt-suggestion.d.ts +33 -0
- package/dist/types/utils/shell-snapshot.d.ts +12 -0
- package/dist/types/web/insane/bridge.d.ts +1 -0
- package/dist/types/web/insane/url-guard.d.ts +17 -0
- package/package.json +8 -8
- package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
- package/scripts/dogfood-repository-binding.ts +209 -0
- package/scripts/generate-sdk-operation-inventory.ts +4 -0
- package/scripts/run-test-manifest.ts +4 -4
- package/src/capability/index.ts +50 -42
- package/src/capability/types.ts +3 -0
- package/src/cli/args.ts +2 -92
- package/src/cli/notify-cli.ts +5 -38
- package/src/cli/setup-cli.ts +10 -4
- package/src/cli.ts +52 -9
- package/src/commands/daemon.ts +22 -5
- package/src/commands/sdk.ts +44 -11
- package/src/config/keybindings.ts +158 -25
- package/src/config/model-profile-activation.ts +7 -18
- package/src/config/model-profile-contract.ts +161 -0
- package/src/config/model-profiles.ts +18 -0
- package/src/config/model-registry.ts +11 -1
- package/src/config/settings-schema.ts +73 -7
- package/src/coordinator-mcp/model-preset.ts +21 -74
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +2 -2
- package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +42 -1
- package/src/discovery/ssh.ts +12 -1
- package/src/edit/index.ts +3 -6
- package/src/edit/modes/patch.ts +38 -1
- package/src/edit/modes/replace.ts +42 -0
- package/src/edit/path-mutation-lock.ts +112 -0
- package/src/eval/py/executor.ts +30 -11
- package/src/eval/py/kernel.ts +1 -21
- package/src/eval/py/prelude.py +2 -2
- package/src/eval/py/runner-artifact.ts +84 -0
- package/src/eval/py/tool-bridge.ts +34 -18
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
- package/src/extensibility/plugins/marketplace/fetcher.ts +191 -7
- package/src/gjc-runtime/launch-tmux.ts +1 -1
- package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
- package/src/gjc-runtime/ralplan-runtime.ts +75 -3
- package/src/gjc-runtime/repository-binding.ts +267 -0
- package/src/gjc-runtime/session-state-sidecar.ts +25 -9
- package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
- package/src/gjc-runtime/tmux-sessions.ts +45 -6
- package/src/gjc-runtime/ultragoal-guard.ts +93 -15
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +103 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +456 -31
- package/src/gjc-runtime/workflow-manifest.generated.json +58 -0
- package/src/gjc-runtime/workflow-manifest.ts +23 -0
- package/src/internal-urls/docs-index.generated.ts +12 -10
- package/src/internal-urls/local-protocol.ts +64 -21
- package/src/internal-urls/mcp-protocol.ts +73 -11
- package/src/main.ts +111 -37
- package/src/modes/DESIGN.md +5 -0
- package/src/modes/acp/acp-agent.ts +50 -16
- package/src/modes/action-registry.ts +1 -1
- package/src/modes/components/btw-panel.ts +82 -16
- package/src/modes/components/model-selector.ts +73 -11
- package/src/modes/components/plan-preview-overlay.ts +1 -1
- package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
- package/src/modes/components/tool-status-header.ts +25 -4
- package/src/modes/components/welcome.ts +22 -18
- package/src/modes/controllers/btw-controller.ts +119 -36
- package/src/modes/controllers/command-controller.ts +97 -54
- package/src/modes/controllers/event-controller.ts +10 -0
- package/src/modes/controllers/input-controller.ts +38 -2
- package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
- package/src/modes/controllers/selector-controller.ts +149 -63
- package/src/modes/interactive-mode.ts +57 -34
- package/src/modes/prompt-action-autocomplete.ts +32 -13
- package/src/modes/prompt-suggestion-controller.ts +96 -0
- package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
- package/src/modes/types.ts +4 -0
- package/src/modes/utils/hotkeys-markdown.ts +64 -36
- package/src/modes/utils/ui-helpers.ts +5 -3
- package/src/prompts/agents/architect.md +0 -1
- package/src/prompts/agents/critic.md +0 -1
- package/src/prompts/system/btw-user.md +3 -8
- package/src/prompts/system/prompt-suggestion-system.md +32 -0
- package/src/prompts/system/system-prompt.md +6 -4
- package/src/prompts/tools/cron.md +3 -1
- package/src/prompts/tools/skill-discovery.md +1 -0
- package/src/runtime-mcp/client.ts +41 -55
- package/src/runtime-mcp/content-limits.ts +71 -0
- package/src/runtime-mcp/json-rpc.ts +23 -9
- package/src/runtime-mcp/manager.ts +51 -53
- package/src/runtime-mcp/oauth-flow.ts +0 -72
- package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
- package/src/runtime-mcp/transports/http.ts +63 -22
- package/src/sdk/broker/broker.ts +34 -20
- package/src/sdk/broker/lifecycle.ts +185 -36
- package/src/sdk/bus/chat-daemon-control.ts +19 -5
- package/src/sdk/bus/config-commands.ts +2 -2
- package/src/sdk/bus/config.ts +9 -1
- package/src/sdk/bus/conversation-store.ts +40 -6
- package/src/sdk/bus/index.ts +244 -70
- package/src/sdk/bus/lifecycle-commands.ts +63 -10
- package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
- package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
- package/src/sdk/bus/notification-orchestration.ts +12 -0
- package/src/sdk/bus/notification-service.ts +68 -20
- package/src/sdk/bus/prompt-reconciliation.ts +239 -0
- package/src/sdk/bus/recent-activity.ts +90 -26
- package/src/sdk/bus/telegram-daemon-contract.ts +18 -3
- package/src/sdk/bus/telegram-daemon-control.ts +147 -35
- package/src/sdk/bus/telegram-daemon.ts +2463 -450
- package/src/sdk/bus/telegram-reference.ts +20 -2
- package/src/sdk/bus/topic-registry.ts +451 -12
- package/src/sdk/cli/session-cli.ts +15 -2
- package/src/sdk/client/discovery.ts +19 -3
- package/src/sdk/client/liveness.ts +49 -0
- package/src/sdk/host/control/dispatch.ts +1 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +2 -6
- package/src/sdk/host/query/handlers.ts +70 -5
- package/src/sdk/index.ts +12 -0
- package/src/sdk/prompt-status.ts +97 -0
- package/src/sdk/protocol/operation-inventory.generated.json +58 -0
- package/src/sdk/protocol/operation-registry.ts +18 -4
- package/src/sdk/session-directory.ts +5 -1
- package/src/sdk/session.ts +31 -5
- package/src/sdk/startup-capability.ts +9 -1
- package/src/sdk/transport/auth-preface.ts +82 -0
- package/src/sdk/transport/index.ts +18 -0
- package/src/sdk/transport/relay.ts +252 -0
- package/src/sdk/transport/serve-cli.ts +105 -0
- package/src/sdk/transport/socket.ts +197 -0
- package/src/sdk/transport/stdio.ts +17 -0
- package/src/session/agent-session.ts +292 -154
- package/src/session/blob-store.ts +25 -7
- package/src/session/btw-contract.ts +59 -0
- package/src/session/internal/managed-session-scope.ts +1163 -137
- package/src/session/internal/managed-session-storage.ts +397 -234
- package/src/session/internal/native-publish-outcome.ts +266 -0
- package/src/session/session-manager.ts +620 -403
- package/src/session/session-storage.ts +128 -11
- package/src/setup/credential-import.ts +28 -3
- package/src/setup/provider-onboarding.ts +30 -1
- package/src/setup/provider-presets.json +2 -1
- package/src/slash-commands/builtin-registry.ts +1 -1
- package/src/ssh/utils.ts +14 -0
- package/src/task/discovery.ts +8 -2
- package/src/task/gjc-command.ts +2 -2
- package/src/task/index.ts +121 -15
- package/src/task/receipt.ts +3 -0
- package/src/task/types.ts +34 -3
- package/src/tools/ask.ts +199 -89
- package/src/tools/ast-edit.ts +2 -2
- package/src/tools/bash-pty-selection.ts +2 -2
- package/src/tools/browser/screenshot-format.ts +6 -1
- package/src/tools/cron.ts +1 -1
- package/src/tools/fetch.ts +13 -131
- package/src/tools/image-gen.ts +476 -23
- package/src/tools/index.ts +4 -0
- package/src/tools/read.ts +2 -0
- package/src/tools/render-utils.ts +7 -1
- package/src/tools/skill-discovery.ts +39 -3
- package/src/tools/sqlite-reader.ts +63 -5
- package/src/utils/edit-mode.ts +2 -2
- package/src/utils/pasted-image-path.ts +15 -6
- package/src/utils/prompt-suggestion.ts +265 -0
- package/src/utils/shell-snapshot.ts +173 -63
- package/src/utils/sixel.ts +3 -3
- package/src/web/insane/bridge.ts +5 -1
- package/src/web/insane/url-guard.ts +140 -27
- package/src/web/scrapers/docs-rs.ts +30 -5
- package/src/web/scrapers/types.ts +19 -49
- package/src/web/scrapers/utils.ts +12 -26
|
@@ -1,12 +1,28 @@
|
|
|
1
|
-
import { prompt } from "@gajae-code/utils";
|
|
2
1
|
import btwUserPrompt from "../../prompts/system/btw-user.md" with { type: "text" };
|
|
2
|
+
import type { BtwConversationScope, BtwTurnCapture } from "../../session/agent-session";
|
|
3
|
+
import {
|
|
4
|
+
BTW_MAX_QUESTION_UTF8_BYTES,
|
|
5
|
+
type BtwTextExchange,
|
|
6
|
+
boundBtwExchanges,
|
|
7
|
+
sanitizeBtwError,
|
|
8
|
+
utf8ByteLength,
|
|
9
|
+
} from "../../session/btw-contract";
|
|
3
10
|
import { BtwPanelComponent } from "../components/btw-panel";
|
|
4
11
|
import type { InteractiveModeContext } from "../types";
|
|
5
12
|
|
|
13
|
+
type BtwFollowUpResult = "accepted" | "busy" | "closed" | "rejected";
|
|
14
|
+
|
|
15
|
+
interface ActiveBtwTurn extends BtwTurnCapture {
|
|
16
|
+
abortController: AbortController | undefined;
|
|
17
|
+
active: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
6
20
|
interface BtwRequest {
|
|
7
21
|
component: BtwPanelComponent;
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
conversationScope: BtwConversationScope | undefined;
|
|
23
|
+
activeTurn: ActiveBtwTurn | undefined;
|
|
24
|
+
inFlight: boolean;
|
|
25
|
+
contextExchanges: BtwTextExchange[];
|
|
10
26
|
}
|
|
11
27
|
|
|
12
28
|
export class BtwController {
|
|
@@ -18,84 +34,151 @@ export class BtwController {
|
|
|
18
34
|
return this.#activeRequest !== undefined;
|
|
19
35
|
}
|
|
20
36
|
|
|
37
|
+
hasOpenPanel(): boolean {
|
|
38
|
+
return this.hasActiveRequest();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
isTurnInFlight(): boolean {
|
|
42
|
+
return this.#activeRequest?.inFlight ?? false;
|
|
43
|
+
}
|
|
44
|
+
|
|
21
45
|
handleEscape(): boolean {
|
|
22
46
|
if (!this.#activeRequest) return false;
|
|
23
|
-
this.#closeActiveRequest(
|
|
47
|
+
this.#closeActiveRequest();
|
|
24
48
|
return true;
|
|
25
49
|
}
|
|
26
50
|
|
|
27
51
|
dispose(): void {
|
|
28
|
-
this.#closeActiveRequest(
|
|
52
|
+
this.#closeActiveRequest();
|
|
29
53
|
}
|
|
30
54
|
|
|
31
55
|
async start(question: string): Promise<void> {
|
|
56
|
+
if (this.hasOpenPanel()) {
|
|
57
|
+
this.ctx.showStatus("A /btw chat is already open. Type a follow-up or press Esc to return to the main chat.");
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
32
60
|
const trimmedQuestion = question.trim();
|
|
33
61
|
if (!trimmedQuestion) {
|
|
34
62
|
this.ctx.showStatus("Usage: /btw <question>");
|
|
35
63
|
return;
|
|
36
64
|
}
|
|
65
|
+
if (!this.#acceptQuestion(trimmedQuestion) || !this.#hasModel()) return;
|
|
66
|
+
const scope = this.ctx.session.createBtwConversationScope(btwUserPrompt);
|
|
67
|
+
const request = this.#openRequest(trimmedQuestion, scope);
|
|
68
|
+
void this.#runRequest(request);
|
|
69
|
+
}
|
|
37
70
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
71
|
+
async submitFollowUp(question: string): Promise<BtwFollowUpResult> {
|
|
72
|
+
const request = this.#activeRequest;
|
|
73
|
+
if (!request) return "closed";
|
|
74
|
+
if (request.inFlight) {
|
|
75
|
+
this.ctx.showStatus("The /btw chat is still answering. Wait for it to finish.");
|
|
76
|
+
return "busy";
|
|
42
77
|
}
|
|
78
|
+
const trimmedQuestion = question.trim();
|
|
79
|
+
if (!trimmedQuestion) return "closed";
|
|
80
|
+
if (!this.#acceptQuestion(trimmedQuestion)) return "rejected";
|
|
81
|
+
if (!request.conversationScope) return "closed";
|
|
82
|
+
request.activeTurn = this.#createTurn(trimmedQuestion, request.conversationScope);
|
|
83
|
+
request.inFlight = true;
|
|
84
|
+
request.component.beginTurn(trimmedQuestion);
|
|
85
|
+
void this.#runRequest(request);
|
|
86
|
+
return "accepted";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#acceptQuestion(question: string): boolean {
|
|
90
|
+
if (utf8ByteLength(question) <= BTW_MAX_QUESTION_UTF8_BYTES) return true;
|
|
91
|
+
this.ctx.showError(`/btw questions are limited to ${BTW_MAX_QUESTION_UTF8_BYTES} UTF-8 bytes.`);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#hasModel(): boolean {
|
|
96
|
+
if (this.ctx.session.model) return true;
|
|
97
|
+
this.ctx.showError("No active model available for /btw.");
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
43
100
|
|
|
44
|
-
|
|
101
|
+
#createTurn(question: string, scope: BtwConversationScope): ActiveBtwTurn {
|
|
102
|
+
return { question, scope, abortController: new AbortController(), active: true };
|
|
103
|
+
}
|
|
45
104
|
|
|
105
|
+
#openRequest(question: string, scope: BtwConversationScope): BtwRequest {
|
|
46
106
|
const request: BtwRequest = {
|
|
47
|
-
component: new BtwPanelComponent({ question
|
|
48
|
-
|
|
49
|
-
|
|
107
|
+
component: new BtwPanelComponent({ question, tui: this.ctx.ui }),
|
|
108
|
+
conversationScope: scope,
|
|
109
|
+
activeTurn: this.#createTurn(question, scope),
|
|
110
|
+
inFlight: true,
|
|
111
|
+
contextExchanges: [],
|
|
50
112
|
};
|
|
51
113
|
this.ctx.btwContainer.clear();
|
|
52
114
|
this.ctx.btwContainer.addChild(request.component);
|
|
53
115
|
this.ctx.ui.requestRender();
|
|
54
116
|
this.#activeRequest = request;
|
|
55
|
-
|
|
117
|
+
return request;
|
|
56
118
|
}
|
|
57
119
|
|
|
58
120
|
async #runRequest(request: BtwRequest): Promise<void> {
|
|
121
|
+
const turn = request.activeTurn;
|
|
122
|
+
const abortController = turn?.abortController;
|
|
123
|
+
if (!turn?.scope || !abortController) return;
|
|
59
124
|
try {
|
|
60
|
-
const promptText = prompt.render(btwUserPrompt, { question: request.question });
|
|
61
125
|
const { replyText } = await this.ctx.session.runEphemeralTurn({
|
|
62
126
|
purpose: "btw",
|
|
63
|
-
|
|
127
|
+
turn,
|
|
128
|
+
contextExchanges: request.contextExchanges.map(exchange => ({ ...exchange })),
|
|
64
129
|
onTextDelta: delta => {
|
|
65
|
-
if (this.#isActiveRequest(request))
|
|
66
|
-
request.component.appendText(delta);
|
|
67
|
-
}
|
|
130
|
+
if (turn.active && this.#isActiveRequest(request)) request.component.appendText(delta);
|
|
68
131
|
},
|
|
69
|
-
signal:
|
|
132
|
+
signal: abortController.signal,
|
|
70
133
|
});
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
134
|
+
if (!turn.active || !this.#isActiveRequest(request)) return;
|
|
135
|
+
request.inFlight = false;
|
|
136
|
+
request.contextExchanges = boundBtwExchanges([
|
|
137
|
+
...request.contextExchanges,
|
|
138
|
+
{ question: turn.question, answer: replyText },
|
|
139
|
+
]);
|
|
140
|
+
if (replyText) request.component.setAnswer(replyText);
|
|
78
141
|
request.component.markComplete();
|
|
79
|
-
} catch
|
|
80
|
-
if (!this.#isActiveRequest(request))
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if (request.abortController.signal.aborted) {
|
|
142
|
+
} catch {
|
|
143
|
+
if (!turn.active || !this.#isActiveRequest(request)) return;
|
|
144
|
+
request.inFlight = false;
|
|
145
|
+
if (abortController.signal.aborted) {
|
|
84
146
|
request.component.markAborted();
|
|
85
147
|
return;
|
|
86
148
|
}
|
|
87
|
-
request.component.markError(
|
|
149
|
+
request.component.markError(sanitizeBtwError("Side-chat request failed."));
|
|
150
|
+
} finally {
|
|
151
|
+
if (request.activeTurn === turn) request.activeTurn = undefined;
|
|
152
|
+
this.#scrubTurn(turn);
|
|
88
153
|
}
|
|
89
154
|
}
|
|
90
155
|
|
|
91
|
-
#
|
|
156
|
+
#scrubTurn(turn: ActiveBtwTurn): void {
|
|
157
|
+
turn.active = false;
|
|
158
|
+
turn.question = "";
|
|
159
|
+
turn.abortController = undefined;
|
|
160
|
+
turn.scope = undefined;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
#closeActiveRequest(): void {
|
|
92
164
|
const request = this.#activeRequest;
|
|
93
165
|
if (!request) return;
|
|
94
166
|
this.#activeRequest = undefined;
|
|
95
|
-
|
|
96
|
-
|
|
167
|
+
const turn = request.activeTurn;
|
|
168
|
+
const abortController = turn?.abortController;
|
|
169
|
+
if (turn) this.#scrubTurn(turn);
|
|
170
|
+
request.activeTurn = undefined;
|
|
171
|
+
request.contextExchanges.splice(0);
|
|
172
|
+
request.inFlight = false;
|
|
173
|
+
if (request.conversationScope) {
|
|
174
|
+
request.conversationScope.messages.splice(0);
|
|
175
|
+
request.conversationScope.systemPrompt.splice(0);
|
|
176
|
+
request.conversationScope = undefined;
|
|
97
177
|
}
|
|
178
|
+
abortController?.abort();
|
|
98
179
|
request.component.close();
|
|
180
|
+
this.ctx.editor?.setText("");
|
|
181
|
+
this.ctx.pendingImages = [];
|
|
99
182
|
this.ctx.btwContainer.clear();
|
|
100
183
|
this.ctx.ui.requestRender();
|
|
101
184
|
}
|
|
@@ -10,12 +10,12 @@ import {
|
|
|
10
10
|
type UsageLimit,
|
|
11
11
|
type UsageReport,
|
|
12
12
|
} from "@gajae-code/ai";
|
|
13
|
-
import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@gajae-code/tui";
|
|
13
|
+
import { type Keybinding, Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@gajae-code/tui";
|
|
14
14
|
import { formatDuration, Snowflake, setProjectDir } from "@gajae-code/utils";
|
|
15
|
-
import { $ } from "bun";
|
|
16
15
|
import { resolveAppendOnlyMode } from "../../append-only-mode";
|
|
17
16
|
import { jobElapsedMs } from "../../async";
|
|
18
17
|
import { reset as resetCapabilities } from "../../capability";
|
|
18
|
+
import type { KeybindingsManager } from "../../config/keybindings";
|
|
19
19
|
import { clearClaudePluginRootsCache } from "../../discovery/helpers";
|
|
20
20
|
import { loadCustomShare } from "../../export/custom-share";
|
|
21
21
|
import type { CompactOptions } from "../../extensibility/extensions/types";
|
|
@@ -36,7 +36,7 @@ import { EvalExecutionComponent } from "../../modes/components/eval-execution";
|
|
|
36
36
|
import { getMarkdownTheme, getSymbolTheme, theme } from "../../modes/theme/theme";
|
|
37
37
|
import type { InteractiveModeContext } from "../../modes/types";
|
|
38
38
|
import { computeContextBreakdown, renderContextUsage } from "../../modes/utils/context-usage";
|
|
39
|
-
import { buildHotkeysMarkdown } from "../../modes/utils/hotkeys-markdown";
|
|
39
|
+
import { buildHotkeysMarkdown, formatHotkeyMarkdownCode } from "../../modes/utils/hotkeys-markdown";
|
|
40
40
|
import { buildToolsMarkdown } from "../../modes/utils/tools-markdown";
|
|
41
41
|
import type { AsyncJobSnapshotItem } from "../../session/agent-session";
|
|
42
42
|
import type { AuthStorage } from "../../session/auth-storage";
|
|
@@ -61,6 +61,39 @@ function showMarkdownPanel(ctx: InteractiveModeContext, title: string, markdown:
|
|
|
61
61
|
ctx.ui.requestRender();
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
export function buildHelpMarkdown(keybindings: Pick<KeybindingsManager, "getAccessibleDisplayString">): string {
|
|
65
|
+
const displayKey = (action: Keybinding): string => keybindings.getAccessibleDisplayString(action) || "Disabled";
|
|
66
|
+
const sessionNewKey = formatHotkeyMarkdownCode(displayKey("app.session.new"));
|
|
67
|
+
const selectModelKey = formatHotkeyMarkdownCode(displayKey("app.model.select"));
|
|
68
|
+
const autocompleteNavigationKeys = formatHotkeyMarkdownCode(
|
|
69
|
+
`${displayKey("tui.select.up")}/${displayKey("tui.select.down")}`,
|
|
70
|
+
false,
|
|
71
|
+
);
|
|
72
|
+
const autocompleteConfirmKeys = formatHotkeyMarkdownCode(
|
|
73
|
+
`${displayKey("tui.input.submit")}/${displayKey("tui.input.tab")}`,
|
|
74
|
+
false,
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
return [
|
|
78
|
+
"**Beginner actions**",
|
|
79
|
+
"",
|
|
80
|
+
"| Action | How |",
|
|
81
|
+
"|---|---|",
|
|
82
|
+
`| Start a fresh session | ${sessionNewKey} or \`/new\` |`,
|
|
83
|
+
"| Resume another session | `/resume` |",
|
|
84
|
+
"| Show session details | `/session info` |",
|
|
85
|
+
"| Delete current session transcript/artifacts | `/session delete` |",
|
|
86
|
+
`| Select a model | \`/model\` or ${selectModelKey} |`,
|
|
87
|
+
"| Show all shortcuts | `?` on an empty prompt or `/hotkeys` |",
|
|
88
|
+
"",
|
|
89
|
+
"**Finding commands**",
|
|
90
|
+
"",
|
|
91
|
+
`- Type \`/\` to browse slash commands, then use ${autocompleteNavigationKeys} and ${autocompleteConfirmKeys}.`,
|
|
92
|
+
"- Type `#` to browse prompt actions like starting a session, pasting an image, or moving the cursor.",
|
|
93
|
+
"- Type `!` for shell commands and `$` for Python snippets.",
|
|
94
|
+
].join("\n");
|
|
95
|
+
}
|
|
96
|
+
|
|
64
97
|
export class CommandController {
|
|
65
98
|
constructor(private readonly ctx: InteractiveModeContext) {}
|
|
66
99
|
|
|
@@ -120,21 +153,34 @@ export class CommandController {
|
|
|
120
153
|
}
|
|
121
154
|
|
|
122
155
|
async handleShareCommand(): Promise<void> {
|
|
123
|
-
|
|
124
|
-
|
|
156
|
+
let tempDir: string | undefined;
|
|
157
|
+
try {
|
|
158
|
+
let tmpFile: string;
|
|
125
159
|
try {
|
|
126
|
-
await fs.
|
|
127
|
-
|
|
128
|
-
|
|
160
|
+
tempDir = await fs.mkdtemp(path.join(os.tmpdir(), "gjc-share-"));
|
|
161
|
+
if (process.platform !== "win32") await fs.chmod(tempDir, 0o700);
|
|
162
|
+
tmpFile = path.join(tempDir, "session.html");
|
|
163
|
+
const file = await fs.open(tmpFile, "wx", 0o600);
|
|
164
|
+
await file.close();
|
|
165
|
+
await this.ctx.session.exportToHtml(tmpFile);
|
|
166
|
+
if (process.platform !== "win32") await fs.chmod(tmpFile, 0o600);
|
|
167
|
+
} catch (error: unknown) {
|
|
168
|
+
this.ctx.showError(`Failed to export session: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
await this.#shareExport(tmpFile);
|
|
172
|
+
} finally {
|
|
173
|
+
if (tempDir) {
|
|
174
|
+
try {
|
|
175
|
+
await fs.rm(tempDir, { recursive: true, force: true });
|
|
176
|
+
} catch {
|
|
177
|
+
// Ignore cleanup errors
|
|
178
|
+
}
|
|
129
179
|
}
|
|
130
|
-
};
|
|
131
|
-
try {
|
|
132
|
-
await this.ctx.session.exportToHtml(tmpFile);
|
|
133
|
-
} catch (error: unknown) {
|
|
134
|
-
this.ctx.showError(`Failed to export session: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
135
|
-
return;
|
|
136
180
|
}
|
|
181
|
+
}
|
|
137
182
|
|
|
183
|
+
async #shareExport(tmpFile: string): Promise<void> {
|
|
138
184
|
try {
|
|
139
185
|
const customShare = await loadCustomShare();
|
|
140
186
|
if (customShare) {
|
|
@@ -149,7 +195,6 @@ export class CommandController {
|
|
|
149
195
|
this.ctx.editorContainer.clear();
|
|
150
196
|
this.ctx.editorContainer.addChild(this.ctx.editor);
|
|
151
197
|
this.ctx.ui.setFocus(this.ctx.editor);
|
|
152
|
-
await cleanupTempFile();
|
|
153
198
|
};
|
|
154
199
|
|
|
155
200
|
try {
|
|
@@ -176,20 +221,22 @@ export class CommandController {
|
|
|
176
221
|
}
|
|
177
222
|
}
|
|
178
223
|
} catch (err) {
|
|
179
|
-
await cleanupTempFile();
|
|
180
224
|
this.ctx.showError(err instanceof Error ? err.message : String(err));
|
|
181
225
|
return;
|
|
182
226
|
}
|
|
183
227
|
|
|
184
228
|
try {
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
229
|
+
const authProcess = Bun.spawn(["gh", "auth", "status"], {
|
|
230
|
+
env: process.env,
|
|
231
|
+
stdin: "ignore",
|
|
232
|
+
stdout: "ignore",
|
|
233
|
+
stderr: "ignore",
|
|
234
|
+
});
|
|
235
|
+
if ((await authProcess.exited) !== 0) {
|
|
188
236
|
this.ctx.showError("GitHub CLI is not logged in. Run 'gh auth login' first.");
|
|
189
237
|
return;
|
|
190
238
|
}
|
|
191
239
|
} catch {
|
|
192
|
-
await cleanupTempFile();
|
|
193
240
|
this.ctx.showError("GitHub CLI (gh) is not installed. Install it from https://cli.github.com/");
|
|
194
241
|
return;
|
|
195
242
|
}
|
|
@@ -205,27 +252,40 @@ export class CommandController {
|
|
|
205
252
|
this.ctx.editorContainer.clear();
|
|
206
253
|
this.ctx.editorContainer.addChild(this.ctx.editor);
|
|
207
254
|
this.ctx.ui.setFocus(this.ctx.editor);
|
|
208
|
-
await cleanupTempFile();
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
loader.onAbort = () => {
|
|
212
|
-
void restoreEditor();
|
|
213
|
-
this.ctx.showStatus("Share cancelled");
|
|
214
255
|
};
|
|
215
256
|
|
|
257
|
+
let cancellationRequested = false;
|
|
216
258
|
try {
|
|
217
|
-
const
|
|
218
|
-
|
|
259
|
+
const gistProcess = Bun.spawn(["gh", "gist", "create", "--public=false", tmpFile], {
|
|
260
|
+
env: process.env,
|
|
261
|
+
stdin: "ignore",
|
|
262
|
+
stdout: "pipe",
|
|
263
|
+
stderr: "pipe",
|
|
264
|
+
signal: loader.signal,
|
|
265
|
+
});
|
|
266
|
+
loader.onAbort = () => {
|
|
267
|
+
cancellationRequested = gistProcess.exitCode === null;
|
|
268
|
+
};
|
|
269
|
+
const stdoutPromise = new Response(gistProcess.stdout).text();
|
|
270
|
+
const stderrPromise = new Response(gistProcess.stderr).text();
|
|
271
|
+
const exitCode = await gistProcess.exited;
|
|
272
|
+
const [stdout, stderr] = await Promise.all([stdoutPromise, stderrPromise]);
|
|
273
|
+
|
|
274
|
+
if (cancellationRequested) {
|
|
275
|
+
await restoreEditor();
|
|
276
|
+
this.ctx.showStatus("Share cancelled");
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
219
279
|
|
|
220
280
|
await restoreEditor();
|
|
221
281
|
|
|
222
|
-
if (
|
|
223
|
-
const errorMsg =
|
|
282
|
+
if (exitCode !== 0) {
|
|
283
|
+
const errorMsg = stderr.trim() || "Unknown error";
|
|
224
284
|
this.ctx.showError(`Failed to create gist: ${errorMsg}`);
|
|
225
285
|
return;
|
|
226
286
|
}
|
|
227
287
|
|
|
228
|
-
const gistUrl =
|
|
288
|
+
const gistUrl = stdout.trim();
|
|
229
289
|
const gistId = gistUrl.split("/").pop();
|
|
230
290
|
if (!gistId) {
|
|
231
291
|
this.ctx.showError("Failed to parse gist ID from gh output");
|
|
@@ -236,10 +296,12 @@ export class CommandController {
|
|
|
236
296
|
this.ctx.showStatus(`Share URL: ${previewUrl}\nGist: ${gistUrl}`);
|
|
237
297
|
this.openInBrowser(previewUrl);
|
|
238
298
|
} catch (error: unknown) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
this.ctx.
|
|
299
|
+
await restoreEditor();
|
|
300
|
+
if (cancellationRequested) {
|
|
301
|
+
this.ctx.showStatus("Share cancelled");
|
|
302
|
+
return;
|
|
242
303
|
}
|
|
304
|
+
this.ctx.showError(`Failed to create gist: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
243
305
|
}
|
|
244
306
|
}
|
|
245
307
|
|
|
@@ -577,26 +639,7 @@ export class CommandController {
|
|
|
577
639
|
}
|
|
578
640
|
|
|
579
641
|
handleHelpCommand(): void {
|
|
580
|
-
|
|
581
|
-
const markdown = [
|
|
582
|
-
"**Beginner actions**",
|
|
583
|
-
"",
|
|
584
|
-
"| Action | How |",
|
|
585
|
-
"|---|---|",
|
|
586
|
-
`| Start a fresh session | \`${sessionNewKey}\` or \`/new\` |`,
|
|
587
|
-
"| Resume another session | `/resume` |",
|
|
588
|
-
"| Show session details | `/session info` |",
|
|
589
|
-
"| Delete current session transcript/artifacts | `/session delete` |",
|
|
590
|
-
"| Select a model | `/model` or `Ctrl+L` |",
|
|
591
|
-
"| Show all shortcuts | `?` on an empty prompt or `/hotkeys` |",
|
|
592
|
-
"",
|
|
593
|
-
"**Finding commands**",
|
|
594
|
-
"",
|
|
595
|
-
"- Type `/` to browse slash commands, then use arrows and Enter/Tab.",
|
|
596
|
-
"- Type `#` to browse prompt actions like starting a session, pasting an image, or moving the cursor.",
|
|
597
|
-
"- Type `!` for shell commands and `$` for Python snippets.",
|
|
598
|
-
].join("\n");
|
|
599
|
-
showMarkdownPanel(this.ctx, "GJC Help", markdown);
|
|
642
|
+
showMarkdownPanel(this.ctx, "GJC Help", buildHelpMarkdown(this.ctx.keybindings));
|
|
600
643
|
}
|
|
601
644
|
|
|
602
645
|
handleToolsCommand(): void {
|
|
@@ -242,6 +242,7 @@ export class EventController {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
async #handleAgentStart(_event: Extract<AgentSessionEvent, { type: "agent_start" }>): Promise<void> {
|
|
245
|
+
this.ctx.promptSuggestion?.onAgentStart();
|
|
245
246
|
this.#lastIntent = undefined;
|
|
246
247
|
this.#readToolCallArgs.clear();
|
|
247
248
|
this.#readToolCallAssistantComponents.clear();
|
|
@@ -836,6 +837,7 @@ export class EventController {
|
|
|
836
837
|
this.ctx.ui.requestRender();
|
|
837
838
|
this.#scheduleIdleCompaction();
|
|
838
839
|
this.sendCompletionNotification();
|
|
840
|
+
this.ctx.promptSuggestion?.onAgentEnd();
|
|
839
841
|
}
|
|
840
842
|
|
|
841
843
|
async #handleAutoCompactionStart(
|
|
@@ -847,6 +849,10 @@ export class EventController {
|
|
|
847
849
|
this.ctx.editor.onEscape = () => {
|
|
848
850
|
this.ctx.session.abortCompaction();
|
|
849
851
|
};
|
|
852
|
+
if (this.ctx.loadingAnimation) {
|
|
853
|
+
this.ctx.loadingAnimation.stop();
|
|
854
|
+
this.ctx.loadingAnimation = undefined;
|
|
855
|
+
}
|
|
850
856
|
this.ctx.statusContainer.clear();
|
|
851
857
|
const reasonText =
|
|
852
858
|
event.reason === "overflow" ? "Context overflow detected, " : event.reason === "idle" ? "Idle " : "";
|
|
@@ -939,6 +945,10 @@ export class EventController {
|
|
|
939
945
|
this.ctx.session.abortRetry();
|
|
940
946
|
}
|
|
941
947
|
};
|
|
948
|
+
if (this.ctx.loadingAnimation) {
|
|
949
|
+
this.ctx.loadingAnimation.stop();
|
|
950
|
+
this.ctx.loadingAnimation = undefined;
|
|
951
|
+
}
|
|
942
952
|
this.ctx.statusContainer.clear();
|
|
943
953
|
// Stop any prior retry loader/timer before installing a new one.
|
|
944
954
|
this.ctx.retryLoader?.stop();
|
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { type AgentMessage, ThinkingLevel } from "@gajae-code/agent-core";
|
|
4
4
|
import { type AutocompleteProvider, matchesKey, type SlashCommand } from "@gajae-code/tui";
|
|
5
|
-
import { $
|
|
5
|
+
import { $pickenv, logger, sanitizeText } from "@gajae-code/utils";
|
|
6
6
|
import { type AppKeybinding, KEYBINDINGS } from "../../config/keybindings";
|
|
7
7
|
import { isSettingsInitialized, settings } from "../../config/settings";
|
|
8
8
|
import { resolveSubskillActivationForSkillInvocation } from "../../extensibility/gjc-plugins";
|
|
@@ -725,8 +725,12 @@ export class InputController {
|
|
|
725
725
|
});
|
|
726
726
|
}
|
|
727
727
|
|
|
728
|
+
// Tab on an empty composer accepts the pending ghost-text prompt suggestion.
|
|
729
|
+
this.ctx.editor.onTab = (text: string) => this.ctx.promptSuggestion?.tryAcceptOnTab(text) === true;
|
|
730
|
+
|
|
728
731
|
this.ctx.editor.onChange = (text: string) => {
|
|
729
732
|
this.#resetEscapeGestures();
|
|
733
|
+
this.ctx.promptSuggestion?.notifyEditorChanged(text);
|
|
730
734
|
const wasBashMode = this.ctx.isBashMode;
|
|
731
735
|
const wasBashNoContext = this.ctx.isBashNoContext;
|
|
732
736
|
const wasPythonMode = this.ctx.isPythonMode;
|
|
@@ -752,6 +756,29 @@ export class InputController {
|
|
|
752
756
|
async submitText(text: string, composer: ComposerSubmissionOptions): Promise<void> {
|
|
753
757
|
text = text.trim();
|
|
754
758
|
if ((!isSettingsInitialized() || settings.get("emojiAutocomplete")) && text) text = expandEmoticons(text);
|
|
759
|
+
if (this.ctx.hasActiveBtw()) {
|
|
760
|
+
if (!text) return;
|
|
761
|
+
if (!text.startsWith("/")) {
|
|
762
|
+
const result = await this.ctx.handleBtwFollowUp(text);
|
|
763
|
+
if (result === "accepted" && this.#canModifyComposer(composer)) {
|
|
764
|
+
this.ctx.editor.setText("");
|
|
765
|
+
this.ctx.pendingImages = [];
|
|
766
|
+
}
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
if (/^\/btw(?:\s|$)/.test(text)) {
|
|
772
|
+
const slashResult = await executeBuiltinSlashCommand(text, {
|
|
773
|
+
ctx: this.ctx,
|
|
774
|
+
handleBackgroundCommand: () => this.handleBackgroundCommand(),
|
|
775
|
+
composer,
|
|
776
|
+
});
|
|
777
|
+
if (slashResult === true) {
|
|
778
|
+
this.ctx.pendingImages = [];
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
755
782
|
|
|
756
783
|
// Empty submit while streaming with queued messages: flush queues immediately
|
|
757
784
|
if (!text && this.ctx.session.isStreaming && this.ctx.session.queuedMessageCount > 0) {
|
|
@@ -907,7 +934,7 @@ export class InputController {
|
|
|
907
934
|
|
|
908
935
|
// Generate session title on first message
|
|
909
936
|
const hasUserMessages = this.ctx.session.messages.some((m: AgentMessage) => m.role === "user");
|
|
910
|
-
if (!hasUserMessages && !this.ctx.sessionManager.getSessionName() && !$
|
|
937
|
+
if (!hasUserMessages && !this.ctx.sessionManager.getSessionName() && !$pickenv("GJC_NO_TITLE", "PI_NO_TITLE")) {
|
|
911
938
|
const registry = this.ctx.session.modelRegistry;
|
|
912
939
|
generateSessionTitle(
|
|
913
940
|
text,
|
|
@@ -1357,6 +1384,14 @@ export class InputController {
|
|
|
1357
1384
|
async handleFollowUp(): Promise<void> {
|
|
1358
1385
|
const text = this.ctx.editor.getText().trim();
|
|
1359
1386
|
if (!text) return;
|
|
1387
|
+
// While /btw is open, plain text stays in the side chat. Slash-origin
|
|
1388
|
+
// input keeps normal dispatch so commands remain available.
|
|
1389
|
+
if (this.ctx.hasActiveBtw() && !text.startsWith("/")) {
|
|
1390
|
+
if ((await this.ctx.handleBtwFollowUp(text)) === "accepted") {
|
|
1391
|
+
this.ctx.editor.setText("");
|
|
1392
|
+
}
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1360
1395
|
|
|
1361
1396
|
// Compaction first: while compacting, queue free text and `/skill:*`
|
|
1362
1397
|
// commands in the compaction-local queue. `flushCompactionQueue`
|
|
@@ -1758,6 +1793,7 @@ export class InputController {
|
|
|
1758
1793
|
moveCursorToMessageStart: () => this.ctx.editor.moveToMessageStart(),
|
|
1759
1794
|
moveCursorToLineStart: () => this.ctx.editor.moveToLineStart(),
|
|
1760
1795
|
moveCursorToLineEnd: () => this.ctx.editor.moveToLineEnd(),
|
|
1796
|
+
getPromptSuggestion: () => this.ctx.promptSuggestion?.current ?? null,
|
|
1761
1797
|
});
|
|
1762
1798
|
}
|
|
1763
1799
|
|