@gajae-code/coding-agent 0.11.7 → 0.11.8

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 (180) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/types/cli/args.d.ts +0 -2
  3. package/dist/types/config/keybindings.d.ts +33 -3
  4. package/dist/types/config/model-profile-activation.d.ts +4 -3
  5. package/dist/types/config/model-profile-contract.d.ts +38 -0
  6. package/dist/types/config/settings-schema.d.ts +15 -2
  7. package/dist/types/edit/modes/patch.d.ts +13 -0
  8. package/dist/types/edit/path-mutation-lock.d.ts +15 -0
  9. package/dist/types/eval/py/executor.d.ts +1 -1
  10. package/dist/types/eval/py/tool-bridge.d.ts +1 -2
  11. package/dist/types/gjc-runtime/repository-binding.d.ts +63 -0
  12. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +1 -0
  13. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +24 -0
  14. package/dist/types/main.d.ts +8 -0
  15. package/dist/types/modes/components/runtime-mcp-add-wizard.d.ts +2 -1
  16. package/dist/types/modes/components/tool-status-header.d.ts +3 -2
  17. package/dist/types/modes/components/welcome.d.ts +2 -0
  18. package/dist/types/modes/controllers/command-controller.d.ts +2 -0
  19. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  20. package/dist/types/modes/interactive-mode.d.ts +5 -2
  21. package/dist/types/modes/prompt-action-autocomplete.d.ts +6 -1
  22. package/dist/types/modes/prompt-suggestion-controller.d.ts +35 -0
  23. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +2 -2
  24. package/dist/types/modes/types.d.ts +3 -0
  25. package/dist/types/modes/utils/hotkeys-markdown.d.ts +2 -1
  26. package/dist/types/runtime-mcp/manager.d.ts +1 -1
  27. package/dist/types/runtime-mcp/oauth-flow.d.ts +0 -5
  28. package/dist/types/runtime-mcp/plugin-network-boundary.d.ts +14 -0
  29. package/dist/types/sdk/broker/broker.d.ts +2 -0
  30. package/dist/types/sdk/broker/lifecycle.d.ts +6 -0
  31. package/dist/types/sdk/bus/chat-daemon-control.d.ts +5 -1
  32. package/dist/types/sdk/bus/config-commands.d.ts +2 -2
  33. package/dist/types/sdk/bus/config.d.ts +2 -0
  34. package/dist/types/sdk/bus/conversation-store.d.ts +1 -0
  35. package/dist/types/sdk/bus/index.d.ts +25 -0
  36. package/dist/types/sdk/bus/notification-orchestration.d.ts +1 -0
  37. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +105 -0
  38. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +13 -3
  39. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -1
  40. package/dist/types/sdk/bus/telegram-daemon.d.ts +128 -1
  41. package/dist/types/sdk/bus/telegram-reference.d.ts +2 -0
  42. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  43. package/dist/types/sdk/host/host.d.ts +1 -1
  44. package/dist/types/sdk/host/query/handlers.d.ts +9 -0
  45. package/dist/types/sdk/index.d.ts +2 -0
  46. package/dist/types/sdk/prompt-status.d.ts +88 -0
  47. package/dist/types/sdk/session-directory.d.ts +1 -1
  48. package/dist/types/sdk/startup-capability.d.ts +3 -0
  49. package/dist/types/session/agent-session.d.ts +2 -0
  50. package/dist/types/session/internal/managed-session-scope.d.ts +11 -2
  51. package/dist/types/session/internal/managed-session-storage.d.ts +17 -2
  52. package/dist/types/session/internal/native-publish-outcome.d.ts +48 -0
  53. package/dist/types/session/session-storage.d.ts +18 -0
  54. package/dist/types/task/index.d.ts +3 -1
  55. package/dist/types/task/receipt.d.ts +2 -0
  56. package/dist/types/task/types.d.ts +94 -0
  57. package/dist/types/tools/ask.d.ts +454 -174
  58. package/dist/types/tools/image-gen.d.ts +47 -1
  59. package/dist/types/tools/index.d.ts +4 -0
  60. package/dist/types/utils/prompt-suggestion.d.ts +33 -0
  61. package/package.json +8 -8
  62. package/scripts/capture-platform-shortcut-labels-showcase.ts +342 -0
  63. package/scripts/dogfood-repository-binding.ts +209 -0
  64. package/scripts/generate-sdk-operation-inventory.ts +2 -0
  65. package/scripts/run-test-manifest.ts +4 -4
  66. package/src/cli/args.ts +2 -92
  67. package/src/cli/notify-cli.ts +5 -38
  68. package/src/cli.ts +18 -0
  69. package/src/commands/sdk.ts +2 -2
  70. package/src/config/keybindings.ts +157 -24
  71. package/src/config/model-profile-activation.ts +7 -18
  72. package/src/config/model-profile-contract.ts +161 -0
  73. package/src/config/model-registry.ts +11 -1
  74. package/src/config/settings-schema.ts +17 -2
  75. package/src/coordinator-mcp/model-preset.ts +21 -74
  76. package/src/defaults/gjc/skills/deep-interview/SKILL.md +2 -2
  77. package/src/defaults/gjc/skills/ralplan/SKILL.md +3 -1
  78. package/src/edit/index.ts +3 -6
  79. package/src/edit/modes/patch.ts +38 -1
  80. package/src/edit/modes/replace.ts +42 -0
  81. package/src/edit/path-mutation-lock.ts +112 -0
  82. package/src/eval/py/executor.ts +30 -11
  83. package/src/eval/py/prelude.py +2 -2
  84. package/src/eval/py/tool-bridge.ts +34 -18
  85. package/src/extensibility/gjc-plugins/runtime-adapters.ts +2 -1
  86. package/src/gjc-runtime/launch-tmux.ts +1 -1
  87. package/src/gjc-runtime/managed-owner-supervisor.ts +83 -4
  88. package/src/gjc-runtime/ralplan-runtime.ts +75 -3
  89. package/src/gjc-runtime/repository-binding.ts +267 -0
  90. package/src/gjc-runtime/session-state-sidecar.ts +25 -9
  91. package/src/gjc-runtime/tmux-owner-isolation.ts +2 -1
  92. package/src/gjc-runtime/tmux-sessions.ts +45 -6
  93. package/src/gjc-runtime/ultragoal-guard.ts +5 -5
  94. package/src/gjc-runtime/ultragoal-runtime.ts +181 -19
  95. package/src/internal-urls/docs-index.generated.ts +6 -5
  96. package/src/internal-urls/local-protocol.ts +33 -16
  97. package/src/internal-urls/mcp-protocol.ts +73 -11
  98. package/src/main.ts +25 -10
  99. package/src/modes/DESIGN.md +5 -0
  100. package/src/modes/acp/acp-agent.ts +50 -16
  101. package/src/modes/components/model-selector.ts +42 -8
  102. package/src/modes/components/plan-preview-overlay.ts +1 -1
  103. package/src/modes/components/runtime-mcp-add-wizard.ts +5 -0
  104. package/src/modes/components/tool-status-header.ts +20 -4
  105. package/src/modes/components/welcome.ts +22 -18
  106. package/src/modes/controllers/command-controller.ts +97 -54
  107. package/src/modes/controllers/event-controller.ts +10 -0
  108. package/src/modes/controllers/input-controller.ts +7 -2
  109. package/src/modes/controllers/runtime-mcp-command-controller.ts +29 -6
  110. package/src/modes/controllers/selector-controller.ts +46 -54
  111. package/src/modes/interactive-mode.ts +41 -27
  112. package/src/modes/prompt-action-autocomplete.ts +32 -13
  113. package/src/modes/prompt-suggestion-controller.ts +96 -0
  114. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +2 -2
  115. package/src/modes/types.ts +3 -0
  116. package/src/modes/utils/hotkeys-markdown.ts +64 -36
  117. package/src/modes/utils/ui-helpers.ts +5 -3
  118. package/src/prompts/agents/architect.md +0 -1
  119. package/src/prompts/agents/critic.md +0 -1
  120. package/src/prompts/system/prompt-suggestion-system.md +32 -0
  121. package/src/prompts/system/system-prompt.md +6 -4
  122. package/src/prompts/tools/cron.md +3 -1
  123. package/src/runtime-mcp/manager.ts +51 -53
  124. package/src/runtime-mcp/oauth-flow.ts +0 -72
  125. package/src/runtime-mcp/plugin-network-boundary.ts +101 -0
  126. package/src/runtime-mcp/transports/http.ts +13 -6
  127. package/src/sdk/broker/broker.ts +34 -20
  128. package/src/sdk/broker/lifecycle.ts +185 -36
  129. package/src/sdk/bus/chat-daemon-control.ts +18 -5
  130. package/src/sdk/bus/config-commands.ts +2 -2
  131. package/src/sdk/bus/config.ts +9 -1
  132. package/src/sdk/bus/conversation-store.ts +40 -6
  133. package/src/sdk/bus/index.ts +240 -65
  134. package/src/sdk/bus/lifecycle-commands.ts +47 -3
  135. package/src/sdk/bus/lifecycle-control-runtime.ts +11 -2
  136. package/src/sdk/bus/lifecycle-orchestrator.ts +32 -1
  137. package/src/sdk/bus/notification-orchestration.ts +12 -0
  138. package/src/sdk/bus/notification-service.ts +27 -2
  139. package/src/sdk/bus/prompt-reconciliation.ts +239 -0
  140. package/src/sdk/bus/recent-activity.ts +90 -26
  141. package/src/sdk/bus/telegram-daemon-contract.ts +13 -3
  142. package/src/sdk/bus/telegram-daemon-control.ts +145 -33
  143. package/src/sdk/bus/telegram-daemon.ts +835 -110
  144. package/src/sdk/bus/telegram-reference.ts +20 -2
  145. package/src/sdk/cli/session-cli.ts +15 -2
  146. package/src/sdk/host/control/dispatch.ts +1 -1
  147. package/src/sdk/host/control/operations.ts +1 -1
  148. package/src/sdk/host/host.ts +2 -6
  149. package/src/sdk/host/query/handlers.ts +70 -5
  150. package/src/sdk/index.ts +12 -0
  151. package/src/sdk/prompt-status.ts +97 -0
  152. package/src/sdk/protocol/operation-inventory.generated.json +47 -0
  153. package/src/sdk/protocol/operation-registry.ts +18 -4
  154. package/src/sdk/session-directory.ts +5 -1
  155. package/src/sdk/session.ts +2 -0
  156. package/src/sdk/startup-capability.ts +9 -1
  157. package/src/session/agent-session.ts +52 -5
  158. package/src/session/blob-store.ts +7 -2
  159. package/src/session/internal/managed-session-scope.ts +854 -84
  160. package/src/session/internal/managed-session-storage.ts +251 -199
  161. package/src/session/internal/native-publish-outcome.ts +266 -0
  162. package/src/session/session-manager.ts +310 -327
  163. package/src/session/session-storage.ts +128 -11
  164. package/src/task/gjc-command.ts +2 -2
  165. package/src/task/index.ts +121 -15
  166. package/src/task/receipt.ts +3 -0
  167. package/src/task/types.ts +34 -3
  168. package/src/tools/ask.ts +198 -88
  169. package/src/tools/ast-edit.ts +2 -2
  170. package/src/tools/bash-pty-selection.ts +2 -2
  171. package/src/tools/browser/screenshot-format.ts +6 -1
  172. package/src/tools/cron.ts +1 -1
  173. package/src/tools/image-gen.ts +178 -6
  174. package/src/tools/index.ts +4 -0
  175. package/src/tools/render-utils.ts +7 -1
  176. package/src/utils/edit-mode.ts +2 -2
  177. package/src/utils/prompt-suggestion.ts +265 -0
  178. package/src/utils/sixel.ts +3 -3
  179. package/src/web/insane/url-guard.ts +3 -1
  180. package/src/web/scrapers/docs-rs.ts +30 -5
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Product-surface dogfood for #2901 repository binding.
3
+ *
4
+ * Creates two sibling git repos, runs real `gjc ultragoal` / `gjc ralplan`
5
+ * CLI entrypoints from source, and prints fail-closed mismatch evidence.
6
+ *
7
+ * Usage (from monorepo root):
8
+ * bun packages/coding-agent/scripts/dogfood-repository-binding.ts
9
+ */
10
+ import * as fsp from "node:fs/promises";
11
+ import * as os from "node:os";
12
+ import * as path from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ import {
15
+ assertCwdMatchesRepositoryBinding,
16
+ assertPathUnderRepositoryBinding,
17
+ parseRepositoryBinding,
18
+ resolveTaskRepositoryBinding,
19
+ } from "../src/gjc-runtime/repository-binding";
20
+ import { readUltragoalPlan, startNextUltragoalGoal } from "../src/gjc-runtime/ultragoal-runtime";
21
+
22
+ const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
23
+ const cli = path.join(repoRoot, "packages/coding-agent/src/cli.ts");
24
+
25
+ async function runGit(cwd: string, args: string[]): Promise<void> {
26
+ const proc = Bun.spawn(["git", ...args], { cwd, stdout: "pipe", stderr: "pipe" });
27
+ const code = await proc.exited;
28
+ if (code !== 0) throw new Error(`git ${args.join(" ")} failed: ${await new Response(proc.stderr).text()}`);
29
+ }
30
+
31
+ async function initRepo(root: string): Promise<void> {
32
+ await fsp.mkdir(root, { recursive: true });
33
+ await runGit(root, ["init"]);
34
+ await runGit(root, ["config", "user.email", "dogfood@example.com"]);
35
+ await runGit(root, ["config", "user.name", "Dogfood"]);
36
+ await fsp.writeFile(path.join(root, "README.md"), `repo ${path.basename(root)}\n`);
37
+ await runGit(root, ["add", "README.md"]);
38
+ await runGit(root, ["commit", "-m", `init ${path.basename(root)}`]);
39
+ }
40
+
41
+ async function runCli(
42
+ cwd: string,
43
+ args: string[],
44
+ env: NodeJS.ProcessEnv,
45
+ ): Promise<{ code: number; stdout: string; stderr: string }> {
46
+ const proc = Bun.spawn(["bun", cli, ...args], { cwd, env, stdout: "pipe", stderr: "pipe" });
47
+ const [code, stdout, stderr] = await Promise.all([
48
+ proc.exited,
49
+ new Response(proc.stdout).text(),
50
+ new Response(proc.stderr).text(),
51
+ ]);
52
+ return { code, stdout, stderr };
53
+ }
54
+
55
+ async function main(): Promise<void> {
56
+ const dogfoodRoot = await fsp.mkdtemp(path.join(os.tmpdir(), "gjc-dogfood-2901-"));
57
+ const left = path.join(dogfoodRoot, "gajae-code");
58
+ const right = path.join(dogfoodRoot, "oh-my-openagent-senpi");
59
+ await initRepo(left);
60
+ await initRepo(right);
61
+
62
+ const sessionId = `dogfood-2901-${process.pid}`;
63
+ const env = { ...process.env, GJC_SESSION_ID: sessionId };
64
+
65
+ console.log("# Dogfood: repository binding (#2901)");
66
+ console.log(`root=${dogfoodRoot}`);
67
+ console.log(`left=${left}`);
68
+ console.log(`right=${right}`);
69
+ console.log(`session=${sessionId}`);
70
+ console.log(`cli=${cli}`);
71
+ console.log(`bun=${Bun.version}`);
72
+ console.log(
73
+ `commit=${Bun.spawnSync(["git", "-C", repoRoot, "rev-parse", "--short", "HEAD"]).stdout.toString().trim()}`,
74
+ );
75
+ console.log();
76
+
77
+ // 1) Product CLI: create goals stamps binding
78
+ const create = await runCli(
79
+ left,
80
+ [
81
+ "ultragoal",
82
+ "create-goals",
83
+ "--brief",
84
+ "@goal dogfood binding\nProve repository binding stamps and fail-closed sibling mismatch.",
85
+ "--json",
86
+ ],
87
+ env,
88
+ );
89
+ console.log("## 1) gjc ultragoal create-goals (LEFT)");
90
+ console.log(`exit=${create.code}`);
91
+ console.log(create.stdout.trim() || create.stderr.trim());
92
+ if (create.code !== 0) process.exit(1);
93
+
94
+ const plan = await readUltragoalPlan(left, sessionId);
95
+ if (!plan?.repositoryBinding) {
96
+ console.error("FAIL: plan missing repositoryBinding");
97
+ process.exit(1);
98
+ }
99
+ console.log();
100
+ console.log("## 2) goals.json repositoryBinding");
101
+ console.log(JSON.stringify(plan.repositoryBinding, null, 2));
102
+
103
+ // 2) Matching cwd starts goal
104
+ console.log();
105
+ console.log("## 3) startNextUltragoalGoal on LEFT (match)");
106
+ const started = await startNextUltragoalGoal({ cwd: left, sessionId });
107
+ console.log(`ok goal=${started.goal?.id} status=${started.goal?.status}`);
108
+
109
+ // 3) Sibling mismatch fails closed
110
+ console.log();
111
+ console.log("## 4) assertCwdMatchesRepositoryBinding on RIGHT (sibling)");
112
+ try {
113
+ await assertCwdMatchesRepositoryBinding(right, plan.repositoryBinding);
114
+ console.error("FAIL: expected identity_mismatch");
115
+ process.exit(1);
116
+ } catch (error) {
117
+ console.log(`fail_closed: ${error instanceof Error ? error.message : String(error)}`);
118
+ }
119
+
120
+ // 4) Path escape fails closed
121
+ console.log();
122
+ console.log("## 5) assertPathUnderRepositoryBinding sibling absolute path");
123
+ try {
124
+ assertPathUnderRepositoryBinding(plan.repositoryBinding, path.join(right, "README.md"));
125
+ console.error("FAIL: expected path_outside_root");
126
+ process.exit(1);
127
+ } catch (error) {
128
+ console.log(`fail_closed: ${error instanceof Error ? error.message : String(error)}`);
129
+ }
130
+
131
+ // 5) Task binding stamp + sibling fail-closed (pre-discovery authority)
132
+ console.log();
133
+ console.log("## 6) task binding stamp (omit declaration) + sibling reject");
134
+ const stamped = await resolveTaskRepositoryBinding(left, undefined);
135
+ console.log(`stamped_worktreeRoot=${stamped.worktreeRoot}`);
136
+ await assertCwdMatchesRepositoryBinding(left, stamped);
137
+ console.log("task_stamp_ok on LEFT");
138
+ const taskBinding = parseRepositoryBinding(plan.repositoryBinding);
139
+ try {
140
+ await resolveTaskRepositoryBinding(right, taskBinding);
141
+ console.error("FAIL: task binding should reject RIGHT");
142
+ process.exit(1);
143
+ } catch (error) {
144
+ console.log(`task_binding_fail_closed on RIGHT: ${error instanceof Error ? error.message : String(error)}`);
145
+ }
146
+
147
+ // 6) Ralplan seed stamps binding via product CLI
148
+ console.log();
149
+ console.log("## 7) gjc ralplan seed (LEFT)");
150
+ const ralplan = await runCli(left, ["ralplan", "--json", "dogfood multi-repo binding"], env);
151
+ console.log(`exit=${ralplan.code}`);
152
+ console.log(ralplan.stdout.trim() || ralplan.stderr.trim());
153
+ if (ralplan.code !== 0) process.exit(1);
154
+ const statePath = path.join(left, ".gjc", `_session-${sessionId}`, "state", "ralplan-state.json");
155
+ const state = JSON.parse(await fsp.readFile(statePath, "utf8")) as {
156
+ repository_binding?: unknown;
157
+ run_id?: string;
158
+ };
159
+ console.log();
160
+ console.log("## 8) ralplan-state.json repository_binding");
161
+ console.log(JSON.stringify({ run_id: state.run_id, repository_binding: state.repository_binding }, null, 2));
162
+ if (!state.repository_binding) {
163
+ console.error("FAIL: ralplan state missing repository_binding");
164
+ process.exit(1);
165
+ }
166
+
167
+ // 7) Ralplan stage write on LEFT succeeds and echoes repository_binding
168
+ console.log();
169
+ console.log("## 9) gjc ralplan --write planner on LEFT (match)");
170
+ const notePath = path.join(left, "dogfood-planner.md");
171
+ await fsp.writeFile(notePath, "# dogfood planner\n");
172
+ const writeLeft = await runCli(
173
+ left,
174
+ ["ralplan", "--write", "--stage", "planner", "--stage_n", "1", "--artifact", notePath, "--json"],
175
+ env,
176
+ );
177
+ console.log(`exit=${writeLeft.code}`);
178
+ console.log(writeLeft.stdout.trim() || writeLeft.stderr.trim());
179
+ if (writeLeft.code !== 0) process.exit(1);
180
+ const writePayload = JSON.parse(writeLeft.stdout) as { repository_binding?: { worktreeRoot?: string } };
181
+ if (!writePayload.repository_binding?.worktreeRoot) {
182
+ console.error("FAIL: write receipt missing repository_binding");
183
+ process.exit(1);
184
+ }
185
+
186
+ // 8) Copy seed authority into RIGHT session layout → stage write fails closed
187
+ console.log();
188
+ console.log("## 10) ralplan --write on RIGHT with LEFT binding (fail-closed)");
189
+ const rightStateDir = path.join(right, ".gjc", `_session-${sessionId}`, "state");
190
+ await fsp.mkdir(rightStateDir, { recursive: true });
191
+ await fsp.copyFile(statePath, path.join(rightStateDir, "ralplan-state.json"));
192
+ const writeRight = await runCli(
193
+ right,
194
+ ["ralplan", "--write", "--stage", "architect", "--stage_n", "1", "--artifact", "# arch\n", "--json"],
195
+ env,
196
+ );
197
+ console.log(`exit=${writeRight.code}`);
198
+ console.log((writeRight.stderr || writeRight.stdout).trim());
199
+ if (writeRight.code === 0) {
200
+ console.error("FAIL: expected sibling write to fail closed");
201
+ process.exit(1);
202
+ }
203
+ console.log("fail_closed: ralplan write on sibling rejected");
204
+
205
+ console.log();
206
+ console.log("DOGFOOD_OK");
207
+ }
208
+
209
+ await main();
@@ -39,6 +39,8 @@ const LOCKED_EXCLUSIONS: Readonly<Record<string, string>> = {
39
39
  "agent_session:setForcedToolChoice": "internal accessor/plumbing, not a user-facing control seam",
40
40
  "agent_session:getActiveSkillState": "internal accessor/plumbing, not a user-facing control seam",
41
41
  "agent_session:getActiveSkillPhase": "internal accessor/plumbing, not a user-facing control seam",
42
+ "agent_session:getDeepInterviewAskStage":
43
+ "internal AskTool schema-selection accessor, not a user-facing SDK control seam",
42
44
  "agent_session:peekQueueInvoker": "internal accessor/plumbing, not a user-facing control seam",
43
45
  "agent_session:peekStandingResolveHandler": "internal accessor/plumbing, not a user-facing control seam",
44
46
  "agent_session:setStandingResolveHandler": "internal accessor/plumbing, not a user-facing control seam",
@@ -60,11 +60,11 @@ function validateRowReceipts(rows: ManifestAdapterRow[]): void {
60
60
  }
61
61
  counts.set(row.adapter, (counts.get(row.adapter) ?? 0) + 1);
62
62
  }
63
- if (rows.length !== ADAPTERS.length * 91)
64
- throw new Error(`Expected ${ADAPTERS.length * 91} adapter rows; received ${rows.length}.`);
63
+ if (rows.length !== ADAPTERS.length * 93)
64
+ throw new Error(`Expected ${ADAPTERS.length * 93} adapter rows; received ${rows.length}.`);
65
65
  for (const adapter of ADAPTERS) {
66
- if (counts.get(adapter) !== 91)
67
- throw new Error(`Expected 91 ${adapter} rows; received ${counts.get(adapter) ?? 0}.`);
66
+ if (counts.get(adapter) !== 93)
67
+ throw new Error(`Expected 93 ${adapter} rows; received ${counts.get(adapter) ?? 0}.`);
68
68
  }
69
69
  process.stdout.write(
70
70
  `manifest check: ${rows.length} row receipts (${[...counts].map(([adapter, count]) => `${adapter}=${count}`).join(", ")})\n`,
package/src/cli/args.ts CHANGED
@@ -1,11 +1,10 @@
1
1
  /**
2
- * CLI argument parsing and help display
2
+ * CLI argument parsing
3
3
  */
4
4
  import * as path from "node:path";
5
5
  import { type Effort, THINKING_EFFORTS } from "@gajae-code/ai";
6
- import { APP_NAME, CONFIG_DIR_NAME, logger } from "@gajae-code/utils";
6
+ import { logger } from "@gajae-code/utils";
7
7
  import { CliParseError } from "@gajae-code/utils/cli";
8
- import chalk from "chalk";
9
8
  import { parseEffort } from "../thinking";
10
9
  import { BUILTIN_TOOLS } from "../tools";
11
10
 
@@ -253,92 +252,3 @@ export function parseArgs(args: string[]): Args {
253
252
 
254
253
  return result;
255
254
  }
256
-
257
- export function getExtraHelpText(): string {
258
- return `${chalk.bold("Environment Variables:")}
259
- ${chalk.dim("# Core Providers")}
260
- ANTHROPIC_API_KEY - Anthropic Claude models
261
- ANTHROPIC_OAUTH_TOKEN - Anthropic OAuth (takes precedence over API key)
262
- CLAUDE_CODE_USE_FOUNDRY - Enable Anthropic Foundry mode (uses Foundry endpoint + mTLS)
263
- FOUNDRY_BASE_URL - Anthropic Foundry base URL (e.g., https://<foundry-host>)
264
- ANTHROPIC_FOUNDRY_API_KEY - Anthropic token used as Authorization: Bearer <token> in Foundry mode
265
- ANTHROPIC_CUSTOM_HEADERS - Extra Foundry headers (e.g., "user-id: USERNAME")
266
- CLAUDE_CODE_CLIENT_CERT - Client certificate (PEM path or inline PEM) for mTLS
267
- CLAUDE_CODE_CLIENT_KEY - Client private key (PEM path or inline PEM) for mTLS
268
- NODE_EXTRA_CA_CERTS - CA bundle path (or inline PEM) for server certificate validation
269
- OPENAI_API_KEY - OpenAI GPT models
270
- GEMINI_API_KEY - Google Gemini models
271
- GITHUB_TOKEN - GitHub Copilot (or GH_TOKEN, COPILOT_GITHUB_TOKEN)
272
-
273
- ${chalk.dim("# Additional LLM Providers")}
274
- AZURE_OPENAI_API_KEY - Azure OpenAI models
275
- GROQ_API_KEY - Groq models
276
- CEREBRAS_API_KEY - Cerebras models
277
- XAI_API_KEY - xAI Grok models
278
- OPENROUTER_API_KEY - OpenRouter aggregated models
279
- KILO_API_KEY - Kilo Gateway models
280
- MISTRAL_API_KEY - Mistral models
281
- ZAI_API_KEY - z.ai models (ZhipuAI/GLM)
282
- MINIMAX_API_KEY - MiniMax models
283
- OPENCODE_API_KEY - OpenCode Zen/OpenCode Go models
284
- CURSOR_ACCESS_TOKEN - Cursor AI models
285
- AI_GATEWAY_API_KEY - Vercel AI Gateway
286
-
287
- ${chalk.dim("# Cloud Providers")}
288
- AWS_PROFILE - AWS Bedrock (or AWS_ACCESS_KEY_ID + AWS_SECRET_ACCESS_KEY)
289
- GOOGLE_CLOUD_PROJECT - Google Vertex AI (requires GOOGLE_CLOUD_LOCATION)
290
- GOOGLE_APPLICATION_CREDENTIALS - Service account for Vertex AI
291
-
292
- ${chalk.dim("# Search & Tools")}
293
- EXA_API_KEY - Exa web search
294
- BRAVE_API_KEY - Brave web search
295
- PERPLEXITY_API_KEY - Perplexity web search (API)
296
- PERPLEXITY_COOKIES - Perplexity web search (session cookie)
297
- TAVILY_API_KEY - Tavily web search
298
- ANTHROPIC_SEARCH_API_KEY - Anthropic search provider
299
-
300
- ${chalk.dim("# Configuration")}
301
- GJC_CODING_AGENT_DIR - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)
302
- GJC_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
303
- GJC_SMOL_MODEL - Override smol/fast model (see --smol)
304
- GJC_SLOW_MODEL - Override slow/reasoning model (see --slow)
305
- GJC_PLAN_MODEL - Override planning model (see --plan)
306
- GJC_NO_PTY - Disable PTY-based interactive bash execution
307
- --tmux - Launch interactive startup inside a fresh tmux session
308
- gjc session - List, inspect, create, remove, or attach tagged GJC-managed tmux sessions
309
- GJC_LAUNCH_POLICY - Launch policy for --tmux startup: tmux or direct
310
- GJC_TMUX_SESSION - Explicit tmux session name override for --tmux startup
311
- GJC_TMUX_PROFILE - Apply GJC tmux scroll/mouse/clipboard profile to --tmux sessions (set 0/off to skip)
312
- GJC_MOUSE - Mouse-wheel scroll in --tmux sessions (set 0/off to let the host terminal scroll)
313
-
314
- For complete environment variable reference, see:
315
- ${chalk.dim("docs/environment-variables.md")}
316
- ${chalk.bold("Available Tools (default-enabled unless noted):")}
317
- read - Read file contents
318
- bash - Execute bash commands
319
- edit - Edit files with find/replace
320
- write - Write files (creates/overwrites)
321
- grep - Search file contents
322
- find - Find files by glob pattern
323
- lsp - Language server protocol (code intelligence)
324
- python - Execute Python code (requires: ${APP_NAME} setup python)
325
- notebook - Edit Jupyter notebooks
326
- browser - Browser automation (Puppeteer)
327
- task - Launch sub-agents for parallel tasks
328
- todo_write - Manage todo/task lists
329
- web_search - Search the web
330
- ask - Ask user questions (interactive mode only)
331
-
332
- ${chalk.bold("Useful Commands:")}
333
- ${APP_NAME} --list-models - List configured provider models
334
- ${APP_NAME} --help - Show this help`;
335
- }
336
-
337
- export function printHelp(): void {
338
- process.stdout.write(
339
- `${chalk.bold(APP_NAME)} - red-claw AI coding assistant\n\n` +
340
- `Run ${APP_NAME} --help for full command and option details.\n` +
341
- `Run ${APP_NAME} <command> --help for command-specific help.\n\n` +
342
- `${getExtraHelpText()}\n`,
343
- );
344
- }
@@ -7,7 +7,6 @@ import { createInterface } from "node:readline/promises";
7
7
  import { APP_NAME } from "@gajae-code/utils/dirs";
8
8
  import chalk from "chalk";
9
9
  import { Settings, type SettingsAtomicPatch } from "../config/settings";
10
- import { isProcessIncarnation, processIncarnation } from "../sdk/broker/process-incarnation";
11
10
  import { type EnsureChatDaemonResult, ensureDiscordDaemon, ensureSlackDaemon } from "../sdk/bus/chat-daemon-control";
12
11
  import { getNotificationConfig, maskToken, tokenFingerprint } from "../sdk/bus/config";
13
12
  import {
@@ -33,7 +32,7 @@ import {
33
32
  import {
34
33
  type EnsureTelegramDaemonDetailedResult,
35
34
  ensureTelegramDaemonRunningDetailed,
36
- readDaemonState,
35
+ resolveTelegramSetupPreflight,
37
36
  } from "../sdk/bus/telegram-daemon";
38
37
  import { runDaemonInternal } from "../sdk/bus/telegram-daemon-cli";
39
38
  import {
@@ -458,42 +457,10 @@ function proposedIdentityFromSetupPreflight(
458
457
 
459
458
  async function resolveSetupPreflight(settings: Settings, deps: NotifyCommandDeps): Promise<TelegramSetupPreflight> {
460
459
  if (deps.setupPreflight) return deps.setupPreflight;
461
- const cfg = getNotificationConfig(settings);
462
- try {
463
- const state = await readDaemonState(settings);
464
- if (!state) return { storedChatId: cfg.chatId };
465
- const validPid = Number.isSafeInteger(state.pid) && state.pid > 0;
466
- if (!validPid || !(deps.setupPidAlive ?? daemonPidAlive)(state.pid)) return { storedChatId: cfg.chatId };
467
- const persistedIncarnation = state.incarnation;
468
- const currentIncarnation = (deps.setupPidIncarnation ?? processIncarnation)(state.pid);
469
- if (
470
- !isProcessIncarnation(persistedIncarnation) ||
471
- !isProcessIncarnation(currentIncarnation) ||
472
- persistedIncarnation !== currentIncarnation
473
- )
474
- return { storedChatId: cfg.chatId };
475
- return {
476
- storedChatId: cfg.chatId,
477
- daemon: {
478
- live: true,
479
- tokenFingerprint: typeof state.tokenFingerprint === "string" ? state.tokenFingerprint : undefined,
480
- chatId: typeof state.chatId === "string" ? state.chatId : undefined,
481
- },
482
- };
483
- } catch {
484
- // A state read failure is not proof of a live daemon; proceed normally. The
485
- // daemon's own 409 handling remains the backstop against poller contention.
486
- return { storedChatId: cfg.chatId };
487
- }
488
- }
489
-
490
- function daemonPidAlive(pid: number): boolean {
491
- try {
492
- process.kill(pid, 0);
493
- return true;
494
- } catch (error) {
495
- return (error as NodeJS.ErrnoException).code === "EPERM";
496
- }
460
+ return await resolveTelegramSetupPreflight(settings, {
461
+ pidAlive: deps.setupPidAlive,
462
+ pidIncarnation: deps.setupPidIncarnation,
463
+ });
497
464
  }
498
465
 
499
466
  type TokenPromptInput = NodeJS.ReadStream & {
package/src/cli.ts CHANGED
@@ -8,6 +8,12 @@ import "@gajae-code/utils/postmortem";
8
8
  import { Args, type CliConfig, Command, type CommandEntry, Flags, run } from "@gajae-code/utils/cli";
9
9
  import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION, VERSION } from "@gajae-code/utils/dirs";
10
10
  import { runFixtureReport } from "./cli/fixture-report";
11
+ import { admitManagedOwnerBeforeCli, completeManagedOwnerRecovery } from "./gjc-runtime/managed-owner-admission";
12
+ import {
13
+ isManagedOwnerSupervisorArgv,
14
+ MANAGED_OWNER_CHILD_TOKEN_ENV,
15
+ runManagedOwnerSupervisor,
16
+ } from "./gjc-runtime/managed-owner-supervisor";
11
17
  import { isTmuxOwnerIsolationCliArgv, runTmuxOwnerIsolationCliFromStdin } from "./gjc-runtime/tmux-owner-isolation-cli";
12
18
  import { smokeTestTabWorker } from "./tools/browser/tab-worker-smoke";
13
19
 
@@ -350,6 +356,18 @@ export async function runCli(argv: string[]): Promise<void> {
350
356
  await runTmuxOwnerIsolationCliFromStdin();
351
357
  return;
352
358
  }
359
+ if (isManagedOwnerSupervisorArgv(argv)) {
360
+ await runManagedOwnerSupervisor();
361
+ return;
362
+ }
363
+ if (process.env[MANAGED_OWNER_CHILD_TOKEN_ENV] !== undefined) {
364
+ const admission = await admitManagedOwnerBeforeCli();
365
+ if (admission.kind === "blocked") return;
366
+ if (admission.kind === "recovery") {
367
+ await completeManagedOwnerRecovery(admission.context);
368
+ return;
369
+ }
370
+ }
353
371
  if (isNotifyDaemonInternalFastPath(argv)) {
354
372
  await runNotifyDaemonInternalFastPath(argv);
355
373
  return;
@@ -295,14 +295,14 @@ export async function runSessionHost(
295
295
  rollback.recordAbsent();
296
296
  const failure = normalizeSdkStartupFailure("registration", "failed", error);
297
297
  await writeFailure(failure, rollback.result);
298
- throw new Error(failure.message);
298
+ throw failure;
299
299
  }
300
300
  const { parsed } = opened;
301
301
  if ("failure" in created) {
302
302
  created.rollback.recordAbsent();
303
303
  await writeFailure(created.failure, created.rollback.result);
304
304
 
305
- throw new Error(created.failure.message);
305
+ throw created.failure;
306
306
  }
307
307
  const { session, capability, rollback } = created;
308
308
  let sessionDisposal: Promise<void> | undefined;