@gajae-code/coding-agent 0.4.4 → 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 (68) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/dist/types/cli/fast-help.d.ts +1 -0
  3. package/dist/types/cli/setup-cli.d.ts +2 -0
  4. package/dist/types/commands/harness.d.ts +3 -0
  5. package/dist/types/commands/setup.d.ts +6 -0
  6. package/dist/types/config/model-registry.d.ts +3 -0
  7. package/dist/types/config/models-config-schema.d.ts +5 -0
  8. package/dist/types/coordinator/contract.d.ts +1 -1
  9. package/dist/types/coordinator-mcp/server.d.ts +8 -2
  10. package/dist/types/harness-control-plane/finalize.d.ts +5 -0
  11. package/dist/types/harness-control-plane/phase-rollup.d.ts +23 -0
  12. package/dist/types/harness-control-plane/receipt-ingest.d.ts +19 -0
  13. package/dist/types/harness-control-plane/receipts.d.ts +46 -0
  14. package/dist/types/harness-control-plane/rpc-adapter.d.ts +3 -0
  15. package/dist/types/harness-control-plane/types.d.ts +9 -1
  16. package/dist/types/main.d.ts +2 -2
  17. package/dist/types/modes/utils/abort-message.d.ts +4 -0
  18. package/dist/types/session/session-manager.d.ts +8 -0
  19. package/dist/types/setup/hermes-setup.d.ts +7 -0
  20. package/dist/types/task/fork-context-advisory.d.ts +13 -0
  21. package/dist/types/task/receipt.d.ts +1 -0
  22. package/dist/types/task/roi-reconciliation.d.ts +27 -0
  23. package/dist/types/task/types.d.ts +10 -0
  24. package/package.json +8 -7
  25. package/scripts/build-binary.ts +4 -0
  26. package/src/cli/fast-help.ts +80 -0
  27. package/src/cli/setup-cli.ts +12 -3
  28. package/src/cli.ts +107 -16
  29. package/src/commands/coordinator.ts +44 -1
  30. package/src/commands/harness.ts +92 -9
  31. package/src/commands/mcp-serve.ts +3 -2
  32. package/src/commands/setup.ts +4 -0
  33. package/src/config/models-config-schema.ts +1 -0
  34. package/src/coordinator/contract.ts +1 -0
  35. package/src/coordinator-mcp/server.ts +385 -182
  36. package/src/cursor.ts +30 -2
  37. package/src/gjc-runtime/launch-worktree.ts +12 -1
  38. package/src/gjc-runtime/session-state-sidecar.ts +38 -0
  39. package/src/harness-control-plane/finalize.ts +39 -5
  40. package/src/harness-control-plane/owner.ts +9 -1
  41. package/src/harness-control-plane/phase-rollup.ts +96 -0
  42. package/src/harness-control-plane/receipt-ingest.ts +127 -0
  43. package/src/harness-control-plane/receipts.ts +229 -1
  44. package/src/harness-control-plane/rpc-adapter.ts +8 -0
  45. package/src/harness-control-plane/types.ts +29 -1
  46. package/src/internal-urls/docs-index.generated.ts +6 -5
  47. package/src/main.ts +7 -3
  48. package/src/modes/components/status-line.ts +6 -6
  49. package/src/modes/controllers/event-controller.ts +5 -4
  50. package/src/modes/interactive-mode.ts +4 -5
  51. package/src/modes/print-mode.ts +1 -1
  52. package/src/modes/theme/theme.ts +2 -2
  53. package/src/modes/utils/abort-message.ts +41 -0
  54. package/src/modes/utils/context-usage.ts +15 -8
  55. package/src/modes/utils/ui-helpers.ts +5 -6
  56. package/src/sdk.ts +9 -4
  57. package/src/session/agent-session.ts +16 -5
  58. package/src/session/session-manager.ts +20 -0
  59. package/src/setup/hermes/templates/operator-instructions.v1.md +3 -2
  60. package/src/setup/hermes-setup.ts +63 -8
  61. package/src/task/fork-context-advisory.ts +99 -0
  62. package/src/task/index.ts +31 -2
  63. package/src/task/receipt.ts +2 -0
  64. package/src/task/roi-reconciliation.ts +90 -0
  65. package/src/task/types.ts +7 -0
  66. package/src/tools/index.ts +2 -2
  67. package/src/tools/subagent-render.ts +10 -1
  68. 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
@@ -0,0 +1 @@
1
+ export declare function getExtraHelpText(): string;
@@ -18,6 +18,8 @@ export interface SetupCommandArgs {
18
18
  repo?: string;
19
19
  profile?: string;
20
20
  sessionCommand?: string;
21
+ noWorktree?: boolean;
22
+ worktreeName?: string;
21
23
  stateRoot?: string;
22
24
  mutation?: string[];
23
25
  artifactByteCap?: string;
@@ -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;
@@ -43,6 +43,12 @@ export default class Setup extends Command {
43
43
  "session-command": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
44
44
  description: string;
45
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
+ };
46
52
  "state-root": import("@gajae-code/utils/cli").FlagDescriptor<"string"> & {
47
53
  description: string;
48
54
  };
@@ -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<{
@@ -1,4 +1,4 @@
1
1
  export declare const COORDINATOR_MCP_PROTOCOL_VERSION = "2024-11-05";
2
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_start_session", "gjc_coordinator_send_prompt", "gjc_coordinator_submit_question_answer", "gjc_coordinator_read_turn", "gjc_coordinator_await_turn", "gjc_coordinator_report_status"];
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
4
  export type CoordinatorToolName = (typeof COORDINATOR_MCP_TOOL_NAMES)[number];
@@ -8,10 +8,11 @@ interface JsonRpcRequest {
8
8
  method: string;
9
9
  params?: unknown;
10
10
  }
11
+ type JsonRpcResult = any;
11
12
  interface JsonRpcResponse {
12
13
  jsonrpc: "2.0";
13
14
  id: string | number | null;
14
- result?: any;
15
+ result?: JsonRpcResult;
15
16
  error?: {
16
17
  code: number;
17
18
  message: string;
@@ -30,6 +31,11 @@ interface SessionStartInput {
30
31
  interface CoordinatorServices {
31
32
  listSessions?: () => unknown[] | Promise<unknown[]>;
32
33
  startSession?: (input: SessionStartInput) => unknown | Promise<unknown>;
34
+ commandRunner?: (command: string[]) => Promise<{
35
+ exitCode: number;
36
+ stdout: string;
37
+ stderr: string;
38
+ }>;
33
39
  }
34
40
  interface CoordinatorMcpServerOptions {
35
41
  env?: NodeJS.ProcessEnv;
@@ -48,5 +54,5 @@ export declare function createCoordinatorMcpServer(options?: CoordinatorMcpServe
48
54
  handleJsonRpc: (request: JsonRpcRequest) => Promise<JsonRpcResponse>;
49
55
  handle: (request: JsonRpcRequest) => Promise<JsonRpcResponse>;
50
56
  };
51
- export declare function handleCoordinatorMcpRequest(request: JsonRpcRequest, options?: LegacyHandlerOptions): Promise<any>;
57
+ export declare function handleCoordinatorMcpRequest(request: JsonRpcRequest, options?: LegacyHandlerOptions): Promise<JsonRpcResponse>;
52
58
  export declare function runCoordinatorMcpStdio(options?: CoordinatorMcpServerOptions): Promise<void>;
@@ -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>;
@@ -0,0 +1,4 @@
1
+ export declare function buildAbortDisplayMessage({ errorMessage, retryAttempt }: {
2
+ errorMessage?: string;
3
+ retryAttempt: number;
4
+ }): string;
@@ -401,6 +401,14 @@ export declare class SessionManager {
401
401
  appendCompaction<T = unknown>(summary: string, shortSummary: string | undefined, firstKeptEntryId: string, tokensBefore: number, details?: T, fromExtension?: boolean, preserveData?: Record<string, unknown>): string;
402
402
  /** Append a custom entry (for extensions) as child of current leaf, then advance leaf. Returns entry id. */
403
403
  appendCustomEntry(customType: string, data?: unknown): string;
404
+ /**
405
+ * Write mutated message entries back into the canonical entry store by id.
406
+ *
407
+ * `getBranch()` materializes resident-blob entries into copies, so in-place
408
+ * mutation of returned entries (e.g. pruning tool outputs) does not affect
409
+ * the canonical store. This applies such mutations for real.
410
+ */
411
+ applyEntryMessageUpdates(entries: readonly SessionMessageEntry[]): void;
404
412
  /**
405
413
  * Rewrite the session file after in-place entry updates.
406
414
  * Use sparingly (e.g., pruning old tool outputs).
@@ -11,6 +11,8 @@ export interface HermesSetupFlags {
11
11
  repo?: string;
12
12
  profile?: string;
13
13
  sessionCommand?: string;
14
+ noWorktree?: boolean;
15
+ worktreeName?: string;
14
16
  stateRoot?: string;
15
17
  mutation?: string[];
16
18
  artifactByteCap?: string;
@@ -33,6 +35,11 @@ export interface CoordinatorSetupSpec {
33
35
  repo?: string;
34
36
  };
35
37
  sessionCommand?: string;
38
+ sessionCommandSource: "default" | "explicit";
39
+ worktree: {
40
+ enabled: boolean;
41
+ name?: string;
42
+ };
36
43
  stateRoot?: string;
37
44
  mutationPolicy: {
38
45
  classes: HermesMutationClass[];
@@ -0,0 +1,13 @@
1
+ import type { ForkContextMode } from "./types";
2
+ export interface ForkContextAdvisory {
3
+ recommendedMode: ForkContextMode;
4
+ reasons: string[];
5
+ estimatedClonedTokens: Record<ForkContextMode, number>;
6
+ callerModeRespected: true;
7
+ }
8
+ export declare function adviseForkContextMode(input: {
9
+ assignment: string;
10
+ context?: string;
11
+ explicitMode?: ForkContextMode;
12
+ parentContextTokens?: number;
13
+ }): ForkContextAdvisory;
@@ -56,6 +56,7 @@ export interface TaskResultReceipt {
56
56
  };
57
57
  extractedToolCounts?: Record<string, number>;
58
58
  forkContext?: SingleResult["forkContext"];
59
+ forkContextAdvisory?: SingleResult["forkContextAdvisory"];
59
60
  roi?: TaskRoi;
60
61
  }
61
62
  /**
@@ -0,0 +1,27 @@
1
+ import type { TaskResultReceipt } from "./receipt";
2
+ import type { SpawnPlanReceipt } from "./spawn-gate";
3
+ /**
4
+ * Pure, advisory-only reconciliation between a spawn plan's inline-token promise
5
+ * and receipt-safe child outputs. These signals never change task success/failure
6
+ * semantics or runtime behavior; they only describe budget/ROI observations for
7
+ * model-facing summaries.
8
+ */
9
+ export interface SpawnRoiChildReconciliation {
10
+ id: string;
11
+ inlineTokens: number;
12
+ maxInlineTokens: number;
13
+ overBudget: boolean;
14
+ overageTokens: number;
15
+ lowRoi: boolean;
16
+ }
17
+ export interface SpawnRoiReconciliation {
18
+ childCount: number;
19
+ promisedMaxInlineTokens: number;
20
+ children: SpawnRoiChildReconciliation[];
21
+ overBudgetChildIds: string[];
22
+ lowRoiChildIds: string[];
23
+ totalInlineTokens: number;
24
+ totalOverageTokens: number;
25
+ advisoryFlags: string[];
26
+ }
27
+ export declare function reconcileSpawnRoi(plan: SpawnPlanReceipt | undefined, receipts: readonly TaskResultReceipt[]): SpawnRoiReconciliation | undefined;
@@ -2,6 +2,7 @@ import type { ThinkingLevel } from "@gajae-code/agent-core";
2
2
  import type { Usage } from "@gajae-code/ai";
3
3
  import * as z from "zod/v4";
4
4
  import type { TaskResultReceipt } from "./receipt";
5
+ import type { SpawnRoiReconciliation } from "./roi-reconciliation";
5
6
  import { type TaskSimpleMode } from "./simple-mode";
6
7
  import type { SpawnPlanReceipt } from "./spawn-gate";
7
8
  import type { NestedRepoPatch } from "./worktree";
@@ -413,6 +414,14 @@ export interface SingleResult {
413
414
  mode: ForkContextMode;
414
415
  clonedTokens: number;
415
416
  };
417
+ /**
418
+ * Advisory fork-context mode recommendation for this task (logged only;
419
+ * never changes the actual mode selection).
420
+ */
421
+ forkContextAdvisory?: {
422
+ recommendedMode: ForkContextMode;
423
+ reasons: string[];
424
+ };
416
425
  }
417
426
  /** Tool details for TUI rendering */
418
427
  export interface TaskToolDetails {
@@ -431,6 +440,7 @@ export interface TaskToolDetails {
431
440
  /** Advisory ids for terminal children that spent tokens without detectable output/review/changes. */
432
441
  lowRoiChildIds: string[];
433
442
  };
443
+ roiReconciliation?: SpawnRoiReconciliation;
434
444
  progress?: AgentProgress[];
435
445
  async?: {
436
446
  state: "running" | "paused" | "queued" | "completed" | "failed";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@gajae-code/coding-agent",
4
- "version": "0.4.4",
4
+ "version": "0.4.5",
5
5
  "description": "Gajae Code CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://gaebal-gajae.dev",
7
7
  "author": "Yeachan-Heo",
@@ -36,6 +36,7 @@
36
36
  "check:types": "tsgo -p tsconfig.json --noEmit",
37
37
  "lint": "biome lint .",
38
38
  "test": "bun test",
39
+ "bench:context": "bun run bench/context-optimization.bench.ts",
39
40
  "generate-schemas": "bun ../../scripts/generate-json-schemas.ts",
40
41
  "check:schemas": "bun ../../scripts/generate-json-schemas.ts --check",
41
42
  "fix": "biome check --write --unsafe . && bun run format-prompts && bun run generate-docs-index",
@@ -50,12 +51,12 @@
50
51
  "@agentclientprotocol/sdk": "0.21.0",
51
52
  "@babel/parser": "^7.29.3",
52
53
  "@mozilla/readability": "^0.6.0",
53
- "@gajae-code/stats": "0.4.4",
54
- "@gajae-code/agent-core": "0.4.4",
55
- "@gajae-code/ai": "0.4.4",
56
- "@gajae-code/natives": "0.4.4",
57
- "@gajae-code/tui": "0.4.4",
58
- "@gajae-code/utils": "0.4.4",
54
+ "@gajae-code/stats": "0.4.5",
55
+ "@gajae-code/agent-core": "0.4.5",
56
+ "@gajae-code/ai": "0.4.5",
57
+ "@gajae-code/natives": "0.4.5",
58
+ "@gajae-code/tui": "0.4.5",
59
+ "@gajae-code/utils": "0.4.5",
59
60
  "@puppeteer/browsers": "^2.13.0",
60
61
  "@types/turndown": "5.0.6",
61
62
  "@xterm/headless": "^6.0.0",
@@ -39,6 +39,10 @@ async function main(): Promise<void> {
39
39
  "bun",
40
40
  "build",
41
41
  "--compile",
42
+ // Minify shrinks the bundled JS the compiled binary must parse at
43
+ // startup (302MB → ~114MB --help RSS measured on darwin-arm64).
44
+ // --keep-names below preserves identifiers for error reports.
45
+ "--minify",
42
46
  "--no-compile-autoload-bunfig",
43
47
  "--no-compile-autoload-dotenv",
44
48
  "--no-compile-autoload-tsconfig",
@@ -0,0 +1,80 @@
1
+ import { APP_NAME, CONFIG_DIR_NAME } from "@gajae-code/utils/dirs";
2
+
3
+ export function getExtraHelpText(): string {
4
+ return `Environment Variables:
5
+ # Core Providers
6
+ ANTHROPIC_API_KEY - Anthropic Claude models
7
+ ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth (takes precedence over API key)
8
+ CLAUDE_CODE_USE_FOUNDRY - Enable Anthropic Foundry mode (uses Foundry endpoint + mTLS)
9
+ FOUNDRY_BASE_URL - Anthropic Foundry base URL (e.g., https://<foundry-host>)
10
+ ANTHROPIC_FOUNDRY_API_KEY - Anthropic token used as Authorization: Bearer <token> in Foundry mode
11
+ ANTHROPIC_CUSTOM_HEADERS - Extra Foundry headers (e.g., "user-id: USERNAME")
12
+ CLAUDE_CODE_CLIENT_CERT - Client certificate (PEM path or inline PEM) for mTLS
13
+ CLAUDE_CODE_CLIENT_KEY - Client private key (PEM path or inline PEM) for mTLS
14
+ NODE_EXTRA_CA_CERTS - CA bundle path (or inline PEM) for server certificate validation
15
+ OPENAI_API_KEY - OpenAI GPT models
16
+ GEMINI_API_KEY - Google Gemini models
17
+ GITHUB_TOKEN - GitHub Copilot (or GH_TOKEN, COPILOT_GITHUB_TOKEN)
18
+
19
+ # Additional LLM Providers
20
+ AZURE_OPENAI_API_KEY - Azure OpenAI models
21
+ GROQ_API_KEY - Groq models
22
+ CEREBRAS_API_KEY - Cerebras models
23
+ XAI_API_KEY - xAI Grok models
24
+ OPENROUTER_API_KEY - OpenRouter aggregated models
25
+ KILO_API_KEY - Kilo Gateway models
26
+ MISTRAL_API_KEY - Mistral models
27
+ ZAI_API_KEY - z.ai models (ZhipuAI/GLM)
28
+ MINIMAX_API_KEY - MiniMax models
29
+ OPENCODE_API_KEY - OpenCode Zen/OpenCode Go models
30
+ CURSOR_ACCESS_TOKEN - Cursor AI models
31
+ AI_GATEWAY_API_KEY - Vercel AI Gateway
32
+
33
+ # Cloud Providers
34
+ AWS_PROFILE - AWS Bedrock (or AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY)
35
+ GOOGLE_CLOUD_PROJECT - Google Vertex AI (requires GOOGLE_CLOUD_LOCATION)
36
+ GOOGLE_APPLICATION_CREDENTIALS - Service account for Vertex AI
37
+
38
+ # Search & Tools
39
+ EXA_API_KEY - Exa web search
40
+ BRAVE_API_KEY - Brave web search
41
+ PERPLEXITY_API_KEY - Perplexity web search (API)
42
+ PERPLEXITY_COOKIES - Perplexity web search (session cookie)
43
+ TAVILY_API_KEY - Tavily web search
44
+ ANTHROPIC_SEARCH_API_KEY - Anthropic search provider
45
+
46
+ # Configuration
47
+ GJC_CODING_AGENT_DIR - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)
48
+ GJC_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
49
+ GJC_SMOL_MODEL - Override smol/fast model (see --smol)
50
+ GJC_SLOW_MODEL - Override slow/reasoning model (see --slow)
51
+ GJC_PLAN_MODEL - Override planning model (see --plan)
52
+ GJC_NO_PTY - Disable PTY-based interactive bash execution
53
+ --tmux - Launch interactive startup inside a new tmux session
54
+ gjc session - List, inspect, create, remove, or attach tagged GJC-managed tmux sessions
55
+ GJC_LAUNCH_POLICY - Launch policy for --tmux startup: tmux or direct
56
+ GJC_TMUX_SESSION - Explicit tmux session name override for --tmux startup
57
+
58
+ For complete environment variable reference, see:
59
+ docs/environment-variables.md
60
+ Available Tools (default-enabled unless noted):
61
+ read - Read file contents
62
+ bash - Execute bash commands
63
+ edit - Edit files with find/replace
64
+ write - Write files (creates/overwrites)
65
+ grep - Search file contents
66
+ find - Find files by glob pattern
67
+ lsp - Language server protocol (code intelligence)
68
+ python - Execute Python code (requires: ${APP_NAME} setup python)
69
+ notebook - Edit Jupyter notebooks
70
+ inspect_image - Analyze images with a vision model
71
+ browser - Browser automation (Puppeteer)
72
+ task - Launch sub-agents for parallel tasks
73
+ todo_write - Manage todo/task lists
74
+ web_search - Search the web
75
+ ask - Ask user questions (interactive mode only)
76
+
77
+ Useful Commands:
78
+ ${APP_NAME} --list-models - List configured provider models
79
+ ${APP_NAME} --help - Show this help`;
80
+ }