@gajae-code/coding-agent 0.3.0 → 0.3.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 +18 -0
- package/dist/types/async/job-manager.d.ts +7 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +4 -4
- package/dist/types/debug/crash-diagnostics.d.ts +45 -0
- package/dist/types/debug/runtime-gauges.d.ts +6 -0
- package/dist/types/deep-interview/render-middleware.d.ts +1 -0
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/eval/py/kernel.d.ts +2 -0
- package/dist/types/exec/bash-executor.d.ts +10 -0
- package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
- package/dist/types/gjc-runtime/state-migrations.d.ts +9 -0
- package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +10 -0
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
- package/dist/types/harness-control-plane/control-endpoint.d.ts +3 -2
- package/dist/types/hooks/skill-state.d.ts +21 -0
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
- package/dist/types/internal-urls/types.d.ts +4 -0
- package/dist/types/lsp/index.d.ts +10 -10
- package/dist/types/modes/bridge/auth.d.ts +12 -0
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
- package/dist/types/modes/bridge/event-stream.d.ts +8 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
- package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
- package/dist/types/modes/index.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/jobs-observer.d.ts +57 -0
- package/dist/types/modes/rpc/host-tools.d.ts +1 -16
- package/dist/types/modes/rpc/host-uris.d.ts +1 -38
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
- package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
- package/dist/types/modes/types.d.ts +1 -0
- package/dist/types/sdk.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +11 -1
- package/dist/types/skill-state/workflow-state-contract.d.ts +1 -2
- package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
- package/dist/types/task/id.d.ts +7 -0
- package/dist/types/task/index.d.ts +5 -0
- package/dist/types/task/receipt.d.ts +85 -0
- package/dist/types/task/spawn-gate.d.ts +38 -0
- package/dist/types/task/types.d.ts +143 -11
- package/dist/types/tools/cron.d.ts +6 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +15 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +36 -0
- package/src/cli/args.ts +9 -2
- package/src/commands/deep-interview.ts +1 -0
- package/src/commands/harness.ts +289 -19
- package/src/commands/launch.ts +2 -2
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +22 -4
- package/src/config/keybindings.ts +6 -0
- package/src/config/settings-schema.ts +6 -3
- package/src/dap/client.ts +17 -3
- package/src/debug/crash-diagnostics.ts +223 -0
- package/src/debug/runtime-gauges.ts +20 -0
- package/src/deep-interview/render-middleware.ts +6 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +28 -2
- package/src/eval/py/executor.ts +21 -1
- package/src/eval/py/kernel.ts +15 -0
- package/src/exec/bash-executor.ts +41 -0
- package/src/gjc-runtime/cli-write-receipt.ts +31 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +69 -32
- package/src/gjc-runtime/ralplan-runtime.ts +213 -36
- package/src/gjc-runtime/state-migrations.ts +54 -7
- package/src/gjc-runtime/state-runtime.ts +461 -64
- package/src/gjc-runtime/state-schema.ts +192 -0
- package/src/gjc-runtime/state-writer.ts +32 -1
- package/src/gjc-runtime/team-runtime.ts +177 -105
- package/src/gjc-runtime/ultragoal-runtime.ts +114 -26
- package/src/gjc-runtime/workflow-command-ref.ts +239 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +108 -4
- package/src/gjc-runtime/workflow-manifest.ts +3 -1
- package/src/harness-control-plane/control-endpoint.ts +19 -8
- package/src/harness-control-plane/owner.ts +57 -10
- package/src/harness-control-plane/state-machine.ts +2 -1
- package/src/hooks/skill-state.ts +176 -26
- package/src/internal-urls/agent-protocol.ts +68 -21
- package/src/internal-urls/artifact-protocol.ts +12 -17
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/internal-urls/registry-helpers.ts +19 -16
- package/src/internal-urls/types.ts +4 -0
- package/src/lsp/client.ts +18 -2
- package/src/main.ts +21 -5
- package/src/modes/bridge/auth.ts +41 -0
- package/src/modes/bridge/bridge-client-bridge.ts +47 -0
- package/src/modes/bridge/bridge-mode.ts +520 -0
- package/src/modes/bridge/bridge-ui-context.ts +200 -0
- package/src/modes/bridge/event-stream.ts +70 -0
- package/src/modes/components/custom-editor.ts +101 -0
- package/src/modes/components/hook-selector.ts +61 -18
- package/src/modes/components/jobs-overlay-model.ts +109 -0
- package/src/modes/components/jobs-overlay.ts +172 -0
- package/src/modes/components/status-line/presets.ts +7 -5
- package/src/modes/components/status-line/segments.ts +25 -0
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/status-line.ts +9 -1
- package/src/modes/controllers/extension-ui-controller.ts +39 -3
- package/src/modes/controllers/input-controller.ts +97 -9
- package/src/modes/controllers/selector-controller.ts +29 -0
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +27 -0
- package/src/modes/jobs-observer.ts +204 -0
- package/src/modes/rpc/host-tools.ts +1 -186
- package/src/modes/rpc/host-uris.ts +1 -235
- package/src/modes/rpc/rpc-client.ts +25 -10
- package/src/modes/rpc/rpc-mode.ts +12 -381
- package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
- package/src/modes/shared/agent-wire/command-validation.ts +131 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
- package/src/modes/shared/agent-wire/handshake.ts +117 -0
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
- package/src/modes/shared/agent-wire/protocol.ts +96 -0
- package/src/modes/shared/agent-wire/responses.ts +17 -0
- package/src/modes/shared/agent-wire/scopes.ts +89 -0
- package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
- package/src/modes/shared/agent-wire/ui-result.ts +48 -0
- package/src/modes/types.ts +1 -0
- package/src/prompts/tools/subagent.md +12 -7
- package/src/prompts/tools/task-summary.md +3 -9
- package/src/prompts/tools/task.md +5 -1
- package/src/sdk.ts +4 -0
- package/src/session/agent-session.ts +214 -38
- package/src/skill-state/deep-interview-mutation-guard.ts +23 -4
- package/src/skill-state/workflow-state-contract.ts +7 -4
- package/src/skill-state/workflow-state-version.ts +3 -0
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/task/executor.ts +29 -5
- package/src/task/id.ts +33 -0
- package/src/task/index.ts +257 -67
- package/src/task/output-manager.ts +5 -4
- package/src/task/receipt.ts +297 -0
- package/src/task/render.ts +48 -131
- package/src/task/spawn-gate.ts +132 -0
- package/src/task/types.ts +48 -7
- package/src/tools/ask.ts +73 -33
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash.ts +1 -1
- package/src/tools/cron.ts +48 -0
- package/src/tools/find.ts +4 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +1 -0
- package/src/tools/search.ts +1 -0
- package/src/tools/skill.ts +6 -1
- package/src/tools/subagent.ts +237 -84
|
@@ -186,7 +186,12 @@ export class RpcClient {
|
|
|
186
186
|
cwd: this.options.cwd,
|
|
187
187
|
env: { ...Bun.env, ...this.options.env },
|
|
188
188
|
stdin: "pipe",
|
|
189
|
+
stderr: "full",
|
|
189
190
|
});
|
|
191
|
+
const startupStderrPromise = this.#process.stderr
|
|
192
|
+
? new Response(this.#process.stderr).text().catch(() => "")
|
|
193
|
+
: Promise.resolve("");
|
|
194
|
+
const getStartupStderr = async () => this.#process?.peekStderr() || (await startupStderrPromise);
|
|
190
195
|
|
|
191
196
|
// Wait for the "ready" signal or process exit
|
|
192
197
|
const { promise: readyPromise, resolve: readyResolve, reject: readyReject } = Promise.withResolvers<void>();
|
|
@@ -203,10 +208,20 @@ export class RpcClient {
|
|
|
203
208
|
}
|
|
204
209
|
this.#handleLine(line);
|
|
205
210
|
}
|
|
206
|
-
// Stream ended without ready signal — process exited
|
|
211
|
+
// Stream ended without ready signal — process exited. Wait for the
|
|
212
|
+
// managed process wrapper so stderr is fully drained before reporting.
|
|
207
213
|
if (!readySettled) {
|
|
208
|
-
|
|
209
|
-
|
|
214
|
+
const proc = this.#process;
|
|
215
|
+
const exitCode = proc ? await proc.exited.catch(() => proc.exitCode ?? -1) : undefined;
|
|
216
|
+
if (!readySettled) {
|
|
217
|
+
const stderr = await getStartupStderr();
|
|
218
|
+
readySettled = true;
|
|
219
|
+
readyReject(
|
|
220
|
+
new Error(
|
|
221
|
+
`Agent process exited${exitCode === undefined ? "" : ` with code ${exitCode}`} before ready. Stderr: ${stderr}`,
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
}
|
|
210
225
|
}
|
|
211
226
|
})().catch((err: Error) => {
|
|
212
227
|
if (!readySettled) {
|
|
@@ -216,12 +231,12 @@ export class RpcClient {
|
|
|
216
231
|
});
|
|
217
232
|
|
|
218
233
|
// Also race against process exit (in case stdout closes before we read it)
|
|
219
|
-
void this.#process.exited.then((exitCode: number) => {
|
|
234
|
+
void this.#process.exited.then(async (exitCode: number) => {
|
|
220
235
|
if (!readySettled) {
|
|
236
|
+
const stderr = await getStartupStderr();
|
|
237
|
+
if (readySettled) return;
|
|
221
238
|
readySettled = true;
|
|
222
|
-
readyReject(
|
|
223
|
-
new Error(`Agent process exited with code ${exitCode}. Stderr: ${this.#process?.peekStderr() ?? ""}`),
|
|
224
|
-
);
|
|
239
|
+
readyReject(new Error(`Agent process exited with code ${exitCode}. Stderr: ${stderr}`));
|
|
225
240
|
}
|
|
226
241
|
});
|
|
227
242
|
|
|
@@ -229,9 +244,9 @@ export class RpcClient {
|
|
|
229
244
|
const readyTimeout = this.#startTimeout(30000, () => {
|
|
230
245
|
if (readySettled) return;
|
|
231
246
|
readySettled = true;
|
|
232
|
-
|
|
233
|
-
new Error(`Timeout waiting for agent to become ready. Stderr: ${
|
|
234
|
-
);
|
|
247
|
+
void getStartupStderr().then(stderr => {
|
|
248
|
+
readyReject(new Error(`Timeout waiting for agent to become ready. Stderr: ${stderr}`));
|
|
249
|
+
});
|
|
235
250
|
});
|
|
236
251
|
|
|
237
252
|
try {
|
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
* - Events: AgentSessionEvent objects streamed as they occur
|
|
11
11
|
* - Extension UI: Extension UI requests are emitted, client responds with extension_ui_response
|
|
12
12
|
*/
|
|
13
|
-
import { getOAuthProviders } from "@gajae-code/ai/utils/oauth";
|
|
14
13
|
import { $env, readJsonl, Snowflake } from "@gajae-code/utils";
|
|
15
14
|
import type {
|
|
16
15
|
ExtensionUIContext,
|
|
@@ -20,6 +19,8 @@ import type {
|
|
|
20
19
|
import { type Theme, theme } from "../../modes/theme/theme";
|
|
21
20
|
import type { AgentSession } from "../../session/agent-session";
|
|
22
21
|
import { initializeExtensions } from "../runtime-init";
|
|
22
|
+
import { dispatchRpcCommand } from "../shared/agent-wire/command-dispatch";
|
|
23
|
+
import { rpcError as error } from "../shared/agent-wire/responses";
|
|
23
24
|
import { isRpcHostToolResult, isRpcHostToolUpdate, RpcHostToolBridge } from "./host-tools";
|
|
24
25
|
import { isRpcHostUriResult, RpcHostUriBridge } from "./host-uris";
|
|
25
26
|
import type {
|
|
@@ -28,11 +29,9 @@ import type {
|
|
|
28
29
|
RpcExtensionUIResponse,
|
|
29
30
|
RpcHostToolCallRequest,
|
|
30
31
|
RpcHostToolCancelRequest,
|
|
31
|
-
RpcHostToolDefinition,
|
|
32
32
|
RpcHostUriCancelRequest,
|
|
33
33
|
RpcHostUriRequest,
|
|
34
34
|
RpcResponse,
|
|
35
|
-
RpcSessionState,
|
|
36
35
|
} from "./rpc-types";
|
|
37
36
|
|
|
38
37
|
// Re-export types for consumers
|
|
@@ -54,30 +53,6 @@ type RpcOutput = (
|
|
|
54
53
|
| object,
|
|
55
54
|
) => void;
|
|
56
55
|
|
|
57
|
-
function normalizeHostToolDefinitions(tools: RpcHostToolDefinition[]): RpcHostToolDefinition[] {
|
|
58
|
-
return tools.map((tool, index) => {
|
|
59
|
-
const name = typeof tool.name === "string" ? tool.name.trim() : "";
|
|
60
|
-
if (!name) {
|
|
61
|
-
throw new Error(`Host tool at index ${index} must provide a non-empty name`);
|
|
62
|
-
}
|
|
63
|
-
const description = typeof tool.description === "string" ? tool.description.trim() : "";
|
|
64
|
-
if (!description) {
|
|
65
|
-
throw new Error(`Host tool "${name}" must provide a non-empty description`);
|
|
66
|
-
}
|
|
67
|
-
if (!tool.parameters || typeof tool.parameters !== "object" || Array.isArray(tool.parameters)) {
|
|
68
|
-
throw new Error(`Host tool "${name}" must provide a JSON Schema object`);
|
|
69
|
-
}
|
|
70
|
-
const label = typeof tool.label === "string" && tool.label.trim() ? tool.label.trim() : name;
|
|
71
|
-
return {
|
|
72
|
-
name,
|
|
73
|
-
label,
|
|
74
|
-
description,
|
|
75
|
-
parameters: tool.parameters,
|
|
76
|
-
hidden: tool.hidden === true,
|
|
77
|
-
};
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
|
|
81
56
|
function parseValueDialogResponse(
|
|
82
57
|
response: RpcExtensionUIResponse,
|
|
83
58
|
dialogOptions: ExtensionUIDialogOptions | undefined,
|
|
@@ -181,21 +156,6 @@ export async function runRpcMode(
|
|
|
181
156
|
};
|
|
182
157
|
const emitRpcTitles = shouldEmitRpcTitles();
|
|
183
158
|
|
|
184
|
-
const success = <T extends RpcCommand["type"]>(
|
|
185
|
-
id: string | undefined,
|
|
186
|
-
command: T,
|
|
187
|
-
data?: object | null,
|
|
188
|
-
): RpcResponse => {
|
|
189
|
-
if (data === undefined) {
|
|
190
|
-
return { id, type: "response", command, success: true } as RpcResponse;
|
|
191
|
-
}
|
|
192
|
-
return { id, type: "response", command, success: true, data } as RpcResponse;
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
const error = (id: string | undefined, command: string, message: string): RpcResponse => {
|
|
196
|
-
return { id, type: "response", command, success: false, error: message };
|
|
197
|
-
};
|
|
198
|
-
|
|
199
159
|
const pendingExtensionRequests = new Map<string, PendingExtensionRequest>();
|
|
200
160
|
const hostToolBridge = new RpcHostToolBridge(output);
|
|
201
161
|
const hostUriBridge = new RpcHostUriBridge(output);
|
|
@@ -450,345 +410,16 @@ export async function runRpcMode(
|
|
|
450
410
|
output(event);
|
|
451
411
|
});
|
|
452
412
|
|
|
453
|
-
// Handle a single command
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
// Don't await - events will stream
|
|
464
|
-
// Extension commands are executed immediately, file prompt templates are expanded
|
|
465
|
-
// If streaming and streamingBehavior specified, queues via steer/followUp
|
|
466
|
-
session
|
|
467
|
-
.prompt(command.message, {
|
|
468
|
-
images: command.images,
|
|
469
|
-
streamingBehavior: command.streamingBehavior,
|
|
470
|
-
})
|
|
471
|
-
.catch(e => output(error(id, "prompt", e.message)));
|
|
472
|
-
return success(id, "prompt");
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
case "steer": {
|
|
476
|
-
await session.steer(command.message, command.images);
|
|
477
|
-
return success(id, "steer");
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
case "follow_up": {
|
|
481
|
-
await session.followUp(command.message, command.images);
|
|
482
|
-
return success(id, "follow_up");
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
case "abort": {
|
|
486
|
-
await session.abort();
|
|
487
|
-
return success(id, "abort");
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
case "abort_and_prompt": {
|
|
491
|
-
await session.abort();
|
|
492
|
-
session
|
|
493
|
-
.prompt(command.message, { images: command.images })
|
|
494
|
-
.catch(e => output(error(id, "abort_and_prompt", e.message)));
|
|
495
|
-
return success(id, "abort_and_prompt");
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
case "new_session": {
|
|
499
|
-
const options = command.parentSession ? { parentSession: command.parentSession } : undefined;
|
|
500
|
-
const cancelled = !(await session.newSession(options));
|
|
501
|
-
return success(id, "new_session", { cancelled });
|
|
502
|
-
}
|
|
503
|
-
|
|
504
|
-
// =================================================================
|
|
505
|
-
// State
|
|
506
|
-
// =================================================================
|
|
507
|
-
|
|
508
|
-
case "get_state": {
|
|
509
|
-
const state: RpcSessionState = {
|
|
510
|
-
model: session.model,
|
|
511
|
-
thinkingLevel: session.thinkingLevel,
|
|
512
|
-
isStreaming: session.isStreaming,
|
|
513
|
-
isCompacting: session.isCompacting,
|
|
514
|
-
steeringMode: session.steeringMode,
|
|
515
|
-
followUpMode: session.followUpMode,
|
|
516
|
-
interruptMode: session.interruptMode,
|
|
517
|
-
sessionFile: session.sessionFile,
|
|
518
|
-
sessionId: session.sessionId,
|
|
519
|
-
sessionName: session.sessionName,
|
|
520
|
-
autoCompactionEnabled: session.autoCompactionEnabled,
|
|
521
|
-
messageCount: session.messages.length,
|
|
522
|
-
queuedMessageCount: session.queuedMessageCount,
|
|
523
|
-
todoPhases: session.getTodoPhases(),
|
|
524
|
-
systemPrompt: session.systemPrompt,
|
|
525
|
-
dumpTools: session.agent.state.tools.map(tool => ({
|
|
526
|
-
name: tool.name,
|
|
527
|
-
description: tool.description,
|
|
528
|
-
parameters: tool.parameters,
|
|
529
|
-
})),
|
|
530
|
-
contextUsage: session.getContextUsage(),
|
|
531
|
-
};
|
|
532
|
-
return success(id, "get_state", state);
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
case "set_todos": {
|
|
536
|
-
session.setTodoPhases(command.phases);
|
|
537
|
-
return success(id, "set_todos", { todoPhases: session.getTodoPhases() });
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
case "set_host_tools": {
|
|
541
|
-
const tools = normalizeHostToolDefinitions(command.tools);
|
|
542
|
-
const rpcTools = hostToolBridge.setTools(tools);
|
|
543
|
-
await session.refreshRpcHostTools(rpcTools);
|
|
544
|
-
return success(id, "set_host_tools", { toolNames: tools.map(tool => tool.name) });
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
case "set_host_uri_schemes": {
|
|
548
|
-
try {
|
|
549
|
-
const schemes = hostUriBridge.setSchemes(command.schemes);
|
|
550
|
-
return success(id, "set_host_uri_schemes", { schemes });
|
|
551
|
-
} catch (err) {
|
|
552
|
-
return error(id, "set_host_uri_schemes", err instanceof Error ? err.message : String(err));
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
|
|
556
|
-
// =================================================================
|
|
557
|
-
// Model
|
|
558
|
-
// =================================================================
|
|
559
|
-
|
|
560
|
-
case "set_model": {
|
|
561
|
-
const models = session.getAvailableModels();
|
|
562
|
-
const model = models.find(m => m.provider === command.provider && m.id === command.modelId);
|
|
563
|
-
if (!model) {
|
|
564
|
-
return error(id, "set_model", `Model not found: ${command.provider}/${command.modelId}`);
|
|
565
|
-
}
|
|
566
|
-
await session.setModel(model);
|
|
567
|
-
return success(id, "set_model", model);
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
case "cycle_model": {
|
|
571
|
-
const result = await session.cycleModel();
|
|
572
|
-
if (!result) {
|
|
573
|
-
return success(id, "cycle_model", null);
|
|
574
|
-
}
|
|
575
|
-
return success(id, "cycle_model", result);
|
|
576
|
-
}
|
|
577
|
-
|
|
578
|
-
case "get_available_models": {
|
|
579
|
-
const models = session.getAvailableModels();
|
|
580
|
-
return success(id, "get_available_models", { models });
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
// =================================================================
|
|
584
|
-
// Thinking
|
|
585
|
-
// =================================================================
|
|
586
|
-
|
|
587
|
-
case "set_thinking_level": {
|
|
588
|
-
session.setThinkingLevel(command.level);
|
|
589
|
-
return success(id, "set_thinking_level");
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
case "cycle_thinking_level": {
|
|
593
|
-
const level = session.cycleThinkingLevel();
|
|
594
|
-
if (!level) {
|
|
595
|
-
return success(id, "cycle_thinking_level", null);
|
|
596
|
-
}
|
|
597
|
-
return success(id, "cycle_thinking_level", { level });
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// =================================================================
|
|
601
|
-
// Queue Modes
|
|
602
|
-
// =================================================================
|
|
603
|
-
|
|
604
|
-
case "set_steering_mode": {
|
|
605
|
-
session.setSteeringMode(command.mode);
|
|
606
|
-
return success(id, "set_steering_mode");
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
case "set_follow_up_mode": {
|
|
610
|
-
session.setFollowUpMode(command.mode);
|
|
611
|
-
return success(id, "set_follow_up_mode");
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
case "set_interrupt_mode": {
|
|
615
|
-
session.setInterruptMode(command.mode);
|
|
616
|
-
return success(id, "set_interrupt_mode");
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
// =================================================================
|
|
620
|
-
// Compaction
|
|
621
|
-
// =================================================================
|
|
622
|
-
|
|
623
|
-
case "compact": {
|
|
624
|
-
const result = await session.compact(command.customInstructions);
|
|
625
|
-
return success(id, "compact", result);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
case "set_auto_compaction": {
|
|
629
|
-
session.setAutoCompactionEnabled(command.enabled);
|
|
630
|
-
return success(id, "set_auto_compaction");
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// =================================================================
|
|
634
|
-
// Retry
|
|
635
|
-
// =================================================================
|
|
636
|
-
|
|
637
|
-
case "set_auto_retry": {
|
|
638
|
-
session.setAutoRetryEnabled(command.enabled);
|
|
639
|
-
return success(id, "set_auto_retry");
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
case "abort_retry": {
|
|
643
|
-
session.abortRetry();
|
|
644
|
-
return success(id, "abort_retry");
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
// =================================================================
|
|
648
|
-
// Bash
|
|
649
|
-
// =================================================================
|
|
650
|
-
|
|
651
|
-
case "bash": {
|
|
652
|
-
const result = await session.executeBash(command.command);
|
|
653
|
-
return success(id, "bash", result);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
case "abort_bash": {
|
|
657
|
-
session.abortBash();
|
|
658
|
-
return success(id, "abort_bash");
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// =================================================================
|
|
662
|
-
// Session
|
|
663
|
-
// =================================================================
|
|
664
|
-
|
|
665
|
-
case "get_session_stats": {
|
|
666
|
-
const stats = session.getSessionStats();
|
|
667
|
-
return success(id, "get_session_stats", stats);
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
case "export_html": {
|
|
671
|
-
const path = await session.exportToHtml(command.outputPath);
|
|
672
|
-
return success(id, "export_html", { path });
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
case "switch_session": {
|
|
676
|
-
const cancelled = !(await session.switchSession(command.sessionPath));
|
|
677
|
-
return success(id, "switch_session", { cancelled });
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
case "branch": {
|
|
681
|
-
const result = await session.branch(command.entryId);
|
|
682
|
-
return success(id, "branch", { text: result.selectedText, cancelled: result.cancelled });
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
case "get_branch_messages": {
|
|
686
|
-
const messages = session.getUserMessagesForBranching();
|
|
687
|
-
return success(id, "get_branch_messages", { messages });
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
case "get_last_assistant_text": {
|
|
691
|
-
const text = session.getLastAssistantText();
|
|
692
|
-
return success(id, "get_last_assistant_text", { text });
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
case "set_session_name": {
|
|
696
|
-
const name = command.name.trim();
|
|
697
|
-
if (!name) {
|
|
698
|
-
return error(id, "set_session_name", "Session name cannot be empty");
|
|
699
|
-
}
|
|
700
|
-
const applied = await session.setSessionName(name, "user");
|
|
701
|
-
if (!applied) {
|
|
702
|
-
return error(id, "set_session_name", "Session name cannot be empty");
|
|
703
|
-
}
|
|
704
|
-
return success(id, "set_session_name");
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
case "handoff": {
|
|
708
|
-
const result = await session.handoff(command.customInstructions);
|
|
709
|
-
return success(id, "handoff", result ? { savedPath: result.savedPath } : null);
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
// =================================================================
|
|
713
|
-
// Messages
|
|
714
|
-
// =================================================================
|
|
715
|
-
|
|
716
|
-
case "get_messages": {
|
|
717
|
-
return success(id, "get_messages", { messages: session.messages });
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
// =================================================================
|
|
721
|
-
// Login
|
|
722
|
-
// =================================================================
|
|
723
|
-
|
|
724
|
-
case "get_login_providers": {
|
|
725
|
-
const providers = getOAuthProviders().map(provider => ({
|
|
726
|
-
id: provider.id,
|
|
727
|
-
name: provider.name,
|
|
728
|
-
available: provider.available,
|
|
729
|
-
authenticated: session.modelRegistry.authStorage.hasAuth(provider.id),
|
|
730
|
-
}));
|
|
731
|
-
return success(id, "get_login_providers", { providers });
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
case "login": {
|
|
735
|
-
const knownProvider = getOAuthProviders().find(p => p.id === command.providerId);
|
|
736
|
-
if (!knownProvider) {
|
|
737
|
-
return error(id, "login", `Unknown OAuth provider: ${command.providerId}`);
|
|
738
|
-
}
|
|
739
|
-
const uiCtx = new RpcExtensionUIContext(pendingExtensionRequests, output);
|
|
740
|
-
// Track whether onAuth has fired. Providers that use OAuthCallbackFlow
|
|
741
|
-
// always call onAuth first (emit browser URL), then onManualCodeInput as
|
|
742
|
-
// a fallback. Providers that require interactive input (API-key paste,
|
|
743
|
-
// GitHub Enterprise URL, device-code entry) call onPrompt before onAuth.
|
|
744
|
-
// We use this ordering to self-classify at runtime — no static allowlist.
|
|
745
|
-
let authEmitted = false;
|
|
746
|
-
try {
|
|
747
|
-
await session.modelRegistry.authStorage.login(command.providerId, {
|
|
748
|
-
onAuth: info => {
|
|
749
|
-
authEmitted = true;
|
|
750
|
-
output({
|
|
751
|
-
type: "extension_ui_request",
|
|
752
|
-
id: Snowflake.next() as string,
|
|
753
|
-
method: "open_url",
|
|
754
|
-
url: info.url,
|
|
755
|
-
instructions: info.instructions,
|
|
756
|
-
} as RpcExtensionUIRequest);
|
|
757
|
-
},
|
|
758
|
-
onProgress: message => {
|
|
759
|
-
uiCtx.notify(message, "info");
|
|
760
|
-
},
|
|
761
|
-
onPrompt: () => {
|
|
762
|
-
if (!authEmitted) {
|
|
763
|
-
// onPrompt called before any auth URL — provider requires
|
|
764
|
-
// interactive input that cannot be satisfied headlessly.
|
|
765
|
-
return Promise.reject(
|
|
766
|
-
new Error(
|
|
767
|
-
`Provider '${command.providerId}' requires interactive prompts ` +
|
|
768
|
-
"which are not supported in RPC mode. Use the terminal UI to log in.",
|
|
769
|
-
),
|
|
770
|
-
);
|
|
771
|
-
}
|
|
772
|
-
// onAuth has already fired — we are inside OAuthCallbackFlow's
|
|
773
|
-
// manual-redirect fallback race. Returning a never-settling promise
|
|
774
|
-
// lets the race block until the callback server wins; a rejection
|
|
775
|
-
// would be caught as null and spin the while(true) loop.
|
|
776
|
-
return new Promise<string>(() => {});
|
|
777
|
-
},
|
|
778
|
-
});
|
|
779
|
-
await session.modelRegistry.refresh();
|
|
780
|
-
return success(id, "login", { providerId: command.providerId });
|
|
781
|
-
} catch (err: unknown) {
|
|
782
|
-
return error(id, "login", err instanceof Error ? err.message : String(err));
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
default: {
|
|
787
|
-
const unknownCommand = command as { type: string };
|
|
788
|
-
return error(undefined, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
};
|
|
413
|
+
// Handle a single command through the shared agent-wire dispatcher so RPC
|
|
414
|
+
// and bridge mode use one command surface.
|
|
415
|
+
const handleCommand = (command: RpcCommand): Promise<RpcResponse> =>
|
|
416
|
+
dispatchRpcCommand(command, {
|
|
417
|
+
session,
|
|
418
|
+
output,
|
|
419
|
+
hostToolRegistry: hostToolBridge,
|
|
420
|
+
hostUriRegistry: hostUriBridge,
|
|
421
|
+
createUiContext: () => new RpcExtensionUIContext(pendingExtensionRequests, output),
|
|
422
|
+
});
|
|
792
423
|
|
|
793
424
|
/**
|
|
794
425
|
* Check if shutdown was requested and perform shutdown if so.
|