@gajae-code/coding-agent 0.5.0 → 0.5.2
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 +36 -0
- package/README.md +1 -1
- package/dist/types/async/job-manager.d.ts +26 -0
- package/dist/types/cli/args.d.ts +1 -0
- package/dist/types/cli/list-models.d.ts +6 -0
- package/dist/types/cli/setup-cli.d.ts +8 -1
- package/dist/types/commands/gc.d.ts +26 -0
- package/dist/types/commands/setup.d.ts +7 -0
- package/dist/types/config/file-lock-gc.d.ts +5 -0
- package/dist/types/config/file-lock.d.ts +29 -0
- 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/coordinator/contract.d.ts +1 -1
- package/dist/types/defaults/gjc/extensions/grok-build/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/index.d.ts +1 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.d.ts +25 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.d.ts +27 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.d.ts +8 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.d.ts +5 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.d.ts +10 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.d.ts +2 -0
- package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.d.ts +38 -0
- package/dist/types/defaults/gjc-grok-cli.d.ts +5 -0
- package/dist/types/extensibility/extensions/index.d.ts +1 -0
- package/dist/types/extensibility/extensions/prefix-command-bridge.d.ts +35 -0
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +103 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +112 -0
- package/dist/types/gjc-runtime/gc-render.d.ts +6 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +134 -0
- package/dist/types/gjc-runtime/ledger-event-renderer.d.ts +68 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +64 -2
- package/dist/types/gjc-runtime/team-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +5 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +11 -0
- package/dist/types/gjc-runtime/tmux-gc.d.ts +7 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +13 -0
- 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/harness-control-plane/gc-adapter.d.ts +3 -0
- package/dist/types/harness-control-plane/owner.d.ts +7 -0
- package/dist/types/harness-control-plane/storage.d.ts +20 -0
- package/dist/types/modes/components/hook-selector.d.ts +7 -1
- package/dist/types/modes/components/provider-onboarding-selector.d.ts +1 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/rpc/rpc-mode.d.ts +72 -2
- package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +13 -0
- package/dist/types/modes/shared/agent-wire/session-registry.d.ts +25 -0
- package/dist/types/modes/shared/agent-wire/unattended-action-policy.d.ts +2 -0
- 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/session/agent-session.d.ts +1 -1
- package/dist/types/session/blob-store.d.ts +39 -3
- package/dist/types/session/history-storage.d.ts +2 -2
- package/dist/types/session/session-manager.d.ts +10 -1
- package/dist/types/setup/credential-import.d.ts +79 -0
- package/dist/types/skill-state/workflow-hud.d.ts +14 -0
- package/dist/types/task/executor.d.ts +1 -0
- package/dist/types/task/render.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +15 -1
- package/dist/types/tools/subagent-render.d.ts +7 -1
- package/dist/types/tools/subagent.d.ts +27 -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 +52 -0
- package/src/cli/args.ts +5 -0
- package/src/cli/auth-broker-cli.ts +1 -0
- package/src/cli/fast-help.ts +2 -0
- package/src/cli/list-models.ts +13 -1
- package/src/cli/setup-cli.ts +138 -3
- package/src/cli.ts +1 -0
- package/src/commands/gc.ts +22 -0
- package/src/commands/harness.ts +7 -3
- package/src/commands/setup.ts +5 -1
- package/src/commands/ultragoal.ts +3 -1
- package/src/config/file-lock-gc.ts +193 -0
- package/src/config/file-lock.ts +66 -10
- package/src/config/model-profile-activation.ts +15 -3
- package/src/config/model-profiles.ts +39 -30
- 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/coordinator/contract.ts +1 -0
- package/src/coordinator-mcp/server.ts +459 -3
- package/src/defaults/gjc/agent.models.grok-cli.yml +36 -0
- package/src/defaults/gjc/extensions/grok-build/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-build/package.json +7 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/biome.json +39 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/package.json +8 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/index.ts +1 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +155 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.ts +361 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/billing.ts +57 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +99 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/stream.ts +50 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/usage.ts +56 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +36 -0
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/errors.ts +44 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +131 -113
- package/src/defaults/gjc/skills/deep-interview/lateral-review-panel.md +49 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +30 -8
- package/src/defaults/gjc-defaults.ts +7 -0
- package/src/defaults/gjc-grok-cli.ts +22 -0
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/prefix-command-bridge.ts +128 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +457 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +18 -26
- package/src/gjc-runtime/deep-interview-state.ts +324 -0
- package/src/gjc-runtime/gc-render.ts +70 -0
- package/src/gjc-runtime/gc-runtime.ts +403 -0
- package/src/gjc-runtime/launch-tmux.ts +3 -4
- package/src/gjc-runtime/ledger-event-renderer.ts +164 -0
- package/src/gjc-runtime/ralplan-runtime.ts +232 -19
- package/src/gjc-runtime/state-renderer.ts +12 -3
- package/src/gjc-runtime/state-runtime.ts +48 -30
- package/src/gjc-runtime/state-writer.ts +254 -7
- package/src/gjc-runtime/team-gc.ts +49 -0
- package/src/gjc-runtime/team-runtime.ts +179 -2
- package/src/gjc-runtime/tmux-common.ts +14 -0
- package/src/gjc-runtime/tmux-gc.ts +177 -0
- package/src/gjc-runtime/tmux-sessions.ts +49 -1
- package/src/gjc-runtime/ultragoal-guard.ts +155 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +1239 -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/gc-adapter.ts +184 -0
- package/src/harness-control-plane/owner.ts +14 -2
- package/src/harness-control-plane/rpc-adapter.ts +1 -1
- package/src/harness-control-plane/storage.ts +70 -0
- package/src/hooks/skill-state.ts +121 -2
- package/src/internal-urls/docs-index.generated.ts +22 -12
- package/src/lsp/defaults.json +1 -0
- package/src/main.ts +18 -3
- package/src/modes/acp/acp-agent.ts +4 -2
- package/src/modes/bridge/bridge-mode.ts +2 -1
- package/src/modes/components/history-search.ts +5 -2
- package/src/modes/components/hook-selector.ts +19 -0
- package/src/modes/components/model-selector.ts +51 -8
- package/src/modes/components/provider-onboarding-selector.ts +6 -1
- package/src/modes/components/status-line/segments.ts +1 -1
- package/src/modes/controllers/command-controller.ts +25 -6
- package/src/modes/controllers/extension-ui-controller.ts +3 -0
- package/src/modes/controllers/selector-controller.ts +81 -1
- package/src/modes/interactive-mode.ts +11 -1
- package/src/modes/rpc/rpc-mode.ts +266 -34
- package/src/modes/shared/agent-wire/command-dispatch.ts +281 -261
- package/src/modes/shared/agent-wire/deep-interview-gate.ts +30 -1
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +3 -0
- package/src/modes/shared/agent-wire/session-registry.ts +109 -0
- package/src/modes/shared/agent-wire/unattended-action-policy.ts +24 -0
- package/src/modes/shared/agent-wire/unattended-run-controller.ts +23 -3
- package/src/modes/shared/agent-wire/unattended-session.ts +32 -2
- 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/prompts/agents/executor.md +5 -2
- package/src/sdk.ts +29 -4
- package/src/session/agent-session.ts +99 -19
- package/src/session/blob-store.ts +59 -3
- package/src/session/history-storage.ts +32 -11
- package/src/session/session-manager.ts +72 -20
- package/src/setup/credential-import.ts +429 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +7 -1
- package/src/skill-state/deep-interview-mutation-guard.ts +2 -1
- package/src/skill-state/workflow-hud.ts +106 -10
- package/src/slash-commands/builtin-registry.ts +3 -2
- package/src/task/executor.ts +16 -1
- package/src/task/render.ts +18 -7
- package/src/tools/ask.ts +59 -2
- package/src/tools/cron.ts +1 -1
- package/src/tools/job.ts +3 -2
- package/src/tools/monitor.ts +36 -1
- package/src/tools/subagent-render.ts +128 -29
- package/src/tools/subagent.ts +173 -9
- 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
|
@@ -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
|
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-process registry of running gjc RPC sessions (issue 10).
|
|
3
|
+
*
|
|
4
|
+
* Each live RPC server writes a record under `<agent-dir>/rpc-sessions/<id>.json`
|
|
5
|
+
* on start and removes it on shutdown, so a separate process can discover which
|
|
6
|
+
* sessions are alive (and, once persistence lands in issue 09, how to reach
|
|
7
|
+
* them). Listing reaps records whose owning process is no longer alive, so a
|
|
8
|
+
* crashed server never leaves a permanent phantom entry.
|
|
9
|
+
*/
|
|
10
|
+
import * as fs from "node:fs/promises";
|
|
11
|
+
import * as path from "node:path";
|
|
12
|
+
import { getAgentDir } from "@gajae-code/utils";
|
|
13
|
+
|
|
14
|
+
export type RpcSessionTransport = "stdio" | "bridge" | "socket";
|
|
15
|
+
|
|
16
|
+
export interface RpcSessionRecord {
|
|
17
|
+
sessionId: string;
|
|
18
|
+
pid: number;
|
|
19
|
+
transport: RpcSessionTransport;
|
|
20
|
+
cwd: string;
|
|
21
|
+
model?: string;
|
|
22
|
+
/** ISO-8601 start timestamp. */
|
|
23
|
+
startedAt: string;
|
|
24
|
+
/** Reachable endpoint for persistent transports (issue 09); absent for stdio. */
|
|
25
|
+
endpoint?: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Registry directory: `<agent-dir>/rpc-sessions` (honors GJC_CODING_AGENT_DIR via getAgentDir). */
|
|
29
|
+
function rpcSessionsDir(agentDir?: string): string {
|
|
30
|
+
return path.join(agentDir ?? getAgentDir(), "rpc-sessions");
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function recordPath(sessionId: string, agentDir?: string): string {
|
|
34
|
+
return path.join(rpcSessionsDir(agentDir), `${sessionId}.json`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Write (or replace) the registry record for a session. The record is written to
|
|
39
|
+
* a same-directory temp file and atomically renamed into place so a concurrent
|
|
40
|
+
* reader never observes (and reaps) a partially-written record.
|
|
41
|
+
*/
|
|
42
|
+
export async function registerRpcSession(record: RpcSessionRecord, agentDir?: string): Promise<string> {
|
|
43
|
+
const file = recordPath(record.sessionId, agentDir);
|
|
44
|
+
// `.tmp` suffix keeps the staging file out of the `*.json` listing/reaping path.
|
|
45
|
+
const staging = `${file}.${process.pid}.tmp`;
|
|
46
|
+
await Bun.write(staging, JSON.stringify(record));
|
|
47
|
+
await fs.rename(staging, file);
|
|
48
|
+
return file;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Remove a session's registry record. Best-effort: a missing file is not an error. */
|
|
52
|
+
export async function unregisterRpcSession(sessionId: string, agentDir?: string): Promise<void> {
|
|
53
|
+
await fs.rm(recordPath(sessionId, agentDir), { force: true });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function isProcessAlive(pid: number): boolean {
|
|
57
|
+
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
58
|
+
try {
|
|
59
|
+
// Signal 0 performs error checking without delivering a signal.
|
|
60
|
+
process.kill(pid, 0);
|
|
61
|
+
return true;
|
|
62
|
+
} catch (err) {
|
|
63
|
+
// ESRCH => no such process (dead). EPERM => alive but owned by another user.
|
|
64
|
+
return (err as NodeJS.ErrnoException).code === "EPERM";
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function parseRecord(raw: string): RpcSessionRecord | undefined {
|
|
69
|
+
let obj: Partial<RpcSessionRecord>;
|
|
70
|
+
try {
|
|
71
|
+
obj = JSON.parse(raw) as Partial<RpcSessionRecord>;
|
|
72
|
+
} catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
if (typeof obj.sessionId !== "string" || typeof obj.pid !== "number") return undefined;
|
|
76
|
+
return obj as RpcSessionRecord;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* List live RPC sessions, reaping records whose process is gone or whose file is
|
|
81
|
+
* unparseable. Returns records sorted by `startedAt` ascending.
|
|
82
|
+
*/
|
|
83
|
+
export async function listRpcSessions(agentDir?: string): Promise<RpcSessionRecord[]> {
|
|
84
|
+
const dir = rpcSessionsDir(agentDir);
|
|
85
|
+
let entries: string[];
|
|
86
|
+
try {
|
|
87
|
+
entries = await fs.readdir(dir);
|
|
88
|
+
} catch {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const live: RpcSessionRecord[] = [];
|
|
92
|
+
for (const entry of entries) {
|
|
93
|
+
if (!entry.endsWith(".json")) continue;
|
|
94
|
+
const file = path.join(dir, entry);
|
|
95
|
+
let raw: string;
|
|
96
|
+
try {
|
|
97
|
+
raw = await fs.readFile(file, "utf8");
|
|
98
|
+
} catch {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const record = parseRecord(raw);
|
|
102
|
+
if (!record || !isProcessAlive(record.pid)) {
|
|
103
|
+
await fs.rm(file, { force: true });
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
live.push(record);
|
|
107
|
+
}
|
|
108
|
+
return live.sort((a, b) => a.startedAt.localeCompare(b.startedAt));
|
|
109
|
+
}
|
|
@@ -45,6 +45,30 @@ export function actionClassForScope(scope: BridgeCommandScope): RpcUnattendedAct
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/** Runtime list of every v1 action class — membership-validation source for negotiate (#319). */
|
|
49
|
+
export const RPC_UNATTENDED_ACTION_CLASSES: readonly RpcUnattendedActionClass[] = [
|
|
50
|
+
"command.prompt",
|
|
51
|
+
"command.control",
|
|
52
|
+
"command.bash",
|
|
53
|
+
"command.export",
|
|
54
|
+
"command.session",
|
|
55
|
+
"command.model",
|
|
56
|
+
"command.message_read",
|
|
57
|
+
"command.host_tools",
|
|
58
|
+
"command.host_uri",
|
|
59
|
+
"command.admin",
|
|
60
|
+
"bash.readonly",
|
|
61
|
+
"bash.mutating",
|
|
62
|
+
"bash.destructive",
|
|
63
|
+
"git.force_push",
|
|
64
|
+
"file.delete",
|
|
65
|
+
"file.write",
|
|
66
|
+
"host_tool.invoke",
|
|
67
|
+
"host_uri.read",
|
|
68
|
+
"host_uri.write",
|
|
69
|
+
"auth.login",
|
|
70
|
+
];
|
|
71
|
+
|
|
48
72
|
const READONLY_COMMANDS = new Set([
|
|
49
73
|
"ls",
|
|
50
74
|
"cat",
|
|
@@ -24,7 +24,8 @@ import type {
|
|
|
24
24
|
RpcUnattendedRefusalCode,
|
|
25
25
|
} from "../../rpc/rpc-types";
|
|
26
26
|
import type { BridgeCommandScope } from "./scopes";
|
|
27
|
-
import {
|
|
27
|
+
import { BRIDGE_COMMAND_SCOPES, MANDATORY_FLOOR_COMMAND_SCOPES } from "./scopes";
|
|
28
|
+
import { actionClassForScope, classifyBashAction, RPC_UNATTENDED_ACTION_CLASSES } from "./unattended-action-policy";
|
|
28
29
|
|
|
29
30
|
/** Coordinated abort surfaces invoked exactly once on a budget breach / abort. */
|
|
30
31
|
export interface UnattendedAbortHooks {
|
|
@@ -157,8 +158,11 @@ export class UnattendedRunController {
|
|
|
157
158
|
this.sessionId = ctx.sessionId;
|
|
158
159
|
this.actor = declaration.actor;
|
|
159
160
|
this.budget = budget;
|
|
160
|
-
this.scopes = new Set(declaration.scopes);
|
|
161
|
-
this.actionAllowlist = new Set(
|
|
161
|
+
this.scopes = new Set([...declaration.scopes, ...MANDATORY_FLOOR_COMMAND_SCOPES]);
|
|
162
|
+
this.actionAllowlist = new Set([
|
|
163
|
+
...declaration.action_allowlist,
|
|
164
|
+
...MANDATORY_FLOOR_COMMAND_SCOPES.map(actionClassForScope),
|
|
165
|
+
]);
|
|
162
166
|
this.now = ctx.now ?? Date.now;
|
|
163
167
|
this.audit = ctx.audit;
|
|
164
168
|
this.abortHooks = ctx.abortHooks ?? {};
|
|
@@ -183,6 +187,22 @@ export class UnattendedRunController {
|
|
|
183
187
|
"declaration.action_allowlist must be string[]",
|
|
184
188
|
);
|
|
185
189
|
}
|
|
190
|
+
const unknownScopes = d.scopes.filter(scope => !BRIDGE_COMMAND_SCOPES.includes(scope as BridgeCommandScope));
|
|
191
|
+
if (unknownScopes.length > 0) {
|
|
192
|
+
throw new UnattendedNegotiationError(
|
|
193
|
+
"invalid_unattended_declaration",
|
|
194
|
+
`declaration.scopes contains unknown scope(s): ${unknownScopes.join(", ")}`,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
const unknownActions = d.action_allowlist.filter(
|
|
198
|
+
action => !RPC_UNATTENDED_ACTION_CLASSES.includes(action as RpcUnattendedActionClass),
|
|
199
|
+
);
|
|
200
|
+
if (unknownActions.length > 0) {
|
|
201
|
+
throw new UnattendedNegotiationError(
|
|
202
|
+
"invalid_unattended_declaration",
|
|
203
|
+
`declaration.action_allowlist contains unknown action class(es): ${unknownActions.join(", ")}`,
|
|
204
|
+
);
|
|
205
|
+
}
|
|
186
206
|
const budget = validateBudget(d.budget);
|
|
187
207
|
// Reject providers that cannot account for tokens/cost (fail-closed): require
|
|
188
208
|
// an explicit positive capability signal — omitted/unknown is refused too.
|
|
@@ -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,
|
|
@@ -31,6 +32,27 @@ import {
|
|
|
31
32
|
} from "./unattended-run-controller";
|
|
32
33
|
import { type GateStore, MemoryGateStore, type OpenGateInput, WorkflowGateBroker } from "./workflow-gate-broker";
|
|
33
34
|
|
|
35
|
+
/**
|
|
36
|
+
* RPC commands that perform agent/tool work and therefore consume one unit of the
|
|
37
|
+
* `max_tool_calls` budget. Read-only/control/cancellation commands are wall-time-bounded
|
|
38
|
+
* and scope-checked but must NOT charge the tool-call budget (issue 04).
|
|
39
|
+
*/
|
|
40
|
+
const CHARGED_COMMAND_TYPES = new Set<RpcCommand["type"]>(["bash", "prompt", "steer", "follow_up", "abort_and_prompt"]);
|
|
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
|
+
|
|
34
56
|
/** Minimal surface a skill runtime / ask tool uses to emit a gate and await its answer. */
|
|
35
57
|
export interface WorkflowGateEmitter {
|
|
36
58
|
/** True only when unattended mode has been negotiated. */
|
|
@@ -85,7 +107,7 @@ export class UnattendedSessionControlPlane implements RpcUnattendedControlPlane,
|
|
|
85
107
|
this.#rejectAllPending(new Error(`unattended run aborted: ${reason}`));
|
|
86
108
|
},
|
|
87
109
|
},
|
|
88
|
-
providerSupportsTokenCostMetrics: this.opts.providerSupportsTokenCostMetrics
|
|
110
|
+
providerSupportsTokenCostMetrics: this.opts.providerSupportsTokenCostMetrics,
|
|
89
111
|
});
|
|
90
112
|
this.#controller = controller;
|
|
91
113
|
this.#broker = new WorkflowGateBroker(this.opts.runId, this.opts.store ?? new MemoryGateStore(), {
|
|
@@ -116,7 +138,15 @@ export class UnattendedSessionControlPlane implements RpcUnattendedControlPlane,
|
|
|
116
138
|
|
|
117
139
|
preflightCommand(command: RpcCommand): void {
|
|
118
140
|
if (!this.#controller) return;
|
|
119
|
-
|
|
141
|
+
const phase = `${command.type} preflight`;
|
|
142
|
+
// Always enforce wall-time; only charge the tool-call budget for commands that perform
|
|
143
|
+
// agent/tool work (issue 04). Read-only/control/cancellation commands must not consume
|
|
144
|
+
// max_tool_calls, but remain wall-time-bounded and scope/action-checked.
|
|
145
|
+
if (CHARGED_COMMAND_TYPES.has(command.type)) {
|
|
146
|
+
this.#controller.preflightToolCall(phase);
|
|
147
|
+
} else {
|
|
148
|
+
this.#controller.checkWallTime(phase);
|
|
149
|
+
}
|
|
120
150
|
if (command.type === "bash") {
|
|
121
151
|
this.#controller.authorizeBash(command.command);
|
|
122
152
|
return;
|
|
@@ -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;
|
|
@@ -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>
|