@gajae-code/coding-agent 0.2.5 → 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 +28 -0
- package/dist/types/async/job-manager.d.ts +91 -2
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/commands/harness.d.ts +37 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +10 -4
- package/dist/types/config/settings.d.ts +2 -0
- 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 +6 -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/extensibility/custom-tools/types.d.ts +1 -0
- package/dist/types/extensibility/extensions/types.d.ts +6 -0
- package/dist/types/extensibility/shared-events.d.ts +1 -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-graph.d.ts +4 -0
- package/dist/types/gjc-runtime/state-migrations.d.ts +33 -0
- package/dist/types/gjc-runtime/state-renderer.d.ts +65 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
- package/dist/types/gjc-runtime/state-validation.d.ts +6 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +147 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +81 -7
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +54 -0
- package/dist/types/harness-control-plane/classifier.d.ts +13 -0
- package/dist/types/harness-control-plane/control-endpoint.d.ts +31 -0
- package/dist/types/harness-control-plane/finalize.d.ts +47 -0
- package/dist/types/harness-control-plane/frame-mapper.d.ts +29 -0
- package/dist/types/harness-control-plane/operate.d.ts +35 -0
- package/dist/types/harness-control-plane/owner.d.ts +46 -0
- package/dist/types/harness-control-plane/preserve.d.ts +19 -0
- package/dist/types/harness-control-plane/receipts.d.ts +88 -0
- package/dist/types/harness-control-plane/rpc-adapter.d.ts +66 -0
- package/dist/types/harness-control-plane/seams.d.ts +21 -0
- package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
- package/dist/types/harness-control-plane/state-machine.d.ts +19 -0
- package/dist/types/harness-control-plane/storage.d.ts +53 -0
- package/dist/types/harness-control-plane/types.d.ts +162 -0
- package/dist/types/hooks/skill-keywords.d.ts +2 -1
- package/dist/types/hooks/skill-state.d.ts +23 -29
- 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/hook-selector.d.ts +1 -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 +2 -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 +2 -0
- package/dist/types/sdk.d.ts +4 -0
- package/dist/types/session/agent-session.d.ts +19 -1
- package/dist/types/skill-state/active-state.d.ts +2 -0
- package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +1 -1
- package/dist/types/skill-state/workflow-state-contract.d.ts +25 -2
- package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
- package/dist/types/task/executor.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 +198 -14
- 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 +26 -1
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +334 -6
- package/src/cli/args.ts +9 -2
- package/src/cli/auth-broker-cli.ts +1 -0
- package/src/cli/config-cli.ts +10 -2
- package/src/cli.ts +2 -0
- package/src/commands/deep-interview.ts +1 -0
- package/src/commands/harness.ts +862 -0
- package/src/commands/launch.ts +2 -2
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +54 -39
- package/src/config/keybindings.ts +6 -0
- package/src/config/settings-schema.ts +13 -3
- package/src/config/settings.ts +5 -0
- 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 +372 -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/team/SKILL.md +47 -21
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +106 -13
- 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/extensibility/custom-tools/types.ts +1 -0
- package/src/extensibility/extensions/types.ts +6 -0
- package/src/extensibility/shared-events.ts +1 -0
- package/src/gjc-runtime/cli-write-receipt.ts +31 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +98 -42
- package/src/gjc-runtime/goal-mode-request.ts +11 -3
- package/src/gjc-runtime/ralplan-runtime.ts +235 -43
- package/src/gjc-runtime/state-graph.ts +86 -0
- package/src/gjc-runtime/state-migrations.ts +179 -0
- package/src/gjc-runtime/state-renderer.ts +345 -0
- package/src/gjc-runtime/state-runtime.ts +1155 -46
- package/src/gjc-runtime/state-schema.ts +192 -0
- package/src/gjc-runtime/state-validation.ts +49 -0
- package/src/gjc-runtime/state-writer.ts +749 -0
- package/src/gjc-runtime/team-runtime.ts +1255 -189
- package/src/gjc-runtime/ultragoal-runtime.ts +460 -43
- package/src/gjc-runtime/workflow-command-ref.ts +239 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +1601 -0
- package/src/gjc-runtime/workflow-manifest.ts +427 -0
- package/src/harness-control-plane/classifier.ts +128 -0
- package/src/harness-control-plane/control-endpoint.ts +148 -0
- package/src/harness-control-plane/finalize.ts +222 -0
- package/src/harness-control-plane/frame-mapper.ts +286 -0
- package/src/harness-control-plane/operate.ts +225 -0
- package/src/harness-control-plane/owner.ts +600 -0
- package/src/harness-control-plane/preserve.ts +102 -0
- package/src/harness-control-plane/receipts.ts +216 -0
- package/src/harness-control-plane/rpc-adapter.ts +276 -0
- package/src/harness-control-plane/seams.ts +39 -0
- package/src/harness-control-plane/session-lease.ts +388 -0
- package/src/harness-control-plane/state-machine.ts +98 -0
- package/src/harness-control-plane/storage.ts +257 -0
- package/src/harness-control-plane/types.ts +214 -0
- package/src/hooks/skill-keywords.ts +4 -2
- package/src/hooks/skill-state.ts +197 -64
- 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/assistant-message.ts +5 -1
- package/src/modes/components/custom-editor.ts +101 -0
- package/src/modes/components/hook-selector.ts +133 -20
- 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/event-controller.ts +71 -6
- package/src/modes/controllers/extension-ui-controller.ts +43 -1
- package/src/modes/controllers/input-controller.ts +105 -9
- package/src/modes/controllers/selector-controller.ts +31 -1
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +28 -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 +2 -0
- package/src/prompts/agents/executor.md +13 -0
- package/src/prompts/tools/subagent.md +39 -4
- package/src/prompts/tools/task-summary.md +3 -9
- package/src/prompts/tools/task.md +5 -1
- package/src/sdk.ts +8 -0
- package/src/session/agent-session.ts +445 -71
- package/src/session/session-manager.ts +13 -1
- package/src/skill-state/active-state.ts +58 -65
- package/src/skill-state/deep-interview-mutation-guard.ts +114 -17
- package/src/skill-state/initial-phase.ts +2 -0
- package/src/skill-state/workflow-state-contract.ts +33 -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 +79 -13
- package/src/task/id.ts +33 -0
- package/src/task/index.ts +376 -74
- package/src/task/output-manager.ts +5 -4
- package/src/task/receipt.ts +297 -0
- package/src/task/render.ts +54 -134
- package/src/task/spawn-gate.ts +132 -0
- package/src/task/types.ts +104 -10
- package/src/tools/ask.ts +88 -27
- 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 +423 -79
package/src/commands/launch.ts
CHANGED
|
@@ -52,8 +52,8 @@ export default class Index extends Command {
|
|
|
52
52
|
description: "Allow starting in ~ without auto-switching to a temp dir",
|
|
53
53
|
}),
|
|
54
54
|
mode: Flags.string({
|
|
55
|
-
description: "Output mode: text (default), json, rpc,
|
|
56
|
-
options: ["text", "json", "rpc", "acp", "rpc-ui"],
|
|
55
|
+
description: "Output mode: text (default), json, rpc, acp, rpc-ui, or bridge",
|
|
56
|
+
options: ["text", "json", "rpc", "acp", "rpc-ui", "bridge"],
|
|
57
57
|
}),
|
|
58
58
|
print: Flags.boolean({
|
|
59
59
|
char: "p",
|
package/src/commands/state.ts
CHANGED
|
@@ -9,9 +9,10 @@ export default class State extends Command {
|
|
|
9
9
|
'$ gjc state write --input \'{"state":{"interview_id":"abc"}}\' --mode deep-interview --json',
|
|
10
10
|
"$ gjc state clear --mode deep-interview",
|
|
11
11
|
"$ gjc state deep-interview read --json",
|
|
12
|
-
'$ gjc state ralplan write --input \'{"phase":"
|
|
12
|
+
'$ gjc state ralplan write --input \'{"phase":"planner","active":true}\' --json',
|
|
13
13
|
"$ gjc state team contract",
|
|
14
14
|
"$ gjc state deep-interview handoff --to ralplan --json",
|
|
15
|
+
"$ gjc state doctor --skill ralplan --json",
|
|
15
16
|
];
|
|
16
17
|
|
|
17
18
|
async run(): Promise<void> {
|
package/src/commands/team.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { Args, Command, Flags } from "@gajae-code/utils/cli";
|
|
2
|
+
import { renderCliWriteReceipt } from "../gjc-runtime/cli-write-receipt";
|
|
3
|
+
import { renderTeamStatusMarkdown } from "../gjc-runtime/state-renderer";
|
|
2
4
|
import {
|
|
3
5
|
buildTeamHudSummary,
|
|
4
6
|
executeGjcTeamApiOperation,
|
|
5
7
|
type GjcTeamSnapshot,
|
|
6
8
|
listGjcTeams,
|
|
7
|
-
|
|
9
|
+
monitorGjcTeamSnapshot,
|
|
8
10
|
parseTeamLaunchArgs,
|
|
11
|
+
persistGjcTeamModeStateSummary,
|
|
9
12
|
readGjcTeamEvents,
|
|
10
13
|
readGjcTeamSnapshot,
|
|
11
14
|
shutdownGjcTeam,
|
|
@@ -31,6 +34,7 @@ async function syncTeamHud(snapshot: GjcTeamSnapshot): Promise<void> {
|
|
|
31
34
|
hud: await buildTeamHudSummary(snapshot, events.at(-1)),
|
|
32
35
|
source: "gjc-team",
|
|
33
36
|
});
|
|
37
|
+
await persistGjcTeamModeStateSummary(snapshot, process.cwd());
|
|
34
38
|
} catch {
|
|
35
39
|
// HUD sync is best-effort and must not change command semantics.
|
|
36
40
|
}
|
|
@@ -42,27 +46,21 @@ function formatTaskCounts(counts: Record<string, number>): string {
|
|
|
42
46
|
.join(" ");
|
|
43
47
|
}
|
|
44
48
|
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
function snapshotWriteReceipt(snapshot: GjcTeamSnapshot): Record<string, unknown> {
|
|
50
|
+
return {
|
|
51
|
+
ok: true,
|
|
52
|
+
team_name: snapshot.team_name,
|
|
53
|
+
phase: snapshot.phase,
|
|
54
|
+
state_dir: snapshot.state_dir,
|
|
55
|
+
tmux_session: snapshot.tmux_session,
|
|
56
|
+
tmux_target: snapshot.tmux_target,
|
|
57
|
+
worker_count: snapshot.workers.length,
|
|
58
|
+
task_counts: snapshot.task_counts,
|
|
59
|
+
};
|
|
55
60
|
}
|
|
56
61
|
|
|
57
|
-
function
|
|
58
|
-
|
|
59
|
-
}): string[] {
|
|
60
|
-
const entries = Object.entries(snapshot.integration_by_worker ?? {});
|
|
61
|
-
if (entries.length === 0) return ["integration: no attempts recorded"];
|
|
62
|
-
return entries.map(([worker, state]) => {
|
|
63
|
-
const files = state.conflict_files?.length ? ` files=${state.conflict_files.join(",")}` : "";
|
|
64
|
-
return `integration: ${worker} ${state.status ?? "unknown"}${files}`;
|
|
65
|
-
});
|
|
62
|
+
function writeReceipt(value: Record<string, unknown>): void {
|
|
63
|
+
process.stdout.write(renderCliWriteReceipt(value));
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
function parseInputFlag(argv: string[]): Record<string, unknown> {
|
|
@@ -76,12 +74,13 @@ function parseInputFlag(argv: string[]): Record<string, unknown> {
|
|
|
76
74
|
}
|
|
77
75
|
|
|
78
76
|
export default class Team extends Command {
|
|
79
|
-
static description =
|
|
77
|
+
static description =
|
|
78
|
+
"Run native GJC tmux team orchestration from inside an existing tmux/GJC --tmux session; --dry-run writes ephemeral .gjc/state/team state only";
|
|
80
79
|
static strict = false;
|
|
81
80
|
|
|
82
81
|
static args = {
|
|
83
82
|
action: Args.string({
|
|
84
|
-
description: "start (default), status, list, shutdown, resume, or api",
|
|
83
|
+
description: "start (default), status, monitor, list, shutdown, resume, or api",
|
|
85
84
|
required: false,
|
|
86
85
|
}),
|
|
87
86
|
};
|
|
@@ -96,8 +95,10 @@ export default class Team extends Command {
|
|
|
96
95
|
};
|
|
97
96
|
|
|
98
97
|
static examples = [
|
|
98
|
+
"gjc --tmux # start/attach the required tmux-backed leader session first",
|
|
99
99
|
'gjc team 3:executor "Implement the approved plan"',
|
|
100
100
|
"gjc team status <team-name> --json",
|
|
101
|
+
"gjc team monitor <team-name> --json",
|
|
101
102
|
'gjc team api claim-task --input \'{"team_name":"demo","worker_id":"worker-1"}\' --json',
|
|
102
103
|
'gjc team 2:executor --dry-run --json "Preview state only"',
|
|
103
104
|
"gjc team shutdown <team-name>",
|
|
@@ -119,26 +120,36 @@ export default class Team extends Command {
|
|
|
119
120
|
return;
|
|
120
121
|
}
|
|
121
122
|
|
|
122
|
-
if (action === "status"
|
|
123
|
+
if (action === "status") {
|
|
123
124
|
const teamName = rest.find(arg => !arg.startsWith("--"));
|
|
124
125
|
if (!teamName) throw new Error("missing_team_name");
|
|
125
|
-
const snapshot = await
|
|
126
|
-
await syncTeamHud(snapshot);
|
|
126
|
+
const snapshot = await readGjcTeamSnapshot(teamName);
|
|
127
127
|
if (json) {
|
|
128
128
|
writeJson(snapshot);
|
|
129
129
|
return;
|
|
130
130
|
}
|
|
131
131
|
writeText([
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
`tmux: ${snapshot.tmux_target || snapshot.tmux_session}`,
|
|
135
|
-
`state: ${snapshot.state_dir}`,
|
|
136
|
-
`tasks: ${snapshot.task_total} (${formatTaskCounts(snapshot.task_counts)})`,
|
|
137
|
-
`workers: ${snapshot.workers.map(worker => `${worker.id}:${worker.status}`).join(" ")}`,
|
|
138
|
-
formatNotificationSummary(snapshot),
|
|
139
|
-
...formatAwaitingIntegrationNextStep(snapshot),
|
|
140
|
-
...formatIntegrationSummary(snapshot),
|
|
132
|
+
renderTeamStatusMarkdown(snapshot).trimEnd(),
|
|
133
|
+
"- mode: read-only status; use `gjc team monitor <team>` or `gjc team resume <team>` for recovery/integration",
|
|
141
134
|
]);
|
|
135
|
+
void formatTaskCounts(snapshot.task_counts);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (action === "monitor" || action === "resume") {
|
|
140
|
+
const teamName = rest.find(arg => !arg.startsWith("--"));
|
|
141
|
+
if (!teamName) throw new Error("missing_team_name");
|
|
142
|
+
const snapshot = await monitorGjcTeamSnapshot(teamName);
|
|
143
|
+
await syncTeamHud(snapshot);
|
|
144
|
+
if (json) {
|
|
145
|
+
writeReceipt(snapshotWriteReceipt(snapshot));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
writeText([
|
|
149
|
+
renderTeamStatusMarkdown(snapshot).trimEnd(),
|
|
150
|
+
"- mode: mutating monitor; liveness recovery and integration may have run",
|
|
151
|
+
]);
|
|
152
|
+
void formatTaskCounts(snapshot.task_counts);
|
|
142
153
|
return;
|
|
143
154
|
}
|
|
144
155
|
|
|
@@ -148,7 +159,7 @@ export default class Team extends Command {
|
|
|
148
159
|
const snapshot = await shutdownGjcTeam(teamName);
|
|
149
160
|
await syncTeamHud(snapshot);
|
|
150
161
|
if (json) {
|
|
151
|
-
|
|
162
|
+
writeReceipt(snapshotWriteReceipt(snapshot));
|
|
152
163
|
return;
|
|
153
164
|
}
|
|
154
165
|
writeText([`team: ${snapshot.team_name}`, `phase: ${snapshot.phase}`, `state: ${snapshot.state_dir}`]);
|
|
@@ -162,8 +173,12 @@ export default class Team extends Command {
|
|
|
162
173
|
"Supported operations:",
|
|
163
174
|
"send-message broadcast mailbox-list mailbox-mark-delivered mailbox-mark-notified notification-list notification-read notification-replay notification-mark-pane-attempt worker-startup-ack",
|
|
164
175
|
"create-task read-task list-tasks update-task claim-task transition-task-status release-task-claim",
|
|
165
|
-
"read-config read-manifest read-worker-status read-worker-heartbeat update-worker-heartbeat write-worker-inbox write-worker-identity",
|
|
166
|
-
"append-event read-events await-event write-shutdown-request read-shutdown-ack read-monitor-snapshot write-monitor-snapshot read-task-approval write-task-approval",
|
|
176
|
+
"read-config read-manifest read-worker-status update-worker-status read-worker-heartbeat recover-stale-claims update-worker-heartbeat write-worker-inbox write-worker-identity",
|
|
177
|
+
"append-event read-events read-traces await-event write-shutdown-request read-shutdown-ack read-monitor-snapshot write-monitor-snapshot read-task-approval write-task-approval",
|
|
178
|
+
"Completion example:",
|
|
179
|
+
'transition-task-status --input \'{"team_name":"demo","task_id":"task-1","to":"completed","claim_token":"...","completion_evidence":{"summary":"done","items":[{"kind":"command","status":"passed","summary":"focused tests passed","command":"bun test packages/coding-agent/test/gjc-runtime/team-runtime.test.ts"}]}}\' --json',
|
|
180
|
+
'Review-only completion may use {"kind":"inspection","status":"verified","summary":"review passed","location":"agent://review"}.',
|
|
181
|
+
'Typed lane task example: create-task --input \'{"team_name":"demo","subject":"Verify delivery","description":"Run verification","owner":"worker-1","lane":"verification","required_role":"executor","depends_on":["task-1"]}\' --json',
|
|
167
182
|
]);
|
|
168
183
|
return;
|
|
169
184
|
}
|
|
@@ -177,7 +192,7 @@ export default class Team extends Command {
|
|
|
177
192
|
// API operations without a resolvable snapshot leave HUD state unchanged.
|
|
178
193
|
}
|
|
179
194
|
}
|
|
180
|
-
|
|
195
|
+
writeReceipt(result as Record<string, unknown>);
|
|
181
196
|
return;
|
|
182
197
|
}
|
|
183
198
|
|
|
@@ -186,7 +201,7 @@ export default class Team extends Command {
|
|
|
186
201
|
const snapshot = await startGjcTeam({ ...options, dryRun });
|
|
187
202
|
await syncTeamHud(snapshot);
|
|
188
203
|
if (json) {
|
|
189
|
-
|
|
204
|
+
writeReceipt(snapshotWriteReceipt(snapshot));
|
|
190
205
|
return;
|
|
191
206
|
}
|
|
192
207
|
writeText([
|
|
@@ -38,6 +38,7 @@ interface AppKeybindings {
|
|
|
38
38
|
"app.session.fork": true;
|
|
39
39
|
"app.session.resume": true;
|
|
40
40
|
"app.session.observe": true;
|
|
41
|
+
"app.jobs.open": true;
|
|
41
42
|
"app.session.togglePath": true;
|
|
42
43
|
"app.session.toggleSort": true;
|
|
43
44
|
"app.session.rename": true;
|
|
@@ -149,6 +150,11 @@ export const KEYBINDINGS = {
|
|
|
149
150
|
defaultKeys: "ctrl+s",
|
|
150
151
|
description: "Observe subagent sessions",
|
|
151
152
|
},
|
|
153
|
+
|
|
154
|
+
"app.jobs.open": {
|
|
155
|
+
defaultKeys: "alt+j",
|
|
156
|
+
description: "Open monitor/cron jobs overlay",
|
|
157
|
+
},
|
|
152
158
|
"app.session.togglePath": {
|
|
153
159
|
defaultKeys: "ctrl+p",
|
|
154
160
|
description: "Toggle session path display",
|
|
@@ -74,6 +74,7 @@ export type StatusLineSegmentId =
|
|
|
74
74
|
| "git"
|
|
75
75
|
| "pr"
|
|
76
76
|
| "subagents"
|
|
77
|
+
| "jobs"
|
|
77
78
|
| "token_in"
|
|
78
79
|
| "token_out"
|
|
79
80
|
| "token_total"
|
|
@@ -147,6 +148,7 @@ interface StringDef {
|
|
|
147
148
|
interface NumberDef {
|
|
148
149
|
type: "number";
|
|
149
150
|
default: number;
|
|
151
|
+
validate?: (value: number) => boolean;
|
|
150
152
|
ui?: UiNumber;
|
|
151
153
|
}
|
|
152
154
|
|
|
@@ -319,6 +321,12 @@ export const SETTINGS_SCHEMA = {
|
|
|
319
321
|
|
|
320
322
|
cycleOrder: { type: "array", default: DEFAULT_CYCLE_ORDER },
|
|
321
323
|
|
|
324
|
+
"gjc.deepInterview.ambiguityThreshold": {
|
|
325
|
+
type: "number",
|
|
326
|
+
default: 0.05,
|
|
327
|
+
validate: (value: number) => Number.isFinite(value) && value > 0 && value <= 1,
|
|
328
|
+
},
|
|
329
|
+
|
|
322
330
|
// ────────────────────────────────────────────────────────────────────────
|
|
323
331
|
// Appearance
|
|
324
332
|
// ────────────────────────────────────────────────────────────────────────
|
|
@@ -2345,11 +2353,12 @@ export const SETTINGS_SCHEMA = {
|
|
|
2345
2353
|
|
|
2346
2354
|
"task.maxConcurrency": {
|
|
2347
2355
|
type: "number",
|
|
2348
|
-
default:
|
|
2356
|
+
default: 8,
|
|
2349
2357
|
ui: {
|
|
2350
2358
|
tab: "tasks",
|
|
2351
2359
|
label: "Max Concurrent Tasks",
|
|
2352
|
-
description:
|
|
2360
|
+
description:
|
|
2361
|
+
"Safer concurrent limit for subagents; higher fan-out still requires an explicit plan above 4 tasks.",
|
|
2353
2362
|
options: [
|
|
2354
2363
|
{ value: "0", label: "Unlimited" },
|
|
2355
2364
|
{ value: "1", label: "1 task" },
|
|
@@ -2401,7 +2410,8 @@ export const SETTINGS_SCHEMA = {
|
|
|
2401
2410
|
ui: {
|
|
2402
2411
|
tab: "tasks",
|
|
2403
2412
|
label: "Fork Context Max Tokens",
|
|
2404
|
-
description:
|
|
2413
|
+
description:
|
|
2414
|
+
"Approximate token cap for explicit full fork-context seeds. 0 uses 15% of the target model context window, with a 15k fallback when the window is unknown.",
|
|
2405
2415
|
},
|
|
2406
2416
|
},
|
|
2407
2417
|
|
package/src/config/settings.ts
CHANGED
|
@@ -297,6 +297,11 @@ export class Settings {
|
|
|
297
297
|
return getDefault(path);
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
+
/** Check whether a setting is present in loaded settings/overrides rather than coming from schema defaults. */
|
|
301
|
+
has(path: SettingPath): boolean {
|
|
302
|
+
return getByPath(this.#merged, path.split(".")) !== undefined;
|
|
303
|
+
}
|
|
304
|
+
|
|
300
305
|
/**
|
|
301
306
|
* Set a setting value (sync).
|
|
302
307
|
* Updates global settings and queues a background save.
|
package/src/dap/client.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { logger, ptree } from "@gajae-code/utils";
|
|
2
|
+
import { formatCrashDiagnosticNotice, writeCrashReport } from "../debug/crash-diagnostics";
|
|
2
3
|
import { NON_INTERACTIVE_ENV } from "../exec/non-interactive-env";
|
|
3
4
|
import { ToolAbortError } from "../tools/tool-errors";
|
|
4
5
|
import type {
|
|
@@ -532,15 +533,28 @@ export class DapClient {
|
|
|
532
533
|
}
|
|
533
534
|
}
|
|
534
535
|
|
|
535
|
-
#handleProcessExit(): void {
|
|
536
|
+
async #handleProcessExit(): Promise<void> {
|
|
536
537
|
if (this.#disposed) return;
|
|
537
538
|
this.#disposed = true;
|
|
538
539
|
const stderr = this.proc.peekStderr().trim();
|
|
539
540
|
const exitCode = this.proc.exitCode;
|
|
541
|
+
const crashNotice = formatCrashDiagnosticNotice(
|
|
542
|
+
await writeCrashReport(
|
|
543
|
+
{
|
|
544
|
+
kind: "dap",
|
|
545
|
+
command: [this.adapter.resolvedCommand, ...this.adapter.args],
|
|
546
|
+
exitCode,
|
|
547
|
+
stderr,
|
|
548
|
+
protocol: this.adapter.connectMode ?? "stdio",
|
|
549
|
+
},
|
|
550
|
+
{ cwd: this.cwd },
|
|
551
|
+
),
|
|
552
|
+
);
|
|
553
|
+
const diagnosticSuffix = crashNotice ? `\n${crashNotice}` : "";
|
|
540
554
|
const error = new Error(
|
|
541
555
|
stderr
|
|
542
|
-
? `DAP adapter exited (code ${exitCode}): ${stderr}`
|
|
543
|
-
: `DAP adapter exited unexpectedly (code ${exitCode})`,
|
|
556
|
+
? `DAP adapter exited (code ${exitCode}): ${stderr}${diagnosticSuffix}`
|
|
557
|
+
: `DAP adapter exited unexpectedly (code ${exitCode})${diagnosticSuffix}`,
|
|
544
558
|
);
|
|
545
559
|
this.#rejectPendingRequests(error);
|
|
546
560
|
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as os from "node:os";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
|
|
5
|
+
const CRASH_DIAGNOSTICS_ENV = "GJC_CRASH_DIAGNOSTICS";
|
|
6
|
+
const CRASH_DIAGNOSTICS_DIR_ENV = "GJC_CRASH_DIAGNOSTICS_DIR";
|
|
7
|
+
const STDERR_PREVIEW_BYTES = 4096;
|
|
8
|
+
const DIRECTORY_MODE = 0o700;
|
|
9
|
+
const REPORT_FILE_MODE = 0o600;
|
|
10
|
+
|
|
11
|
+
export type CrashProcessKind = "bash" | "python" | "lsp" | "dap" | "mcp" | "browser" | "worker" | "native" | "unknown";
|
|
12
|
+
|
|
13
|
+
export type CrashClass =
|
|
14
|
+
| "clean_exit"
|
|
15
|
+
| "non_zero_exit"
|
|
16
|
+
| "signal_exit"
|
|
17
|
+
| "timeout"
|
|
18
|
+
| "cancelled"
|
|
19
|
+
| "spawn_error"
|
|
20
|
+
| "protocol_exit"
|
|
21
|
+
| "native_panic"
|
|
22
|
+
| "unknown";
|
|
23
|
+
|
|
24
|
+
export interface CrashClassificationInput {
|
|
25
|
+
kind: CrashProcessKind;
|
|
26
|
+
command?: string[];
|
|
27
|
+
exitCode?: number | null;
|
|
28
|
+
signal?: string | null;
|
|
29
|
+
cancelled?: boolean;
|
|
30
|
+
timedOut?: boolean;
|
|
31
|
+
spawnError?: unknown;
|
|
32
|
+
stderr?: string;
|
|
33
|
+
protocol?: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface CrashClassification {
|
|
37
|
+
kind: CrashProcessKind;
|
|
38
|
+
class: CrashClass;
|
|
39
|
+
crashed: boolean;
|
|
40
|
+
exitCode: number | null;
|
|
41
|
+
signal: string | null;
|
|
42
|
+
command?: string[];
|
|
43
|
+
protocol?: string;
|
|
44
|
+
reason: string;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface CrashReport extends CrashClassification {
|
|
48
|
+
schemaVersion: 1;
|
|
49
|
+
createdAt: string;
|
|
50
|
+
pid: number;
|
|
51
|
+
cwd: string;
|
|
52
|
+
stderrPreview?: string;
|
|
53
|
+
spawnError?: string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface CrashReportWriteResult {
|
|
57
|
+
report: CrashReport;
|
|
58
|
+
path: string | null;
|
|
59
|
+
enabled: boolean;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function crashDiagnosticsEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
|
|
63
|
+
const value = env[CRASH_DIAGNOSTICS_ENV];
|
|
64
|
+
return value === "1" || value === "true" || value === "yes";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function getCrashDiagnosticsDirectory(env: NodeJS.ProcessEnv = process.env): string {
|
|
68
|
+
return env[CRASH_DIAGNOSTICS_DIR_ENV] ?? path.join(os.tmpdir(), "gjc-crash-diagnostics");
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function classifyProcessCrash(input: CrashClassificationInput): CrashClassification {
|
|
72
|
+
const exitCode = input.exitCode ?? null;
|
|
73
|
+
const signal = input.signal ?? null;
|
|
74
|
+
const command = input.command;
|
|
75
|
+
const protocol = input.protocol;
|
|
76
|
+
|
|
77
|
+
if (input.timedOut) {
|
|
78
|
+
return {
|
|
79
|
+
kind: input.kind,
|
|
80
|
+
class: "timeout",
|
|
81
|
+
crashed: true,
|
|
82
|
+
exitCode,
|
|
83
|
+
signal,
|
|
84
|
+
command,
|
|
85
|
+
protocol,
|
|
86
|
+
reason: "process timed out",
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (input.cancelled) {
|
|
90
|
+
return {
|
|
91
|
+
kind: input.kind,
|
|
92
|
+
class: "cancelled",
|
|
93
|
+
crashed: false,
|
|
94
|
+
exitCode,
|
|
95
|
+
signal,
|
|
96
|
+
command,
|
|
97
|
+
protocol,
|
|
98
|
+
reason: "process was cancelled",
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (input.spawnError !== undefined) {
|
|
102
|
+
return {
|
|
103
|
+
kind: input.kind,
|
|
104
|
+
class: "spawn_error",
|
|
105
|
+
crashed: true,
|
|
106
|
+
exitCode,
|
|
107
|
+
signal,
|
|
108
|
+
command,
|
|
109
|
+
protocol,
|
|
110
|
+
reason: stringifyError(input.spawnError),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
if (signal) {
|
|
114
|
+
return {
|
|
115
|
+
kind: input.kind,
|
|
116
|
+
class: "signal_exit",
|
|
117
|
+
crashed: true,
|
|
118
|
+
exitCode,
|
|
119
|
+
signal,
|
|
120
|
+
command,
|
|
121
|
+
protocol,
|
|
122
|
+
reason: `process exited after signal ${signal}`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
if (exitCode === 0) {
|
|
126
|
+
return {
|
|
127
|
+
kind: input.kind,
|
|
128
|
+
class: "clean_exit",
|
|
129
|
+
crashed: false,
|
|
130
|
+
exitCode,
|
|
131
|
+
signal,
|
|
132
|
+
command,
|
|
133
|
+
protocol,
|
|
134
|
+
reason: "process exited cleanly",
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
if (exitCode !== null) {
|
|
138
|
+
return {
|
|
139
|
+
kind: input.kind,
|
|
140
|
+
class: "non_zero_exit",
|
|
141
|
+
crashed: true,
|
|
142
|
+
exitCode,
|
|
143
|
+
signal,
|
|
144
|
+
command,
|
|
145
|
+
protocol,
|
|
146
|
+
reason: `process exited with code ${exitCode}`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
kind: input.kind,
|
|
151
|
+
class: "protocol_exit",
|
|
152
|
+
crashed: true,
|
|
153
|
+
exitCode,
|
|
154
|
+
signal,
|
|
155
|
+
command,
|
|
156
|
+
protocol,
|
|
157
|
+
reason: "process exited before protocol completion",
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export async function writeCrashReport(
|
|
162
|
+
input: CrashClassificationInput,
|
|
163
|
+
options: { cwd?: string; env?: NodeJS.ProcessEnv; now?: Date } = {},
|
|
164
|
+
): Promise<CrashReportWriteResult> {
|
|
165
|
+
const classification = classifyProcessCrash(input);
|
|
166
|
+
const report: CrashReport = {
|
|
167
|
+
schemaVersion: 1,
|
|
168
|
+
createdAt: (options.now ?? new Date()).toISOString(),
|
|
169
|
+
pid: process.pid,
|
|
170
|
+
cwd: options.cwd ?? process.cwd(),
|
|
171
|
+
...classification,
|
|
172
|
+
stderrPreview: input.stderr ? trimStartBytes(input.stderr, STDERR_PREVIEW_BYTES) : undefined,
|
|
173
|
+
spawnError: input.spawnError === undefined ? undefined : stringifyError(input.spawnError),
|
|
174
|
+
};
|
|
175
|
+
const enabled = crashDiagnosticsEnabled(options.env);
|
|
176
|
+
|
|
177
|
+
if (!classification.crashed || !enabled) {
|
|
178
|
+
return { report, path: null, enabled };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
try {
|
|
182
|
+
const dir = getCrashDiagnosticsDirectory(options.env);
|
|
183
|
+
await ensurePrivateDiagnosticsDirectory(dir);
|
|
184
|
+
const filename = `${report.createdAt.replace(/[:.]/g, "-")}-${report.kind}-${report.class}-${process.pid}.json`;
|
|
185
|
+
const reportPath = path.join(dir, filename);
|
|
186
|
+
await writePrivateCrashReport(reportPath, `${JSON.stringify(report, null, 2)}\n`);
|
|
187
|
+
return { report, path: reportPath, enabled };
|
|
188
|
+
} catch {
|
|
189
|
+
return { report, path: null, enabled };
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export function formatCrashDiagnosticNotice(result: CrashReportWriteResult): string | null {
|
|
194
|
+
if (!result.report.crashed || !result.enabled) return null;
|
|
195
|
+
const location = result.path ? ` report=${result.path}` : "";
|
|
196
|
+
return `[crash:${result.report.kind}:${result.report.class}] ${result.report.reason}${location}`;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async function ensurePrivateDiagnosticsDirectory(dir: string): Promise<void> {
|
|
200
|
+
await fs.mkdir(dir, { recursive: true, mode: DIRECTORY_MODE });
|
|
201
|
+
await fs.chmod(dir, DIRECTORY_MODE);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function writePrivateCrashReport(reportPath: string, contents: string): Promise<void> {
|
|
205
|
+
const file = await fs.open(reportPath, "wx", REPORT_FILE_MODE);
|
|
206
|
+
try {
|
|
207
|
+
await file.writeFile(contents);
|
|
208
|
+
} finally {
|
|
209
|
+
await file.close();
|
|
210
|
+
}
|
|
211
|
+
await fs.chmod(reportPath, REPORT_FILE_MODE);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function stringifyError(error: unknown): string {
|
|
215
|
+
if (error instanceof Error) return error.message;
|
|
216
|
+
return String(error);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function trimStartBytes(value: string, maxBytes: number): string {
|
|
220
|
+
const bytes = Buffer.from(value);
|
|
221
|
+
if (bytes.byteLength <= maxBytes) return value;
|
|
222
|
+
return Buffer.from(bytes.subarray(bytes.byteLength - maxBytes)).toString("utf8");
|
|
223
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime resource owner gauges (Stage 2 observability).
|
|
3
|
+
*
|
|
4
|
+
* Reports counts of long-lived runtime owners as plain data so memory/CPU leak
|
|
5
|
+
* work can see whether owner maps grow without bound across a session. This is
|
|
6
|
+
* framework-agnostic on purpose: it does not depend on the TUI metrics surface,
|
|
7
|
+
* so any consumer (debug report, a metrics bridge, a test) can sample it.
|
|
8
|
+
*/
|
|
9
|
+
import { getShellSessionCount } from "../exec/bash-executor";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Current runtime owner counts, keyed by `<owner>.<resource>`. Extend as more
|
|
13
|
+
* owners (Python kernels, LSP clients, browser tabs, async jobs, streaming
|
|
14
|
+
* queues) expose count getters.
|
|
15
|
+
*/
|
|
16
|
+
export function getRuntimeResourceCounts(): Record<string, number> {
|
|
17
|
+
return {
|
|
18
|
+
"bash.shellSessions": getShellSessionCount(),
|
|
19
|
+
};
|
|
20
|
+
}
|