@gajae-code/coding-agent 0.4.3 → 0.4.5

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.
Files changed (92) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/types/async/job-manager.d.ts +19 -1
  3. package/dist/types/cli/fast-help.d.ts +1 -0
  4. package/dist/types/cli/setup-cli.d.ts +16 -1
  5. package/dist/types/commands/coordinator.d.ts +19 -0
  6. package/dist/types/commands/harness.d.ts +3 -0
  7. package/dist/types/commands/mcp-serve.d.ts +24 -0
  8. package/dist/types/commands/setup.d.ts +47 -0
  9. package/dist/types/config/model-registry.d.ts +3 -0
  10. package/dist/types/config/models-config-schema.d.ts +5 -0
  11. package/dist/types/coordinator/contract.d.ts +4 -0
  12. package/dist/types/coordinator-mcp/policy.d.ts +24 -0
  13. package/dist/types/coordinator-mcp/safety.d.ts +26 -0
  14. package/dist/types/coordinator-mcp/server.d.ts +58 -0
  15. package/dist/types/extensibility/extensions/types.d.ts +13 -0
  16. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
  17. package/dist/types/harness-control-plane/finalize.d.ts +5 -0
  18. package/dist/types/harness-control-plane/phase-rollup.d.ts +23 -0
  19. package/dist/types/harness-control-plane/receipt-ingest.d.ts +19 -0
  20. package/dist/types/harness-control-plane/receipts.d.ts +46 -0
  21. package/dist/types/harness-control-plane/rpc-adapter.d.ts +3 -0
  22. package/dist/types/harness-control-plane/types.d.ts +9 -1
  23. package/dist/types/main.d.ts +2 -2
  24. package/dist/types/modes/components/hook-selector.d.ts +11 -0
  25. package/dist/types/modes/utils/abort-message.d.ts +4 -0
  26. package/dist/types/session/session-manager.d.ts +8 -0
  27. package/dist/types/setup/hermes-setup.d.ts +78 -0
  28. package/dist/types/task/fork-context-advisory.d.ts +13 -0
  29. package/dist/types/task/receipt.d.ts +1 -0
  30. package/dist/types/task/render.d.ts +7 -1
  31. package/dist/types/task/roi-reconciliation.d.ts +27 -0
  32. package/dist/types/task/types.d.ts +10 -0
  33. package/dist/types/tools/subagent-render.d.ts +25 -0
  34. package/dist/types/tools/subagent.d.ts +5 -1
  35. package/package.json +8 -7
  36. package/scripts/build-binary.ts +4 -0
  37. package/src/async/job-manager.ts +43 -1
  38. package/src/cli/fast-help.ts +80 -0
  39. package/src/cli/setup-cli.ts +95 -2
  40. package/src/cli.ts +109 -16
  41. package/src/commands/coordinator.ts +113 -0
  42. package/src/commands/harness.ts +92 -9
  43. package/src/commands/mcp-serve.ts +63 -0
  44. package/src/commands/setup.ts +34 -1
  45. package/src/config/models-config-schema.ts +1 -0
  46. package/src/coordinator/contract.ts +21 -0
  47. package/src/coordinator-mcp/policy.ts +160 -0
  48. package/src/coordinator-mcp/safety.ts +80 -0
  49. package/src/coordinator-mcp/server.ts +1519 -0
  50. package/src/cursor.ts +30 -2
  51. package/src/extensibility/extensions/types.ts +13 -0
  52. package/src/gjc-runtime/launch-worktree.ts +12 -1
  53. package/src/gjc-runtime/session-state-sidecar.ts +117 -0
  54. package/src/harness-control-plane/finalize.ts +39 -5
  55. package/src/harness-control-plane/owner.ts +9 -1
  56. package/src/harness-control-plane/phase-rollup.ts +96 -0
  57. package/src/harness-control-plane/receipt-ingest.ts +127 -0
  58. package/src/harness-control-plane/receipts.ts +229 -1
  59. package/src/harness-control-plane/rpc-adapter.ts +8 -0
  60. package/src/harness-control-plane/types.ts +29 -1
  61. package/src/internal-urls/docs-index.generated.ts +6 -4
  62. package/src/main.ts +7 -3
  63. package/src/modes/components/hook-selector.ts +109 -5
  64. package/src/modes/components/status-line.ts +6 -6
  65. package/src/modes/controllers/event-controller.ts +5 -4
  66. package/src/modes/controllers/extension-ui-controller.ts +16 -1
  67. package/src/modes/interactive-mode.ts +4 -5
  68. package/src/modes/print-mode.ts +1 -1
  69. package/src/modes/theme/theme.ts +2 -2
  70. package/src/modes/utils/abort-message.ts +41 -0
  71. package/src/modes/utils/context-usage.ts +15 -8
  72. package/src/modes/utils/ui-helpers.ts +5 -6
  73. package/src/prompts/agents/architect.md +6 -0
  74. package/src/prompts/agents/critic.md +6 -0
  75. package/src/prompts/agents/planner.md +8 -1
  76. package/src/sdk.ts +9 -4
  77. package/src/session/agent-session.ts +22 -5
  78. package/src/session/session-manager.ts +20 -0
  79. package/src/setup/hermes/templates/operator-instructions.v1.md +30 -0
  80. package/src/setup/hermes-setup.ts +484 -0
  81. package/src/task/fork-context-advisory.ts +99 -0
  82. package/src/task/index.ts +33 -2
  83. package/src/task/receipt.ts +2 -0
  84. package/src/task/render.ts +14 -0
  85. package/src/task/roi-reconciliation.ts +90 -0
  86. package/src/task/types.ts +7 -0
  87. package/src/tools/ask.ts +30 -10
  88. package/src/tools/index.ts +2 -2
  89. package/src/tools/renderers.ts +2 -0
  90. package/src/tools/subagent-render.ts +169 -0
  91. package/src/tools/subagent.ts +49 -7
  92. package/src/utils/title-generator.ts +16 -2
package/CHANGELOG.md CHANGED
@@ -2,6 +2,46 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.4.5] - 2026-06-12
6
+
7
+ ### Added
8
+
9
+ - Added a dim `(ctrl+s to observe sessions)` discoverability hint under the `subagent` await panel header while any awaited subagent is still running, pointing to the full session observer overlay; the hint shows in both collapsed and expanded states and disappears once no subagent is running.
10
+ - Added a `phase-rollup` receipt family (receipt-of-receipts) to the harness control plane: a hash-sealed rollup that supersedes N child task receipts at a lifecycle boundary, preserving per-child `{id, status, outputUri, outputSha256, receiptSha256, tokens, costTotal, clonedTokens, lowRoi}` pointers plus aggregate ROI totals, with a pure deterministic builder (`buildPhaseRollupReceipt`) and fail-closed semantic validation.
11
+ - Added a pure receipt-ingestion fast path (`ingestReceipts`): fail-closed batch validation + lifecycle transition computation via the existing state machine, plus a deterministic model-facing digest hard-capped at 280 chars — groundwork for LLM-free receipt routing.
12
+ - Added advisory spawn-ROI reconciliation (`reconcileSpawnRoi`) and deterministic fork-context mode advice (`adviseForkContextMode`) surfaced in task receipts without changing task success semantics.
13
+ - Added the Grok Build provider contract design document.
14
+
15
+ ### Changed
16
+
17
+ - Reduced compiled CLI startup and native bundle pressure with default-small grammar loading, tokenizer tiering, and compiled fast-help paths.
18
+ - Preserved dev/main release metadata and changelog consistency for the 0.4.5 lockstep release.
19
+
20
+ ### Fixed
21
+
22
+ - Kept the unified `goal` tool registered and active by default whenever `goal.enabled` is true, including explicit tool subsets and `gjc ultragoal create-goals` arming flows.
23
+ - Restored no-argument `gjc` interactive startup instead of launching help.
24
+ - Rendered and executed Cursor-native tool calls, including detached/native handler paths and empty-pattern composer grep guards.
25
+ - Tool-output pruning no longer rewrites already-sent provider-facing history mid prompt-cache epoch and now persists pruned message updates back into canonical session storage.
26
+ - Preserved provider abort root causes in the final TUI abort label, kept replay rendering idempotent, and added a `PI_STREAM_IDLE_TIMEOUT_MS` remediation hint when stream idle watchdogs fire.
27
+ - Hardened harness owner recovery/finalize paths and submit-prompt-file handling.
28
+
29
+ ## [0.4.4] - 2026-06-10
30
+
31
+ ### Added
32
+
33
+ - Made coordinator turns event-backed, adding an MCP coordinator server and the `gjc coordinator` / `gjc mcp-serve` commands backed by durable turn/session state (#479).
34
+ - Surfaced awaited sub-agent live streaming status in the await panel (#475).
35
+
36
+ ### Changed
37
+
38
+ - Refreshed the README brand images (#477).
39
+
40
+ ### Fixed
41
+
42
+ - Persisted ralplan role-agent artifacts via the CLI, returning receipt-only output to the caller (#474).
43
+ - Collected the `ask` tool "Other" custom input inline below the option list (#476).
44
+
5
45
  ## [0.4.3] - 2026-06-10
6
46
 
7
47
  ### Added
@@ -17,9 +57,11 @@
17
57
  ### Changed
18
58
 
19
59
  - Added conservative `timeout-minutes` values to all CI workflow jobs to prevent indefinite hangs.
60
+ - Made coordinator MCP turn waiting state-backed by durable turn/session files, with runtime session sidecar updates for running/completed/error states and Meeseeks guidance that avoids fixed sleep/capture-pane loops.
20
61
 
21
62
  ### Fixed
22
63
 
64
+ - Failed stale coordinator turns quickly when their recorded tmux session is gone, clearing active-turn state instead of burning await timeouts.
23
65
  - Improved the grep limit-reached message to show the current limit value and suggest using `--limit` for more results.
24
66
  - Passed the active model's `maxTokens` (reserved completion budget) into the auto-compaction threshold and context-usage reserve so prompt packing reserves output for large-window models, keeping the safe input budget below the total context window (e.g. ~272K for a 400K/128K model) instead of filling the whole window ([#442](https://github.com/Yeachan-Heo/gajae-code/issues/442)).
25
67
  - Fixed a `gjc harness` recovery deadlock where a session created by `start` without `--detach` (persisted as `started` with no owner lease/endpoint) could never get a live owner: `recover` refused to spawn one because no prior endpoint existed, while `start` reported `session-already-exists`. `recover` now bootstraps a fresh owner for a never-started session (no lease, no endpoint, no owner-run evidence) without writing a misleading `vanish` receipt, reported via `bootstrappedOwner: true`. Bootstrap is independent of the vanish classifier's `ownerRequired` verdict (nothing has vanished), so a session started in a non-git workspace (git delta `unknown`) is recovered too, while a deleted worktree is still refused (#421).
@@ -1,4 +1,4 @@
1
- import type { AgentSource } from "../task/types";
1
+ import type { AgentProgress, AgentSource } from "../task/types";
2
2
  export interface AsyncJob {
3
3
  id: string;
4
4
  type: "bash" | "task";
@@ -189,6 +189,24 @@ export declare class AsyncJobManager {
189
189
  registerLiveHandle(subagentId: string, handle: SubagentLiveHandle): void;
190
190
  getLiveHandle(subagentId: string): SubagentLiveHandle | undefined;
191
191
  removeLiveHandle(subagentId: string): void;
192
+ /**
193
+ * Retain the latest live `AgentProgress` for a subagent (deep-cloned so later
194
+ * mutation of the live object cannot corrupt retained state). Read by the
195
+ * `subagent` await panel; cleared on terminal/cancel/purge/dispose.
196
+ *
197
+ * Ignored for ids without a canonical `SubagentRecord` (e.g. foreground/inline
198
+ * task runs that share the executor path) so the map only holds detached
199
+ * subagent progress and never accumulates untracked foreground task state.
200
+ */
201
+ recordSubagentProgress(subagentId: string, progress: AgentProgress): void;
202
+ getSubagentProgress(subagentId: string): AgentProgress | undefined;
203
+ /**
204
+ * True only when a live, in-session progress producer exists for this id: a
205
+ * canonical registered record with a live handle or an in-memory running job.
206
+ * False for `SubagentTool` backward-compat job synthesis and resumed-from-disk
207
+ * records, which have no live producer to stream from.
208
+ */
209
+ hasLiveSubagent(subagentId: string, filter?: AsyncJobFilter): boolean;
192
210
  /** Install the TaskTool-owned resume runner. Returns the new job id, or undefined on failure. */
193
211
  setResumeRunner(runner: (subagentId: string, message?: string, descriptor?: ResumeDescriptor) => string | undefined): void;
194
212
  registerResumeDescriptor(descriptor: ResumeDescriptor): void;
@@ -0,0 +1 @@
1
+ export declare function getExtraHelpText(): string;
@@ -1,4 +1,4 @@
1
- export type SetupComponent = "defaults" | "hooks" | "provider" | "python" | "stt";
1
+ export type SetupComponent = "defaults" | "hermes" | "hooks" | "provider" | "python" | "stt";
2
2
  export interface SetupCommandArgs {
3
3
  component: SetupComponent;
4
4
  flags: {
@@ -12,6 +12,21 @@ export interface SetupCommandArgs {
12
12
  apiKeyEnv?: string;
13
13
  model?: string[];
14
14
  modelsPath?: string;
15
+ smoke?: boolean;
16
+ install?: boolean;
17
+ root?: string[];
18
+ repo?: string;
19
+ profile?: string;
20
+ sessionCommand?: string;
21
+ noWorktree?: boolean;
22
+ worktreeName?: string;
23
+ stateRoot?: string;
24
+ mutation?: string[];
25
+ artifactByteCap?: string;
26
+ serverKey?: string;
27
+ gjcCommand?: string;
28
+ target?: string;
29
+ profileDir?: string;
15
30
  };
16
31
  }
17
32
  /**
@@ -0,0 +1,19 @@
1
+ import { Command } from "@gajae-code/utils/cli";
2
+ export default class Coordinator extends Command {
3
+ static description: string;
4
+ static strict: boolean;
5
+ static args: {
6
+ action: import("@gajae-code/utils/cli").ArgDescriptor & {
7
+ description: string;
8
+ required: false;
9
+ };
10
+ };
11
+ static flags: {
12
+ json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
13
+ char: string;
14
+ description: string;
15
+ default: boolean;
16
+ };
17
+ };
18
+ run(): Promise<void>;
19
+ }
@@ -14,6 +14,9 @@ export default class Harness extends Command {
14
14
  description: string;
15
15
  default: string;
16
16
  };
17
+ "prompt-file": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
18
+ description: string;
19
+ };
17
20
  session: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
18
21
  char: string;
19
22
  description: string;
@@ -0,0 +1,24 @@
1
+ import { Command } from "@gajae-code/utils/cli";
2
+ export declare function validateMcpServeSubcommandForTest(server: string | undefined): void;
3
+ export default class McpServe extends Command {
4
+ static description: string;
5
+ static strict: boolean;
6
+ static args: {
7
+ server: import("@gajae-code/utils/cli").ArgDescriptor & {
8
+ description: string;
9
+ required: false;
10
+ };
11
+ };
12
+ static flags: {
13
+ json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
14
+ char: string;
15
+ description: string;
16
+ default: boolean;
17
+ };
18
+ check: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
19
+ description: string;
20
+ default: boolean;
21
+ };
22
+ };
23
+ run(): Promise<void>;
24
+ }
@@ -24,6 +24,53 @@ export default class Setup extends Command {
24
24
  json: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
25
25
  description: string;
26
26
  };
27
+ smoke: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
28
+ description: string;
29
+ };
30
+ install: import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
31
+ description: string;
32
+ };
33
+ root: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
34
+ description: string;
35
+ multiple: true;
36
+ };
37
+ repo: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
38
+ description: string;
39
+ };
40
+ profile: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
41
+ description: string;
42
+ };
43
+ "session-command": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
44
+ description: string;
45
+ };
46
+ "no-worktree": import("@gajae-code/utils/cli").FlagDescriptor<"boolean"> & {
47
+ description: string;
48
+ };
49
+ "worktree-name": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
50
+ description: string;
51
+ };
52
+ "state-root": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
53
+ description: string;
54
+ };
55
+ mutation: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
56
+ description: string;
57
+ multiple: true;
58
+ };
59
+ "artifact-byte-cap": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
60
+ description: string;
61
+ };
62
+ "server-key": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
63
+ description: string;
64
+ };
65
+ "gjc-command": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
66
+ description: string;
67
+ };
68
+ target: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
69
+ description: string;
70
+ };
71
+ "profile-dir": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
72
+ description: string;
73
+ };
27
74
  preset: import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
28
75
  description: string;
29
76
  };
@@ -70,6 +70,7 @@ export declare const ModelsConfigFile: ConfigFile<{
70
70
  allowsSyntheticReasoningContentForToolCalls?: boolean | undefined;
71
71
  requiresAssistantContentForToolCalls?: boolean | undefined;
72
72
  supportsToolChoice?: boolean | undefined;
73
+ supportsForcedToolChoice?: boolean | undefined;
73
74
  disableReasoningOnForcedToolChoice?: boolean | undefined;
74
75
  disableReasoningOnToolChoice?: boolean | undefined;
75
76
  thinkingFormat?: "openai" | "openrouter" | "qwen" | "qwen-chat-template" | "zai" | undefined;
@@ -145,6 +146,7 @@ export declare const ModelsConfigFile: ConfigFile<{
145
146
  allowsSyntheticReasoningContentForToolCalls?: boolean | undefined;
146
147
  requiresAssistantContentForToolCalls?: boolean | undefined;
147
148
  supportsToolChoice?: boolean | undefined;
149
+ supportsForcedToolChoice?: boolean | undefined;
148
150
  disableReasoningOnForcedToolChoice?: boolean | undefined;
149
151
  disableReasoningOnToolChoice?: boolean | undefined;
150
152
  thinkingFormat?: "openai" | "openrouter" | "qwen" | "qwen-chat-template" | "zai" | undefined;
@@ -216,6 +218,7 @@ export declare const ModelsConfigFile: ConfigFile<{
216
218
  allowsSyntheticReasoningContentForToolCalls?: boolean | undefined;
217
219
  requiresAssistantContentForToolCalls?: boolean | undefined;
218
220
  supportsToolChoice?: boolean | undefined;
221
+ supportsForcedToolChoice?: boolean | undefined;
219
222
  disableReasoningOnForcedToolChoice?: boolean | undefined;
220
223
  disableReasoningOnToolChoice?: boolean | undefined;
221
224
  thinkingFormat?: "openai" | "openrouter" | "qwen" | "qwen-chat-template" | "zai" | undefined;
@@ -30,6 +30,7 @@ export declare const OpenAICompatSchema: z.ZodObject<{
30
30
  allowsSyntheticReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
31
31
  requiresAssistantContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
32
32
  supportsToolChoice: z.ZodOptional<z.ZodBoolean>;
33
+ supportsForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
33
34
  disableReasoningOnForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
34
35
  disableReasoningOnToolChoice: z.ZodOptional<z.ZodBoolean>;
35
36
  thinkingFormat: z.ZodOptional<z.ZodEnum<{
@@ -182,6 +183,7 @@ export declare const ModelOverrideSchema: z.ZodObject<{
182
183
  allowsSyntheticReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
183
184
  requiresAssistantContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
184
185
  supportsToolChoice: z.ZodOptional<z.ZodBoolean>;
186
+ supportsForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
185
187
  disableReasoningOnForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
186
188
  disableReasoningOnToolChoice: z.ZodOptional<z.ZodBoolean>;
187
189
  thinkingFormat: z.ZodOptional<z.ZodEnum<{
@@ -288,6 +290,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
288
290
  allowsSyntheticReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
289
291
  requiresAssistantContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
290
292
  supportsToolChoice: z.ZodOptional<z.ZodBoolean>;
293
+ supportsForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
291
294
  disableReasoningOnForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
292
295
  disableReasoningOnToolChoice: z.ZodOptional<z.ZodBoolean>;
293
296
  thinkingFormat: z.ZodOptional<z.ZodEnum<{
@@ -442,6 +445,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
442
445
  allowsSyntheticReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
443
446
  requiresAssistantContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
444
447
  supportsToolChoice: z.ZodOptional<z.ZodBoolean>;
448
+ supportsForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
445
449
  disableReasoningOnForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
446
450
  disableReasoningOnToolChoice: z.ZodOptional<z.ZodBoolean>;
447
451
  thinkingFormat: z.ZodOptional<z.ZodEnum<{
@@ -575,6 +579,7 @@ export declare const ModelsConfigSchema: z.ZodObject<{
575
579
  allowsSyntheticReasoningContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
576
580
  requiresAssistantContentForToolCalls: z.ZodOptional<z.ZodBoolean>;
577
581
  supportsToolChoice: z.ZodOptional<z.ZodBoolean>;
582
+ supportsForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
578
583
  disableReasoningOnForcedToolChoice: z.ZodOptional<z.ZodBoolean>;
579
584
  disableReasoningOnToolChoice: z.ZodOptional<z.ZodBoolean>;
580
585
  thinkingFormat: z.ZodOptional<z.ZodEnum<{
@@ -0,0 +1,4 @@
1
+ export declare const COORDINATOR_MCP_PROTOCOL_VERSION = "2024-11-05";
2
+ export declare const COORDINATOR_MCP_SERVER_NAME = "gjc-coordinator-mcp";
3
+ export declare const COORDINATOR_MCP_TOOL_NAMES: readonly ["gjc_coordinator_list_sessions", "gjc_coordinator_read_status", "gjc_coordinator_read_tail", "gjc_coordinator_list_questions", "gjc_coordinator_list_artifacts", "gjc_coordinator_read_artifact", "gjc_coordinator_read_coordination_status", "gjc_coordinator_register_session", "gjc_coordinator_start_session", "gjc_coordinator_send_prompt", "gjc_coordinator_submit_question_answer", "gjc_coordinator_read_turn", "gjc_coordinator_await_turn", "gjc_coordinator_report_status"];
4
+ export type CoordinatorToolName = (typeof COORDINATOR_MCP_TOOL_NAMES)[number];
@@ -0,0 +1,24 @@
1
+ export type CoordinatorMutationClass = "sessions" | "questions" | "reports";
2
+ export interface CoordinatorNamespace {
3
+ profile: string | null;
4
+ repo: string | null;
5
+ }
6
+ export interface CoordinatorMcpConfig {
7
+ allowedRoots: string[];
8
+ mutationClasses: Set<CoordinatorMutationClass>;
9
+ artifactByteCap: number;
10
+ namespace: CoordinatorNamespace;
11
+ stateRoot: string;
12
+ sessionCommand: string | null;
13
+ }
14
+ export interface CoordinatorMutationRequest {
15
+ allow_mutation?: boolean;
16
+ }
17
+ export declare function buildCoordinatorMcpConfig(env?: NodeJS.ProcessEnv): CoordinatorMcpConfig;
18
+ export declare function assertCoordinatorWorkdir(config: CoordinatorMcpConfig, cwd: unknown): Promise<string>;
19
+ export declare function assertCoordinatorArtifactPath(config: CoordinatorMcpConfig, artifactPath: unknown): Promise<{
20
+ path: string;
21
+ byteCap: number;
22
+ }>;
23
+ export declare function requireCoordinatorMutation(config: CoordinatorMcpConfig, mutationClass: CoordinatorMutationClass, request: CoordinatorMutationRequest): void;
24
+ export declare function coordinatorNamespacePath(config: CoordinatorMcpConfig): string;
@@ -0,0 +1,26 @@
1
+ import { type CoordinatorMutationClass } from "./policy";
2
+ export declare const COORDINATOR_MUTATION_CLASSES: readonly ["sessions", "questions", "reports"];
3
+ export type { CoordinatorMutationClass };
4
+ export interface CoordinatorSafetyConfig {
5
+ allowedRoots: string[];
6
+ artifactMaxBytes: number;
7
+ enabledMutationClasses: Set<CoordinatorMutationClass>;
8
+ repo?: string;
9
+ profile?: string;
10
+ }
11
+ export interface CoordinatorSafetyPolicy {
12
+ config: CoordinatorSafetyConfig;
13
+ resolveWorkdir(input: unknown): Promise<string>;
14
+ resolveArtifactPath(input: unknown): Promise<string>;
15
+ assertMutationAllowed(mutationClass: CoordinatorMutationClass, args: Record<string, unknown>): {
16
+ ok: true;
17
+ } | CoordinatorFailure;
18
+ }
19
+ export interface CoordinatorFailure {
20
+ ok: false;
21
+ reason: string;
22
+ [key: string]: unknown;
23
+ }
24
+ export declare function createCoordinatorSafetyPolicy(options?: {
25
+ env?: NodeJS.ProcessEnv;
26
+ }): Promise<CoordinatorSafetyPolicy>;
@@ -0,0 +1,58 @@
1
+ import { COORDINATOR_MCP_PROTOCOL_VERSION, COORDINATOR_MCP_SERVER_NAME, COORDINATOR_MCP_TOOL_NAMES, type CoordinatorToolName } from "../coordinator/contract";
2
+ import { type CoordinatorMcpConfig } from "./policy";
3
+ export type { CoordinatorToolName };
4
+ export { COORDINATOR_MCP_PROTOCOL_VERSION, COORDINATOR_MCP_SERVER_NAME, COORDINATOR_MCP_TOOL_NAMES };
5
+ interface JsonRpcRequest {
6
+ jsonrpc: "2.0";
7
+ id?: string | number | null;
8
+ method: string;
9
+ params?: unknown;
10
+ }
11
+ type JsonRpcResult = any;
12
+ interface JsonRpcResponse {
13
+ jsonrpc: "2.0";
14
+ id: string | number | null;
15
+ result?: JsonRpcResult;
16
+ error?: {
17
+ code: number;
18
+ message: string;
19
+ data?: unknown;
20
+ };
21
+ }
22
+ interface SessionStartInput {
23
+ cwd: string;
24
+ prompt?: string;
25
+ namespace: {
26
+ profile: string | null;
27
+ repo: string | null;
28
+ };
29
+ worktree: true;
30
+ }
31
+ interface CoordinatorServices {
32
+ listSessions?: () => unknown[] | Promise<unknown[]>;
33
+ startSession?: (input: SessionStartInput) => unknown | Promise<unknown>;
34
+ commandRunner?: (command: string[]) => Promise<{
35
+ exitCode: number;
36
+ stdout: string;
37
+ stderr: string;
38
+ }>;
39
+ }
40
+ interface CoordinatorMcpServerOptions {
41
+ env?: NodeJS.ProcessEnv;
42
+ services?: CoordinatorServices;
43
+ }
44
+ interface LegacyHandlerOptions {
45
+ env?: NodeJS.ProcessEnv;
46
+ createSession?: () => unknown;
47
+ }
48
+ export declare function readCoordinatorArtifact(config: CoordinatorMcpConfig, args: {
49
+ path: unknown;
50
+ }): Promise<Record<string, unknown>>;
51
+ export declare function createCoordinatorMcpServer(options?: CoordinatorMcpServerOptions): {
52
+ config: CoordinatorMcpConfig;
53
+ callTool: (name: string, args?: Record<string, unknown>) => Promise<Record<string, unknown>>;
54
+ handleJsonRpc: (request: JsonRpcRequest) => Promise<JsonRpcResponse>;
55
+ handle: (request: JsonRpcRequest) => Promise<JsonRpcResponse>;
56
+ };
57
+ export declare function handleCoordinatorMcpRequest(request: JsonRpcRequest, options?: LegacyHandlerOptions): Promise<JsonRpcResponse>;
58
+ export declare function runCoordinatorMcpStdio(options?: CoordinatorMcpServerOptions): Promise<void>;
@@ -62,6 +62,19 @@ export interface ExtensionUIDialogOptions {
62
62
  * select-only rendering hint; non-TUI bridges drop it and do not serialize it.
63
63
  */
64
64
  scrollTitleRows?: number;
65
+ /**
66
+ * For interactive TUI select dialogs, handle the option with `optionLabel`
67
+ * inline: selecting it keeps the title and option list on screen and opens
68
+ * a free-text input below the list. Submitting calls `onSubmit` with the
69
+ * typed text and resolves the select with `optionLabel`; Escape returns to
70
+ * option selection. Non-TUI bridges (RPC, ACP) drop it; callers must keep
71
+ * a fallback path for selects that resolve `optionLabel` without invoking
72
+ * `onSubmit`.
73
+ */
74
+ customInput?: {
75
+ optionLabel: string;
76
+ onSubmit: (text: string) => void;
77
+ };
65
78
  }
66
79
  /** Raw terminal input listener for extensions. */
67
80
  export type TerminalInputHandler = (data: string) => {
@@ -0,0 +1,13 @@
1
+ export declare const GJC_COORDINATOR_SESSION_STATE_FILE_ENV = "GJC_COORDINATOR_SESSION_STATE_FILE";
2
+ export declare const GJC_COORDINATOR_SESSION_ID_ENV = "GJC_COORDINATOR_SESSION_ID";
3
+ interface RuntimeStateEvent {
4
+ type: string;
5
+ messages?: unknown[];
6
+ }
7
+ interface RuntimeStateContext {
8
+ sessionId: string;
9
+ cwd: string;
10
+ sessionFile?: string | null;
11
+ }
12
+ export declare function persistCoordinatorRuntimeStateFromEvent(event: RuntimeStateEvent, context: RuntimeStateContext): Promise<void>;
13
+ export {};
@@ -30,6 +30,11 @@ export interface FinalizeOptions {
30
30
  reviewOnly?: boolean;
31
31
  /** Operator/loop-supplied terminal review verdict (closed vocabulary). */
32
32
  verdict?: string | null;
33
+ /**
34
+ * Final assistant text from the live RPC owner, used to extract a closed-vocabulary verdict
35
+ * for review-only sessions when no explicit {@link verdict} is supplied. Never persisted raw.
36
+ */
37
+ assistantText?: string | null;
33
38
  /** Bounded PR/issue reference for the review target (e.g. "PR-414"). Never resolved from the live repo. */
34
39
  prTarget?: string | null;
35
40
  validationCommands?: ValidationCommandSpec[];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Phase-boundary receipt rollup builder (receipt-of-receipts).
3
+ *
4
+ * At a harness lifecycle boundary, N child task receipts can be superseded by a
5
+ * single `phase-rollup` receipt that preserves per-child pointers (id, status,
6
+ * outputRef, sha256) plus aggregate ROI totals. The rollup is hash-sealed via
7
+ * the standard receipt envelope and validated fail-closed like every other
8
+ * family (see `validatePhaseRollup` in receipts.ts). Pure builder — no runtime
9
+ * injection behavior is changed here.
10
+ */
11
+ import type { TaskResultReceipt } from "../task/receipt";
12
+ import { type BuildReceiptInput, type PhaseRollupEvidence, type ReceiptEnvelope } from "./receipts";
13
+ export interface BuildPhaseRollupInput {
14
+ receiptId: string;
15
+ sessionId: string;
16
+ source: string;
17
+ subject: BuildReceiptInput<PhaseRollupEvidence>["subject"];
18
+ phase: string;
19
+ children: readonly TaskResultReceipt[];
20
+ /** Supply for deterministic output; defaults to now. */
21
+ createdAt?: string;
22
+ }
23
+ export declare function buildPhaseRollupReceipt(input: BuildPhaseRollupInput): ReceiptEnvelope<PhaseRollupEvidence>;
@@ -0,0 +1,19 @@
1
+ import type { ReceiptEnvelope } from "./receipts";
2
+ import type { HarnessLifecycle, ReceiptFamily, SessionState } from "./types";
3
+ export declare const RECEIPT_DIGEST_MAX_CHARS = 280;
4
+ export declare const RECEIPT_FAMILY_LIFECYCLE_TARGETS: Partial<Record<ReceiptFamily, HarnessLifecycle>>;
5
+ export interface ReceiptIngestResult {
6
+ accepted: ReceiptEnvelope<unknown>[];
7
+ rejected: {
8
+ receipt: ReceiptEnvelope<unknown>;
9
+ reasons: string[];
10
+ }[];
11
+ transitions: {
12
+ from: HarnessLifecycle;
13
+ to: HarnessLifecycle;
14
+ receiptId: string;
15
+ }[];
16
+ finalLifecycle: HarnessLifecycle;
17
+ digest: string;
18
+ }
19
+ export declare function ingestReceipts(state: SessionState, receipts: readonly ReceiptEnvelope<unknown>[]): ReceiptIngestResult;
@@ -20,6 +20,8 @@ export interface ReceiptEnvelope<E = Record<string, unknown>> {
20
20
  sha256: string;
21
21
  }
22
22
  export declare const RECEIPT_SCHEMA_VERSION: 1;
23
+ /** Deterministic stringify with sorted keys (stable hash basis). */
24
+ export declare function canonicalJson(value: unknown): string;
23
25
  export declare function sha256Hex(input: string): string;
24
26
  export interface BuildReceiptInput<E> {
25
27
  receiptId: string;
@@ -90,6 +92,10 @@ export interface ReviewVerdictEvidence {
90
92
  finalizedAt: string;
91
93
  /** Bounded summary code/reference for the verdict; never raw assistant text. */
92
94
  summaryRef: string | null;
95
+ /** Where the verdict came from: explicit operator input or extracted from final assistant text. */
96
+ verdictSource?: "input" | "assistant";
97
+ /** sha256 of the assistant text the verdict was extracted from, when sourced from the agent. */
98
+ assistantDigest?: string | null;
93
99
  }
94
100
  export interface ReviewFailureEvidence {
95
101
  /** Machine-actionable reason the review produced no terminal verdict. */
@@ -98,6 +104,46 @@ export interface ReviewFailureEvidence {
98
104
  failedAt: string;
99
105
  /** Routing hint for the operator/fallback path. */
100
106
  fallback: string;
107
+ /** sha256 of the assistant text examined for a verdict, when one was available. */
108
+ assistantDigest?: string | null;
109
+ /** Bounded, whitespace-collapsed assistant summary (never an unbounded transcript dump). */
110
+ assistantSummary?: string | null;
101
111
  }
112
+ /** Pointer back to one superseded child task receipt. */
113
+ export interface PhaseRollupChildPointer {
114
+ id: string;
115
+ status: "completed" | "failed" | "aborted" | "merge_failed" | "paused";
116
+ /** Artifact URI holding the child's full output, when available. */
117
+ outputUri: string | null;
118
+ /** Content hash of the child's output artifact, when available. */
119
+ outputSha256: string | null;
120
+ /** Hash of the child receipt itself (canonical JSON), for staleness checks. */
121
+ receiptSha256: string;
122
+ /**
123
+ * Per-child ROI accounting carried into the rollup so the aggregate totals
124
+ * below are recomputable/verifiable from child evidence (not self-reported).
125
+ * `tokens` is the child's effective token count; cost/cloned are null when
126
+ * the child reported no such accounting.
127
+ */
128
+ tokens: number;
129
+ costTotal: number | null;
130
+ clonedTokens: number | null;
131
+ lowRoi: boolean;
132
+ }
133
+ export interface PhaseRollupEvidence {
134
+ /** Harness lifecycle boundary this rollup was emitted at. */
135
+ phase: string;
136
+ children: PhaseRollupChildPointer[];
137
+ aggregate: {
138
+ childCount: number;
139
+ completed: number;
140
+ failed: number;
141
+ totalTokens: number;
142
+ totalCostTotal: number | null;
143
+ totalClonedTokens: number | null;
144
+ lowRoiChildIds: string[];
145
+ };
146
+ }
147
+ export declare function validatePhaseRollup(e: PhaseRollupEvidence): string[];
102
148
  /** Classifications that MUST have a valid `vanish` receipt before the action proceeds. */
103
149
  export declare function requiresVanishBeforeAction(classification: RecoveryClassification): boolean;
@@ -24,6 +24,8 @@ export interface HarnessRpc {
24
24
  isLive?(): boolean;
25
25
  /** ISO timestamp of the last observed event frame, or null. */
26
26
  lastFrameAt?(): string | null;
27
+ /** Final assistant text from the live session (for review-verdict extraction); null when unavailable. */
28
+ getLastAssistantText?(): Promise<string | null>;
27
29
  }
28
30
  export interface AcceptanceResult {
29
31
  accepted: boolean;
@@ -54,6 +56,7 @@ export declare class GajaeCodeRpc implements HarnessRpc {
54
56
  isLive(): boolean;
55
57
  lastFrameAt(): string | null;
56
58
  getState(): Promise<RpcStateSnapshot>;
59
+ getLastAssistantText(): Promise<string | null>;
57
60
  sendPrompt(prompt: string): Promise<{
58
61
  commandId: string;
59
62
  ack: boolean;
@@ -16,6 +16,14 @@ export type SessionMode = "implement" | "review";
16
16
  export type ReviewVerdict = "APPROVE_MERGE_READY" | "REQUEST_CHANGES" | "OWNER_CONFIRMATION_REQUIRED";
17
17
  export declare const REVIEW_VERDICTS: readonly ReviewVerdict[];
18
18
  export declare function isReviewVerdict(value: unknown): value is ReviewVerdict;
19
+ /**
20
+ * Extract a single closed-vocabulary review verdict from free-form assistant text.
21
+ *
22
+ * Scans for canonical verdict tokens (and accepted aliases) as whole words and returns the
23
+ * LAST occurrence — the agent's final stated decision wins over any earlier mention. Returns
24
+ * null when no allowed token is present, so the finalizer fails closed on a missing verdict.
25
+ */
26
+ export declare function extractReviewVerdict(text: string | null | undefined): ReviewVerdict | null;
19
27
  /** Lifecycle states of an operated session. */
20
28
  export type HarnessLifecycle = "new" | "started" | "submitted" | "observing" | "recovering" | "validating" | "finalizing" | "completed" | "blocked" | "retired";
21
29
  /** Event severities emitted by the owner. */
@@ -27,7 +35,7 @@ export type RiskKind = "normal" | "prompt-not-accepted" | "deleted-worktree" | "
27
35
  /** Deterministic recovery classifications. */
28
36
  export type RecoveryClassification = "continue" | "send-enter" | "reinject-prompt" | "restart-clean" | "restart-preserve-delta" | "fallback-codex-exec" | "human-check";
29
37
  /** Receipt families persisted under the session storage dir. */
30
- export type ReceiptFamily = "vanish" | "prompt-acceptance" | "validation" | "completion" | "review-verdict" | "review-failure";
38
+ export type ReceiptFamily = "vanish" | "prompt-acceptance" | "validation" | "completion" | "review-verdict" | "review-failure" | "phase-rollup";
31
39
  /** The CLI verbs / primitives exposed by `gjc harness <verb>`. */
32
40
  export type HarnessVerb = "start" | "submit" | "observe" | "classify" | "recover" | "validate" | "finalize" | "retire" | "events" | "monitor" | "operate";
33
41
  /** Submission transports. */
@@ -7,7 +7,7 @@
7
7
  import type { Args } from "./cli/args";
8
8
  import { ModelRegistry } from "./config/model-registry";
9
9
  import { Settings } from "./config/settings";
10
- import { InteractiveMode, runAcpMode } from "./modes";
10
+ import type { InteractiveMode } from "./modes/interactive-mode";
11
11
  import type { SubmittedUserInput } from "./modes/types";
12
12
  import { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession, discoverAuthStorage } from "./sdk";
13
13
  import type { AgentSession } from "./session/agent-session";
@@ -51,7 +51,7 @@ export declare function createAcpSessionFactory(args: AcpSessionFactoryOptions):
51
51
  interface RunRootCommandDependencies {
52
52
  createAgentSession?: typeof createAgentSession;
53
53
  discoverAuthStorage?: typeof discoverAuthStorage;
54
- runAcpMode?: typeof runAcpMode;
54
+ runAcpMode?: (createSession: AcpSessionFactory) => Promise<void>;
55
55
  settings?: Settings;
56
56
  }
57
57
  export declare function runRootCommand(parsed: Args, rawArgs: string[], deps?: RunRootCommandDependencies): Promise<void>;