@gajae-code/coding-agent 0.5.1 → 0.5.3
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 +31 -0
- package/README.md +1 -1
- package/dist/types/async/job-manager.d.ts +6 -0
- package/dist/types/cli/setup-cli.d.ts +8 -1
- package/dist/types/commands/setup.d.ts +7 -0
- package/dist/types/config/file-lock.d.ts +24 -2
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +62 -0
- package/dist/types/dap/client.d.ts +2 -1
- package/dist/types/edit/read-file.d.ts +6 -0
- package/dist/types/eval/js/context-manager.d.ts +3 -0
- package/dist/types/eval/js/executor.d.ts +1 -0
- package/dist/types/exec/bash-executor.d.ts +2 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +64 -2
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +7 -1
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +29 -0
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +1 -0
- package/dist/types/modes/components/model-selector.d.ts +2 -0
- package/dist/types/modes/components/oauth-selector.d.ts +1 -0
- package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
- package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +1 -0
- package/dist/types/modes/components/tool-execution.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-mode.d.ts +56 -1
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/theme/defaults/index.d.ts +302 -0
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/modes/types.d.ts +1 -1
- package/dist/types/runtime/process-lifecycle.d.ts +108 -0
- package/dist/types/runtime-mcp/transports/stdio.d.ts +1 -0
- package/dist/types/runtime-mcp/types.d.ts +2 -0
- package/dist/types/session/agent-session.d.ts +17 -1
- package/dist/types/session/artifacts.d.ts +4 -1
- package/dist/types/session/history-storage.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +10 -1
- package/dist/types/session/streaming-output.d.ts +5 -0
- package/dist/types/setup/credential-import.d.ts +79 -0
- package/dist/types/slash-commands/helpers/fast-status-report.d.ts +76 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/render.d.ts +1 -1
- package/dist/types/tools/bash.d.ts +1 -0
- package/dist/types/tools/browser/tab-supervisor.d.ts +9 -0
- package/dist/types/tools/sqlite-reader.d.ts +2 -1
- package/dist/types/tools/subagent-render.d.ts +7 -1
- package/dist/types/tools/subagent.d.ts +21 -0
- package/dist/types/tools/ultragoal-ask-guard.d.ts +5 -0
- package/dist/types/web/search/index.d.ts +4 -4
- package/dist/types/web/search/provider.d.ts +16 -20
- package/dist/types/web/search/providers/base.d.ts +2 -1
- package/dist/types/web/search/providers/openai-compatible.d.ts +9 -0
- package/dist/types/web/search/types.d.ts +14 -2
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +153 -39
- package/src/cli/args.ts +2 -0
- package/src/cli/fast-help.ts +2 -0
- package/src/cli/setup-cli.ts +138 -3
- package/src/commands/setup.ts +5 -1
- package/src/commands/ultragoal.ts +3 -1
- package/src/config/file-lock-gc.ts +14 -2
- package/src/config/file-lock.ts +63 -13
- package/src/config/model-profile-activation.ts +15 -3
- package/src/config/model-profiles.ts +15 -15
- package/src/config/model-registry.ts +21 -1
- package/src/config/models-config-schema.ts +1 -0
- package/src/config/settings-schema.ts +62 -0
- package/src/dap/client.ts +105 -64
- package/src/dap/session.ts +44 -7
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +30 -8
- package/src/edit/read-file.ts +19 -1
- package/src/eval/js/context-manager.ts +228 -65
- package/src/eval/js/executor.ts +2 -0
- package/src/eval/js/index.ts +1 -0
- package/src/eval/js/worker-core.ts +10 -6
- package/src/eval/py/executor.ts +68 -19
- package/src/eval/py/kernel.ts +46 -22
- package/src/eval/py/runner.py +68 -14
- package/src/exec/bash-executor.ts +49 -13
- package/src/gjc-runtime/deep-interview-recorder.ts +40 -0
- package/src/gjc-runtime/launch-tmux.ts +3 -4
- package/src/gjc-runtime/ralplan-runtime.ts +174 -12
- package/src/gjc-runtime/state-runtime.ts +2 -1
- package/src/gjc-runtime/state-writer.ts +254 -7
- package/src/gjc-runtime/tmux-gc.ts +88 -38
- package/src/gjc-runtime/tmux-sessions.ts +44 -6
- package/src/gjc-runtime/ultragoal-guard.ts +155 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1227 -31
- package/src/gjc-runtime/workflow-manifest.generated.json +44 -0
- package/src/gjc-runtime/workflow-manifest.ts +12 -0
- package/src/harness-control-plane/owner.ts +3 -2
- package/src/harness-control-plane/rpc-adapter.ts +1 -1
- package/src/hooks/skill-state.ts +121 -2
- package/src/internal-urls/artifact-protocol.ts +10 -1
- package/src/internal-urls/docs-index.generated.ts +14 -10
- package/src/lsp/client.ts +64 -26
- package/src/lsp/defaults.json +1 -0
- package/src/lsp/index.ts +2 -1
- package/src/lsp/lspmux.ts +33 -9
- package/src/lsp/types.ts +2 -0
- package/src/main.ts +14 -4
- package/src/modes/acp/acp-agent.ts +4 -2
- package/src/modes/bridge/bridge-mode.ts +23 -1
- package/src/modes/components/assistant-message.ts +10 -2
- package/src/modes/components/bash-execution.ts +5 -1
- package/src/modes/components/eval-execution.ts +5 -1
- package/src/modes/components/history-search.ts +5 -2
- package/src/modes/components/model-selector.ts +60 -2
- package/src/modes/components/oauth-selector.ts +5 -0
- package/src/modes/components/provider-onboarding-selector.ts +6 -1
- package/src/modes/components/runtime-mcp-add-wizard.ts +58 -7
- package/src/modes/components/skill-message.ts +24 -16
- package/src/modes/components/tool-execution.ts +6 -0
- package/src/modes/controllers/extension-ui-controller.ts +33 -6
- package/src/modes/controllers/input-controller.ts +5 -0
- package/src/modes/controllers/selector-controller.ts +86 -2
- package/src/modes/interactive-mode.ts +11 -1
- package/src/modes/rpc/rpc-mode.ts +132 -18
- package/src/modes/shared/agent-wire/command-dispatch.ts +5 -2
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +3 -0
- package/src/modes/shared/agent-wire/unattended-session.ts +16 -1
- package/src/modes/theme/defaults/claude-code.json +100 -0
- package/src/modes/theme/defaults/codex.json +100 -0
- package/src/modes/theme/defaults/index.ts +6 -0
- package/src/modes/theme/defaults/opencode.json +102 -0
- package/src/modes/theme/theme.ts +2 -2
- package/src/modes/types.ts +1 -1
- package/src/modes/utils/ui-helpers.ts +5 -2
- package/src/prompts/agents/executor.md +5 -2
- package/src/runtime/process-lifecycle.ts +400 -0
- package/src/runtime-mcp/manager.ts +164 -50
- package/src/runtime-mcp/transports/http.ts +12 -11
- package/src/runtime-mcp/transports/stdio.ts +64 -38
- package/src/runtime-mcp/types.ts +3 -0
- package/src/sdk.ts +39 -1
- package/src/session/agent-session.ts +190 -33
- package/src/session/artifacts.ts +17 -2
- package/src/session/blob-store.ts +36 -2
- package/src/session/history-storage.ts +32 -11
- package/src/session/session-manager.ts +99 -31
- package/src/session/streaming-output.ts +54 -3
- package/src/setup/credential-import.ts +429 -0
- package/src/skill-state/deep-interview-mutation-guard.ts +2 -1
- package/src/slash-commands/builtin-registry.ts +30 -3
- package/src/slash-commands/helpers/fast-status-report.ts +111 -0
- package/src/task/executor.ts +7 -1
- package/src/task/render.ts +18 -7
- package/src/tools/archive-reader.ts +10 -1
- package/src/tools/ask.ts +4 -2
- package/src/tools/bash.ts +11 -4
- package/src/tools/browser/tab-supervisor.ts +22 -0
- package/src/tools/browser.ts +38 -4
- package/src/tools/cron.ts +1 -1
- package/src/tools/read.ts +11 -12
- package/src/tools/sqlite-reader.ts +19 -5
- package/src/tools/subagent-render.ts +119 -29
- package/src/tools/subagent.ts +147 -7
- package/src/tools/ultragoal-ask-guard.ts +39 -0
- package/src/web/search/index.ts +25 -25
- package/src/web/search/provider.ts +178 -87
- package/src/web/search/providers/base.ts +2 -1
- package/src/web/search/providers/openai-compatible.ts +151 -0
- package/src/web/search/types.ts +47 -22
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import * as fs from "node:fs/promises";
|
|
15
15
|
import * as path from "node:path";
|
|
16
|
-
import { $pickenv, readLines, Snowflake } from "@gajae-code/utils";
|
|
16
|
+
import { $pickenv, logger, readLines, Snowflake } from "@gajae-code/utils";
|
|
17
17
|
import type {
|
|
18
18
|
ExtensionUIContext,
|
|
19
19
|
ExtensionUIDialogOptions,
|
|
@@ -27,7 +27,7 @@ import { AgentWireFrameSequencer, toAgentWireEventFrame } from "../shared/agent-
|
|
|
27
27
|
import { rpcError as error } from "../shared/agent-wire/responses";
|
|
28
28
|
import { registerRpcSession, unregisterRpcSession } from "../shared/agent-wire/session-registry";
|
|
29
29
|
import { defaultAuditPath, UnattendedAuditLog } from "../shared/agent-wire/unattended-audit";
|
|
30
|
-
import { UnattendedSessionControlPlane } from "../shared/agent-wire/unattended-session";
|
|
30
|
+
import { modelSupportsTokenCostMetrics, UnattendedSessionControlPlane } from "../shared/agent-wire/unattended-session";
|
|
31
31
|
import { FileGateStore } from "../shared/agent-wire/workflow-gate-broker";
|
|
32
32
|
import { isRpcHostToolResult, isRpcHostToolUpdate, RpcHostToolBridge } from "./host-tools";
|
|
33
33
|
import { isRpcHostUriResult, RpcHostUriBridge } from "./host-uris";
|
|
@@ -82,6 +82,82 @@ export function shouldEmitRpcTitlesForTest(): boolean {
|
|
|
82
82
|
|
|
83
83
|
const shouldEmitRpcTitles = shouldEmitRpcTitlesForTest;
|
|
84
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Cancellation commands bypass the ordered serial chain because they must
|
|
87
|
+
* interrupt in-flight work — they cannot wait behind the very command they are
|
|
88
|
+
* meant to abort.
|
|
89
|
+
*/
|
|
90
|
+
export const RPC_CANCELLATION_COMMANDS: ReadonlySet<RpcCommand["type"]> = new Set<RpcCommand["type"]>([
|
|
91
|
+
"abort",
|
|
92
|
+
"abort_bash",
|
|
93
|
+
"abort_retry",
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Safe read-only commands that bypass the ordered serial chain so they never
|
|
98
|
+
* head-of-line-block behind a long-running ordered command like
|
|
99
|
+
* `bash`/`compact`/`handoff`/`login` (#606, issue 13 — the partial fix only
|
|
100
|
+
* fast-laned cancellation).
|
|
101
|
+
*
|
|
102
|
+
* Every command listed here has a dispatch handler that is **fully synchronous
|
|
103
|
+
* and side-effect-free**: on the single-threaded event loop it runs to
|
|
104
|
+
* completion between the await points of any in-flight ordered command, reading
|
|
105
|
+
* live state without mutating it. Because such a read performs no causal write,
|
|
106
|
+
* jumping ahead of an earlier *queued* ordered command is observably harmless —
|
|
107
|
+
* there is no state change to reorder. Read payloads are additionally
|
|
108
|
+
* snapshotted inside the handler (e.g. `get_messages` returns a shallow copy of
|
|
109
|
+
* `session.messages`) so a fast-lane read can never serialize a half-mutated
|
|
110
|
+
* array that an ordered turn/compaction is rewriting in place.
|
|
111
|
+
*
|
|
112
|
+
* Deliberately excluded (kept ordered): every async/long command and every
|
|
113
|
+
* mutating command. In particular the control-flag setters (`set_thinking_level`,
|
|
114
|
+
* `cycle_thinking_level`, `set_steering_mode`, `set_follow_up_mode`,
|
|
115
|
+
* `set_interrupt_mode`, `set_auto_compaction`, `set_auto_retry`) stay ordered.
|
|
116
|
+
* Their handlers are synchronous, so fast-laning one ahead of an already-queued
|
|
117
|
+
* `prompt`/`bash` would apply the new mode *before* that earlier command runs —
|
|
118
|
+
* the earlier command would then observe the later setter's value, a
|
|
119
|
+
* causal-order (arrival-order) regression. Mutations therefore stay on the
|
|
120
|
+
* chain, and new command types default to ordered (fail-safe).
|
|
121
|
+
*/
|
|
122
|
+
export const RPC_SAFE_READ_CONTROL_COMMANDS: ReadonlySet<RpcCommand["type"]> = new Set<RpcCommand["type"]>([
|
|
123
|
+
// Pure synchronous reads — snapshot live state at processing time, never mutate.
|
|
124
|
+
"get_state",
|
|
125
|
+
"get_session_stats",
|
|
126
|
+
"get_available_models",
|
|
127
|
+
"get_branch_messages",
|
|
128
|
+
"get_last_assistant_text",
|
|
129
|
+
"get_messages",
|
|
130
|
+
"get_login_providers",
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
/** True when a command may bypass the ordered serial chain and run immediately. */
|
|
134
|
+
export function isFastLaneRpcCommand(type: RpcCommand["type"]): boolean {
|
|
135
|
+
return RPC_CANCELLATION_COMMANDS.has(type) || RPC_SAFE_READ_CONTROL_COMMANDS.has(type);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Schedules inbound RPC commands: fast-lane commands run immediately while
|
|
140
|
+
* everything else runs through a serial chain so causal order is preserved. The
|
|
141
|
+
* read loop never blocks, which is what lets a fast-lane command reach a
|
|
142
|
+
* long-running ordered command instead of being head-of-line-blocked behind it.
|
|
143
|
+
*/
|
|
144
|
+
export function createRpcCommandScheduler(
|
|
145
|
+
run: (command: RpcCommand) => Promise<void>,
|
|
146
|
+
track: (task: Promise<void>) => void,
|
|
147
|
+
): { dispatch: (command: RpcCommand) => void } {
|
|
148
|
+
let orderedChain: Promise<void> = Promise.resolve();
|
|
149
|
+
return {
|
|
150
|
+
dispatch(command: RpcCommand): void {
|
|
151
|
+
if (isFastLaneRpcCommand(command.type)) {
|
|
152
|
+
track(run(command));
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
orderedChain = orderedChain.then(() => run(command));
|
|
156
|
+
track(orderedChain);
|
|
157
|
+
},
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
85
161
|
function auditOutcomeFor(event: string): "accepted" | "rejected" | "denied" | "exceeded" | "aborted" | "info" {
|
|
86
162
|
if (event.includes("denied")) return "denied";
|
|
87
163
|
if (event.includes("exceeded")) return "exceeded";
|
|
@@ -91,6 +167,43 @@ function auditOutcomeFor(event: string): "accepted" | "rejected" | "denied" | "e
|
|
|
91
167
|
return "info";
|
|
92
168
|
}
|
|
93
169
|
|
|
170
|
+
export class RpcListenRefusedError extends Error {
|
|
171
|
+
constructor(socketPath: string) {
|
|
172
|
+
super(
|
|
173
|
+
`RPC --listen refused: a live server is already listening on ${socketPath}. ` +
|
|
174
|
+
"Stop it first or choose a different --listen path.",
|
|
175
|
+
);
|
|
176
|
+
this.name = "RpcListenRefusedError";
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Probe whether a unix-domain socket path has a live server accepting
|
|
182
|
+
* connections. Returns `true` when a connection succeeds (a previous owner is
|
|
183
|
+
* still alive), and returns `false` only for known missing/stale endpoints
|
|
184
|
+
* (ENOENT / ECONNREFUSED). Unexpected probe failures fail closed as "alive" so
|
|
185
|
+
* `--listen` startup refuses to unlink a path it could not safely classify.
|
|
186
|
+
*/
|
|
187
|
+
export async function isUnixSocketAlive(socketPath: string): Promise<boolean> {
|
|
188
|
+
try {
|
|
189
|
+
const socket = await Bun.connect({
|
|
190
|
+
unix: socketPath,
|
|
191
|
+
socket: { data() {}, open() {}, error() {}, close() {} },
|
|
192
|
+
});
|
|
193
|
+
socket.end();
|
|
194
|
+
return true;
|
|
195
|
+
} catch (err) {
|
|
196
|
+
const code = err && typeof err === "object" ? (err as { code?: unknown }).code : undefined;
|
|
197
|
+
if (code === "ENOENT" || code === "ECONNREFUSED") return false;
|
|
198
|
+
logger.warn("RPC --listen socket probe failed closed", {
|
|
199
|
+
socketPath,
|
|
200
|
+
code: typeof code === "string" ? code : undefined,
|
|
201
|
+
error: err instanceof Error ? err.message : String(err),
|
|
202
|
+
});
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
94
207
|
export function requestRpcEditor(
|
|
95
208
|
pendingRequests: Map<string, PendingExtensionRequest>,
|
|
96
209
|
output: RpcOutput,
|
|
@@ -230,6 +343,7 @@ export async function runRpcMode(
|
|
|
230
343
|
emitFrame: gate => output(gate),
|
|
231
344
|
store: gateStore,
|
|
232
345
|
audit: recordAudit,
|
|
346
|
+
providerSupportsTokenCostMetrics: modelSupportsTokenCostMetrics(session.model),
|
|
233
347
|
getUsageSnapshot: () => {
|
|
234
348
|
const stats = session.getSessionStats();
|
|
235
349
|
return { tokens: stats.tokens.total, costUsd: stats.cost };
|
|
@@ -537,14 +651,13 @@ export async function runRpcMode(
|
|
|
537
651
|
unattendedControlPlane,
|
|
538
652
|
});
|
|
539
653
|
|
|
540
|
-
//
|
|
541
|
-
//
|
|
542
|
-
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
545
|
-
//
|
|
546
|
-
|
|
547
|
-
let orderedChain: Promise<void> = Promise.resolve();
|
|
654
|
+
// Fast-lane commands (cancellation + safe read/control, see
|
|
655
|
+
// isFastLaneRpcCommand) bypass the ordered serial chain and run immediately;
|
|
656
|
+
// everything else runs through a serial chain so causal order is preserved
|
|
657
|
+
// (e.g. an ordered `set_model` after `bash` still applies after the bash
|
|
658
|
+
// result) while the read loop itself never blocks — that is what lets a
|
|
659
|
+
// fast-lane command reach a long-running `bash`/`compact`/`handoff`/`login`
|
|
660
|
+
// instead of being head-of-line-blocked behind it (issue 13).
|
|
548
661
|
const runCommand = async (command: RpcCommand): Promise<void> => {
|
|
549
662
|
try {
|
|
550
663
|
output(await handleCommand(command));
|
|
@@ -556,14 +669,7 @@ export async function runRpcMode(
|
|
|
556
669
|
inFlightCommands.add(task);
|
|
557
670
|
void task.finally(() => inFlightCommands.delete(task));
|
|
558
671
|
};
|
|
559
|
-
const dispatchCommand = (
|
|
560
|
-
if (CANCELLATION_COMMANDS.has(command.type)) {
|
|
561
|
-
trackCommand(runCommand(command));
|
|
562
|
-
return;
|
|
563
|
-
}
|
|
564
|
-
orderedChain = orderedChain.then(() => runCommand(command));
|
|
565
|
-
trackCommand(orderedChain);
|
|
566
|
-
};
|
|
672
|
+
const { dispatch: dispatchCommand } = createRpcCommandScheduler(runCommand, trackCommand);
|
|
567
673
|
|
|
568
674
|
/**
|
|
569
675
|
* Check if shutdown was requested and perform shutdown if so.
|
|
@@ -620,6 +726,14 @@ export async function runRpcMode(
|
|
|
620
726
|
if (options?.listen) {
|
|
621
727
|
const socketPath = options.listen;
|
|
622
728
|
await fs.mkdir(path.dirname(socketPath), { recursive: true }).catch(() => {});
|
|
729
|
+
// Refuse to clobber a live previous owner: probe the path first and only
|
|
730
|
+
// unlink a stale endpoint. A second `--listen` on the same path must not
|
|
731
|
+
// remove the socket another running server is still serving (#606).
|
|
732
|
+
// Unexpected probe failures are treated as alive, so this also refuses
|
|
733
|
+
// rather than unlinking a socket path we could not safely classify.
|
|
734
|
+
if (await isUnixSocketAlive(socketPath)) {
|
|
735
|
+
throw new RpcListenRefusedError(socketPath);
|
|
736
|
+
}
|
|
623
737
|
await fs.rm(socketPath, { force: true }).catch(() => {});
|
|
624
738
|
await registerRpcSession({
|
|
625
739
|
sessionId: session.sessionId,
|
|
@@ -363,7 +363,10 @@ export async function dispatchRpcCommand(
|
|
|
363
363
|
}
|
|
364
364
|
|
|
365
365
|
case "get_messages": {
|
|
366
|
-
|
|
366
|
+
// Fast-lane read: snapshot the live array so a concurrent ordered
|
|
367
|
+
// turn/compaction mutating session.messages in place cannot make this
|
|
368
|
+
// response serialize a half-rewritten array (#606, issue 13).
|
|
369
|
+
return rpcSuccess(id, "get_messages", { messages: [...session.messages] });
|
|
367
370
|
}
|
|
368
371
|
|
|
369
372
|
case "get_login_providers": {
|
|
@@ -447,7 +450,7 @@ export async function dispatchRpcCommand(
|
|
|
447
450
|
|
|
448
451
|
default: {
|
|
449
452
|
const unknownCommand = command as { type: string };
|
|
450
|
-
return rpcError(
|
|
453
|
+
return rpcError(id, unknownCommand.type, `Unknown command: ${unknownCommand.type}`);
|
|
451
454
|
}
|
|
452
455
|
}
|
|
453
456
|
} catch (err) {
|
|
@@ -93,6 +93,9 @@ export class RpcHostToolBridge {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
setTools(tools: RpcHostToolDefinition[]): AgentTool[] {
|
|
96
|
+
if (tools.some(tool => tool.name === "ask")) {
|
|
97
|
+
throw new Error('RPC host tool "ask" is reserved and cannot be supplied by the host');
|
|
98
|
+
}
|
|
96
99
|
this.#definitions = new Map(tools.map(tool => [tool.name, tool]));
|
|
97
100
|
return tools.map(tool => new RpcHostToolAdapter(tool, this));
|
|
98
101
|
}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* Also implements the dispatch-facing {@link RpcUnattendedControlPlane} so the
|
|
15
15
|
* RPC server can route `negotiate_unattended` + `workflow_gate_response` here.
|
|
16
16
|
*/
|
|
17
|
+
import type { Model } from "@gajae-code/ai";
|
|
17
18
|
import type {
|
|
18
19
|
RpcCommand,
|
|
19
20
|
RpcUnattendedAccepted,
|
|
@@ -38,6 +39,20 @@ import { type GateStore, MemoryGateStore, type OpenGateInput, WorkflowGateBroker
|
|
|
38
39
|
*/
|
|
39
40
|
const CHARGED_COMMAND_TYPES = new Set<RpcCommand["type"]>(["bash", "prompt", "steer", "follow_up", "abort_and_prompt"]);
|
|
40
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Derive an explicit `providerSupportsTokenCostMetrics` capability from the
|
|
44
|
+
* active model so unattended negotiation fails closed when token/cost usage
|
|
45
|
+
* cannot be accounted for (#606). Callers that omit a model — or whose model is
|
|
46
|
+
* configured to suppress streaming usage (`compat.supportsUsageInStreaming:
|
|
47
|
+
* false`) — get `false`, which the controller refuses with
|
|
48
|
+
* `unsupported_budget_metric`.
|
|
49
|
+
*/
|
|
50
|
+
export function modelSupportsTokenCostMetrics(model: Model | undefined): boolean {
|
|
51
|
+
if (!model) return false;
|
|
52
|
+
const compat = model.compat as { supportsUsageInStreaming?: boolean } | undefined;
|
|
53
|
+
return compat?.supportsUsageInStreaming !== false;
|
|
54
|
+
}
|
|
55
|
+
|
|
41
56
|
/** Minimal surface a skill runtime / ask tool uses to emit a gate and await its answer. */
|
|
42
57
|
export interface WorkflowGateEmitter {
|
|
43
58
|
/** True only when unattended mode has been negotiated. */
|
|
@@ -92,7 +107,7 @@ export class UnattendedSessionControlPlane implements RpcUnattendedControlPlane,
|
|
|
92
107
|
this.#rejectAllPending(new Error(`unattended run aborted: ${reason}`));
|
|
93
108
|
},
|
|
94
109
|
},
|
|
95
|
-
providerSupportsTokenCostMetrics: this.opts.providerSupportsTokenCostMetrics
|
|
110
|
+
providerSupportsTokenCostMetrics: this.opts.providerSupportsTokenCostMetrics,
|
|
96
111
|
});
|
|
97
112
|
this.#controller = controller;
|
|
98
113
|
this.#broker = new WorkflowGateBroker(this.opts.runId, this.opts.store ?? new MemoryGateStore(), {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/can1357/gajae-code/main/packages/coding-agent/theme-schema.json",
|
|
3
|
+
"name": "claude-code",
|
|
4
|
+
"vars": {
|
|
5
|
+
"bg": "#1a1a1a",
|
|
6
|
+
"surface": "#373737",
|
|
7
|
+
"surfaceSubtle": "#2a2a2a",
|
|
8
|
+
"separator": "#505050",
|
|
9
|
+
"fg": "#ffffff",
|
|
10
|
+
"muted": "#888888",
|
|
11
|
+
"dim": "#666666",
|
|
12
|
+
"brandTerracotta": "#d77757",
|
|
13
|
+
"shimmerTerracotta": "#eb9f7f",
|
|
14
|
+
"toolPink": "#fd5db1",
|
|
15
|
+
"lavender": "#b1b9f9",
|
|
16
|
+
"autoAcceptPurple": "#af87ff",
|
|
17
|
+
"successGreen": "#4eba65",
|
|
18
|
+
"warningAmber": "#ffc107",
|
|
19
|
+
"errorSoftRed": "#ff6b80",
|
|
20
|
+
"diffAddedBg": "#225c2b",
|
|
21
|
+
"diffRemovedBg": "#7a2936",
|
|
22
|
+
"diffRemovedFg": "#ff8fa0"
|
|
23
|
+
},
|
|
24
|
+
"colors": {
|
|
25
|
+
"accent": "brandTerracotta",
|
|
26
|
+
"border": "separator",
|
|
27
|
+
"borderAccent": "toolPink",
|
|
28
|
+
"borderMuted": "dim",
|
|
29
|
+
"success": "successGreen",
|
|
30
|
+
"error": "errorSoftRed",
|
|
31
|
+
"warning": "warningAmber",
|
|
32
|
+
"muted": "muted",
|
|
33
|
+
"dim": "dim",
|
|
34
|
+
"text": "fg",
|
|
35
|
+
"thinkingText": "muted",
|
|
36
|
+
"selectedBg": "surface",
|
|
37
|
+
"userMessageBg": "surface",
|
|
38
|
+
"userMessageText": "fg",
|
|
39
|
+
"customMessageBg": "surfaceSubtle",
|
|
40
|
+
"customMessageText": "fg",
|
|
41
|
+
"customMessageLabel": "brandTerracotta",
|
|
42
|
+
"toolPendingBg": "surfaceSubtle",
|
|
43
|
+
"toolSuccessBg": "diffAddedBg",
|
|
44
|
+
"toolErrorBg": "diffRemovedBg",
|
|
45
|
+
"toolTitle": "fg",
|
|
46
|
+
"toolOutput": "muted",
|
|
47
|
+
"mdHeading": "brandTerracotta",
|
|
48
|
+
"mdLink": "lavender",
|
|
49
|
+
"mdLinkUrl": "muted",
|
|
50
|
+
"mdCode": "shimmerTerracotta",
|
|
51
|
+
"mdCodeBlock": "fg",
|
|
52
|
+
"mdCodeBlockBorder": "toolPink",
|
|
53
|
+
"mdQuote": "muted",
|
|
54
|
+
"mdQuoteBorder": "separator",
|
|
55
|
+
"mdHr": "dim",
|
|
56
|
+
"mdListBullet": "brandTerracotta",
|
|
57
|
+
"toolDiffAdded": "successGreen",
|
|
58
|
+
"toolDiffRemoved": "diffRemovedFg",
|
|
59
|
+
"toolDiffContext": "muted",
|
|
60
|
+
"syntaxComment": "muted",
|
|
61
|
+
"syntaxKeyword": "lavender",
|
|
62
|
+
"syntaxFunction": "shimmerTerracotta",
|
|
63
|
+
"syntaxVariable": "fg",
|
|
64
|
+
"syntaxString": "successGreen",
|
|
65
|
+
"syntaxNumber": "warningAmber",
|
|
66
|
+
"syntaxType": "autoAcceptPurple",
|
|
67
|
+
"syntaxOperator": "toolPink",
|
|
68
|
+
"syntaxPunctuation": "muted",
|
|
69
|
+
"thinkingOff": "dim",
|
|
70
|
+
"thinkingMinimal": "muted",
|
|
71
|
+
"thinkingLow": "shimmerTerracotta",
|
|
72
|
+
"thinkingMedium": "brandTerracotta",
|
|
73
|
+
"thinkingHigh": "toolPink",
|
|
74
|
+
"thinkingXhigh": "errorSoftRed",
|
|
75
|
+
"bashMode": "toolPink",
|
|
76
|
+
"pythonMode": "lavender",
|
|
77
|
+
"statusLineBg": "bg",
|
|
78
|
+
"statusLineSep": "separator",
|
|
79
|
+
"statusLineModel": "brandTerracotta",
|
|
80
|
+
"statusLinePath": "lavender",
|
|
81
|
+
"statusLineGitClean": "successGreen",
|
|
82
|
+
"statusLineGitDirty": "warningAmber",
|
|
83
|
+
"statusLineContext": "lavender",
|
|
84
|
+
"statusLineSpend": "warningAmber",
|
|
85
|
+
"statusLineStaged": "successGreen",
|
|
86
|
+
"statusLineDirty": "warningAmber",
|
|
87
|
+
"statusLineUntracked": "errorSoftRed",
|
|
88
|
+
"statusLineOutput": "fg",
|
|
89
|
+
"statusLineCost": "shimmerTerracotta",
|
|
90
|
+
"statusLineSubagents": "autoAcceptPurple"
|
|
91
|
+
},
|
|
92
|
+
"export": {
|
|
93
|
+
"pageBg": "#1a1a1a",
|
|
94
|
+
"cardBg": "#2a2a2a",
|
|
95
|
+
"infoBg": "#373737"
|
|
96
|
+
},
|
|
97
|
+
"symbols": {
|
|
98
|
+
"preset": "unicode"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/can1357/gajae-code/main/packages/coding-agent/theme-schema.json",
|
|
3
|
+
"name": "codex",
|
|
4
|
+
"vars": {
|
|
5
|
+
"bg": "#0f1115",
|
|
6
|
+
"surface": "#151922",
|
|
7
|
+
"surfaceBright": "#1c2230",
|
|
8
|
+
"selection": "#24313a",
|
|
9
|
+
"fg": "#d7d7d7",
|
|
10
|
+
"muted": "#8a8f98",
|
|
11
|
+
"dim": "#5f6670",
|
|
12
|
+
"borderNeutral": "#343a46",
|
|
13
|
+
"ansiCyan": "#00bcd4",
|
|
14
|
+
"cyanSoft": "#58d5e8",
|
|
15
|
+
"brandMagenta": "#c678dd",
|
|
16
|
+
"magentaSoft": "#d7a4e8",
|
|
17
|
+
"successGreen": "#4caf50",
|
|
18
|
+
"errorRed": "#ef5350",
|
|
19
|
+
"warningOrange": "#f59e0b",
|
|
20
|
+
"diffRemovalRed": "#d84a4a",
|
|
21
|
+
"toolSuccessBg": "#14241a",
|
|
22
|
+
"toolErrorBg": "#2a1718"
|
|
23
|
+
},
|
|
24
|
+
"colors": {
|
|
25
|
+
"accent": "ansiCyan",
|
|
26
|
+
"border": "borderNeutral",
|
|
27
|
+
"borderAccent": "ansiCyan",
|
|
28
|
+
"borderMuted": "dim",
|
|
29
|
+
"success": "successGreen",
|
|
30
|
+
"error": "errorRed",
|
|
31
|
+
"warning": "warningOrange",
|
|
32
|
+
"muted": "muted",
|
|
33
|
+
"dim": "dim",
|
|
34
|
+
"text": "fg",
|
|
35
|
+
"thinkingText": "muted",
|
|
36
|
+
"selectedBg": "selection",
|
|
37
|
+
"userMessageBg": "surface",
|
|
38
|
+
"userMessageText": "fg",
|
|
39
|
+
"customMessageBg": "surface",
|
|
40
|
+
"customMessageText": "fg",
|
|
41
|
+
"customMessageLabel": "brandMagenta",
|
|
42
|
+
"toolPendingBg": "surface",
|
|
43
|
+
"toolSuccessBg": "toolSuccessBg",
|
|
44
|
+
"toolErrorBg": "toolErrorBg",
|
|
45
|
+
"toolTitle": "fg",
|
|
46
|
+
"toolOutput": "muted",
|
|
47
|
+
"mdHeading": "brandMagenta",
|
|
48
|
+
"mdLink": "ansiCyan",
|
|
49
|
+
"mdLinkUrl": "muted",
|
|
50
|
+
"mdCode": "cyanSoft",
|
|
51
|
+
"mdCodeBlock": "fg",
|
|
52
|
+
"mdCodeBlockBorder": "borderNeutral",
|
|
53
|
+
"mdQuote": "muted",
|
|
54
|
+
"mdQuoteBorder": "borderNeutral",
|
|
55
|
+
"mdHr": "dim",
|
|
56
|
+
"mdListBullet": "ansiCyan",
|
|
57
|
+
"toolDiffAdded": "successGreen",
|
|
58
|
+
"toolDiffRemoved": "diffRemovalRed",
|
|
59
|
+
"toolDiffContext": "muted",
|
|
60
|
+
"syntaxComment": "dim",
|
|
61
|
+
"syntaxKeyword": "brandMagenta",
|
|
62
|
+
"syntaxFunction": "cyanSoft",
|
|
63
|
+
"syntaxVariable": "fg",
|
|
64
|
+
"syntaxString": "successGreen",
|
|
65
|
+
"syntaxNumber": "magentaSoft",
|
|
66
|
+
"syntaxType": "ansiCyan",
|
|
67
|
+
"syntaxOperator": "muted",
|
|
68
|
+
"syntaxPunctuation": "dim",
|
|
69
|
+
"thinkingOff": "dim",
|
|
70
|
+
"thinkingMinimal": "muted",
|
|
71
|
+
"thinkingLow": "cyanSoft",
|
|
72
|
+
"thinkingMedium": "ansiCyan",
|
|
73
|
+
"thinkingHigh": "brandMagenta",
|
|
74
|
+
"thinkingXhigh": "errorRed",
|
|
75
|
+
"bashMode": "ansiCyan",
|
|
76
|
+
"pythonMode": "brandMagenta",
|
|
77
|
+
"statusLineBg": "bg",
|
|
78
|
+
"statusLineSep": "dim",
|
|
79
|
+
"statusLineModel": "brandMagenta",
|
|
80
|
+
"statusLinePath": "cyanSoft",
|
|
81
|
+
"statusLineGitClean": "successGreen",
|
|
82
|
+
"statusLineGitDirty": "warningOrange",
|
|
83
|
+
"statusLineContext": "ansiCyan",
|
|
84
|
+
"statusLineSpend": "cyanSoft",
|
|
85
|
+
"statusLineStaged": "successGreen",
|
|
86
|
+
"statusLineDirty": "warningOrange",
|
|
87
|
+
"statusLineUntracked": "diffRemovalRed",
|
|
88
|
+
"statusLineOutput": "fg",
|
|
89
|
+
"statusLineCost": "muted",
|
|
90
|
+
"statusLineSubagents": "brandMagenta"
|
|
91
|
+
},
|
|
92
|
+
"export": {
|
|
93
|
+
"pageBg": "#0f1115",
|
|
94
|
+
"cardBg": "#151922",
|
|
95
|
+
"infoBg": "#1c2230"
|
|
96
|
+
},
|
|
97
|
+
"symbols": {
|
|
98
|
+
"preset": "unicode"
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import blue_crab from "./blue-crab.json" with { type: "json" };
|
|
2
|
+
import claude_code from "./claude-code.json" with { type: "json" };
|
|
3
|
+
import codex from "./codex.json" with { type: "json" };
|
|
4
|
+
import opencode from "./opencode.json" with { type: "json" };
|
|
2
5
|
import red_claw from "./red-claw.json" with { type: "json" };
|
|
3
6
|
|
|
4
7
|
export const defaultThemes = {
|
|
5
8
|
"blue-crab": blue_crab,
|
|
9
|
+
"claude-code": claude_code,
|
|
10
|
+
codex,
|
|
11
|
+
opencode,
|
|
6
12
|
"red-claw": red_claw,
|
|
7
13
|
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/can1357/gajae-code/main/packages/coding-agent/theme-schema.json",
|
|
3
|
+
"name": "opencode",
|
|
4
|
+
"vars": {
|
|
5
|
+
"background": "#212121",
|
|
6
|
+
"currentLine": "#252525",
|
|
7
|
+
"selection": "#303030",
|
|
8
|
+
"backgroundDarker": "#121212",
|
|
9
|
+
"foreground": "#e0e0e0",
|
|
10
|
+
"comment": "#6a6a6a",
|
|
11
|
+
"primary": "#fab283",
|
|
12
|
+
"secondary": "#5c9cf5",
|
|
13
|
+
"accentPurple": "#9d7cd8",
|
|
14
|
+
"errorRed": "#e06c75",
|
|
15
|
+
"warningOrange": "#f5a742",
|
|
16
|
+
"successGreen": "#7fd88f",
|
|
17
|
+
"infoCyan": "#56b6c2",
|
|
18
|
+
"emphasizedYellow": "#e5c07b",
|
|
19
|
+
"border": "#4b4c5c",
|
|
20
|
+
"diffAdded": "#478247",
|
|
21
|
+
"diffRemoved": "#7c4444",
|
|
22
|
+
"diffContext": "#a0a0a0",
|
|
23
|
+
"addedBg": "#303a30",
|
|
24
|
+
"removedBg": "#3a3030"
|
|
25
|
+
},
|
|
26
|
+
"colors": {
|
|
27
|
+
"accent": "primary",
|
|
28
|
+
"border": "border",
|
|
29
|
+
"borderAccent": "accentPurple",
|
|
30
|
+
"borderMuted": "comment",
|
|
31
|
+
"success": "successGreen",
|
|
32
|
+
"error": "errorRed",
|
|
33
|
+
"warning": "warningOrange",
|
|
34
|
+
"muted": "comment",
|
|
35
|
+
"dim": "comment",
|
|
36
|
+
"text": "foreground",
|
|
37
|
+
"thinkingText": "diffContext",
|
|
38
|
+
"selectedBg": "selection",
|
|
39
|
+
"userMessageBg": "currentLine",
|
|
40
|
+
"userMessageText": "foreground",
|
|
41
|
+
"customMessageBg": "currentLine",
|
|
42
|
+
"customMessageText": "foreground",
|
|
43
|
+
"customMessageLabel": "primary",
|
|
44
|
+
"toolPendingBg": "currentLine",
|
|
45
|
+
"toolSuccessBg": "addedBg",
|
|
46
|
+
"toolErrorBg": "removedBg",
|
|
47
|
+
"toolTitle": "foreground",
|
|
48
|
+
"toolOutput": "comment",
|
|
49
|
+
"mdHeading": "secondary",
|
|
50
|
+
"mdLink": "primary",
|
|
51
|
+
"mdLinkUrl": "infoCyan",
|
|
52
|
+
"mdCode": "successGreen",
|
|
53
|
+
"mdCodeBlock": "foreground",
|
|
54
|
+
"mdCodeBlockBorder": "border",
|
|
55
|
+
"mdQuote": "emphasizedYellow",
|
|
56
|
+
"mdQuoteBorder": "emphasizedYellow",
|
|
57
|
+
"mdHr": "comment",
|
|
58
|
+
"mdListBullet": "primary",
|
|
59
|
+
"toolDiffAdded": "diffAdded",
|
|
60
|
+
"toolDiffRemoved": "diffRemoved",
|
|
61
|
+
"toolDiffContext": "diffContext",
|
|
62
|
+
"syntaxComment": "comment",
|
|
63
|
+
"syntaxKeyword": "secondary",
|
|
64
|
+
"syntaxFunction": "primary",
|
|
65
|
+
"syntaxVariable": "errorRed",
|
|
66
|
+
"syntaxString": "successGreen",
|
|
67
|
+
"syntaxNumber": "accentPurple",
|
|
68
|
+
"syntaxType": "emphasizedYellow",
|
|
69
|
+
"syntaxOperator": "infoCyan",
|
|
70
|
+
"syntaxPunctuation": "foreground",
|
|
71
|
+
"thinkingOff": "comment",
|
|
72
|
+
"thinkingMinimal": "diffContext",
|
|
73
|
+
"thinkingLow": "infoCyan",
|
|
74
|
+
"thinkingMedium": "secondary",
|
|
75
|
+
"thinkingHigh": "accentPurple",
|
|
76
|
+
"thinkingXhigh": "errorRed",
|
|
77
|
+
"bashMode": "infoCyan",
|
|
78
|
+
"pythonMode": "accentPurple",
|
|
79
|
+
"statusLineBg": "backgroundDarker",
|
|
80
|
+
"statusLineSep": "border",
|
|
81
|
+
"statusLineModel": "primary",
|
|
82
|
+
"statusLinePath": "secondary",
|
|
83
|
+
"statusLineGitClean": "successGreen",
|
|
84
|
+
"statusLineGitDirty": "warningOrange",
|
|
85
|
+
"statusLineContext": "infoCyan",
|
|
86
|
+
"statusLineSpend": "emphasizedYellow",
|
|
87
|
+
"statusLineStaged": "diffAdded",
|
|
88
|
+
"statusLineDirty": "warningOrange",
|
|
89
|
+
"statusLineUntracked": "errorRed",
|
|
90
|
+
"statusLineOutput": "foreground",
|
|
91
|
+
"statusLineCost": "primary",
|
|
92
|
+
"statusLineSubagents": "accentPurple"
|
|
93
|
+
},
|
|
94
|
+
"export": {
|
|
95
|
+
"pageBg": "#121212",
|
|
96
|
+
"cardBg": "#212121",
|
|
97
|
+
"infoBg": "#252525"
|
|
98
|
+
},
|
|
99
|
+
"symbols": {
|
|
100
|
+
"preset": "unicode"
|
|
101
|
+
}
|
|
102
|
+
}
|
package/src/modes/theme/theme.ts
CHANGED
|
@@ -810,7 +810,7 @@ const colorValueSchema = z.union([
|
|
|
810
810
|
|
|
811
811
|
type ColorValue = z.infer<typeof colorValueSchema>;
|
|
812
812
|
|
|
813
|
-
const THEME_COLOR_KEYS = [
|
|
813
|
+
export const THEME_COLOR_KEYS = [
|
|
814
814
|
"accent",
|
|
815
815
|
"border",
|
|
816
816
|
"borderAccent",
|
|
@@ -1648,7 +1648,7 @@ async function loadThemeJson(name: string): Promise<ThemeJson> {
|
|
|
1648
1648
|
errorMessage += `\nMissing required color tokens:\n`;
|
|
1649
1649
|
errorMessage += missingColors.map(c => ` - ${c}`).join("\n");
|
|
1650
1650
|
errorMessage += `\n\nPlease add these colors to your theme's "colors" object.`;
|
|
1651
|
-
errorMessage += `\nSee the built-in themes
|
|
1651
|
+
errorMessage += `\nSee the built-in themes under src/modes/theme/defaults/ for reference values.`;
|
|
1652
1652
|
}
|
|
1653
1653
|
if (otherErrors.length > 0) {
|
|
1654
1654
|
errorMessage += `\n\nOther errors:\n${otherErrors.join("\n")}`;
|
package/src/modes/types.ts
CHANGED
|
@@ -109,7 +109,7 @@ export interface InteractiveModeContext {
|
|
|
109
109
|
retryLoader: Loader | undefined;
|
|
110
110
|
autoCompactionEscapeHandler?: () => void;
|
|
111
111
|
retryEscapeHandler?: () => void;
|
|
112
|
-
retryCountdownTimer?:
|
|
112
|
+
retryCountdownTimer?: NodeJS.Timeout;
|
|
113
113
|
unsubscribe?: () => void;
|
|
114
114
|
onInputCallback?: (input: SubmittedUserInput) => void;
|
|
115
115
|
optimisticUserMessageSignature: string | undefined;
|
|
@@ -706,13 +706,16 @@ export class UiHelpers {
|
|
|
706
706
|
|
|
707
707
|
/** Move pending bash components from pending area to chat */
|
|
708
708
|
flushPendingBashComponents(): void {
|
|
709
|
+
// Move (detach, not dispose) the live execution components from the pending
|
|
710
|
+
// area into the chat transcript — they are reused instances, so a disposing
|
|
711
|
+
// removeChild() would tear them down before re-adding.
|
|
709
712
|
for (const component of this.ctx.pendingBashComponents) {
|
|
710
|
-
this.ctx.pendingMessagesContainer.
|
|
713
|
+
this.ctx.pendingMessagesContainer.detachChild(component);
|
|
711
714
|
this.ctx.chatContainer.addChild(component);
|
|
712
715
|
}
|
|
713
716
|
this.ctx.pendingBashComponents = [];
|
|
714
717
|
for (const component of this.ctx.pendingPythonComponents) {
|
|
715
|
-
this.ctx.pendingMessagesContainer.
|
|
718
|
+
this.ctx.pendingMessagesContainer.detachChild(component);
|
|
716
719
|
this.ctx.chatContainer.addChild(component);
|
|
717
720
|
}
|
|
718
721
|
this.ctx.pendingPythonComponents = [];
|
|
@@ -36,10 +36,13 @@ This mode activates only when the assignment explicitly labels Executor as Ultra
|
|
|
36
36
|
|
|
37
37
|
When active:
|
|
38
38
|
- Start from the approved plan/spec/acceptance criteria, then user-facing contracts, then implementation code only as supporting evidence. Treat plan/code mismatches as blockers.
|
|
39
|
-
- Exercise the real user-facing invocation rather than inspecting internals alone: GUI/web
|
|
39
|
+
- Exercise the real user-facing invocation rather than inspecting internals alone. Live artifacts must be runtime-valid: GUI/web needs a real automation transcript plus non-uniform screenshot; CLI needs executed argv-only replay; native/desktop/TUI needs a real screenshot, PTY capture with control codes, or app-automation transcript. `inlineEvidence` is supplemental only and is never sole proof for live surfaces.
|
|
40
|
+
- For CLI evidence, emit argv-only replay JSON with `schemaVersion: 1`, `kind: "cli-replay"`, `replaySafe: true`, and `command` as a string array. Use only allowlisted deterministic executables/arguments, or mark unsafe/non-deterministic commands with audited `replayExempt` metadata plus a valid structural fallback artifact.
|
|
41
|
+
- Native/TUI evidence must be structural, not prose-only: screenshot, app transcript, or PTY artifact with terminal control codes.
|
|
42
|
+
- Do not call the `ask` tool while an Ultragoal run is active; record unresolved decisions with `gjc ultragoal record-review-blockers`.
|
|
40
43
|
- Try to break the work with adversarial cases, not just happy-path confirmations.
|
|
41
44
|
- Report the QA matrix with the final field names `executorQa.contractCoverage`, `executorQa.surfaceEvidence`, `executorQa.adversarialCases`, and `executorQa.artifactRefs`.
|
|
42
|
-
- Include artifact refs for every executed surface and adversarial case: transcript ids, log paths, screenshots, image verdicts, test outputs, or other durable evidence.
|
|
45
|
+
- Include artifact refs for every executed surface and adversarial case: transcript ids, log paths, screenshots, image verdicts, CLI replay records, PTY captures, test outputs, or other durable evidence.
|
|
43
46
|
- Use `status: "not_applicable"` only for rows in `executorQa.contractCoverage` and `executorQa.surfaceEvidence`; each not-applicable row requires `contractRef` plus `reason`. `executorQa.adversarialCases` rows cannot be not-applicable.
|
|
44
47
|
- Report blockers for any missing plan/spec/acceptance source, contract ambiguity, plan/code mismatch, untestable surface, failed adversarial case, shallow evidence, or missing artifact ref.
|
|
45
48
|
</ultragoal_red_team_mode>
|