@gajae-code/coding-agent 0.16.7 → 0.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. package/CHANGELOG.md +180 -1
  2. package/dist/types/capability/fs.d.ts +37 -4
  3. package/dist/types/capability/index.d.ts +19 -0
  4. package/dist/types/capability/types.d.ts +9 -0
  5. package/dist/types/cli/doctor/args.d.ts +36 -0
  6. package/dist/types/cli/doctor/checks.d.ts +18 -0
  7. package/dist/types/cli/doctor/config-repairs.d.ts +38 -0
  8. package/dist/types/cli/doctor/context.d.ts +89 -0
  9. package/dist/types/cli/doctor/files.d.ts +27 -0
  10. package/dist/types/cli/doctor/ids.d.ts +20 -0
  11. package/dist/types/cli/doctor/install-repairs.d.ts +94 -0
  12. package/dist/types/cli/doctor/journal.d.ts +43 -0
  13. package/dist/types/cli/doctor/managed-link.d.ts +39 -0
  14. package/dist/types/cli/doctor/native-probe.d.ts +2 -0
  15. package/dist/types/cli/doctor/permission-repairs.d.ts +25 -0
  16. package/dist/types/cli/doctor/plugin-quarantine.d.ts +77 -0
  17. package/dist/types/cli/doctor/plugin-restore.d.ts +40 -0
  18. package/dist/types/cli/doctor/plugin-targets.d.ts +11 -0
  19. package/dist/types/cli/doctor/probe-client.d.ts +9 -0
  20. package/dist/types/cli/doctor/probe-types.d.ts +18 -0
  21. package/dist/types/cli/doctor/probe.d.ts +3 -0
  22. package/dist/types/cli/doctor/projection-probe.d.ts +2 -0
  23. package/dist/types/cli/doctor/repairs.d.ts +28 -0
  24. package/dist/types/cli/doctor/report.d.ts +27 -0
  25. package/dist/types/cli/doctor/runner.d.ts +4 -0
  26. package/dist/types/cli/doctor/safety.d.ts +10 -0
  27. package/dist/types/cli/doctor/service-repairs.d.ts +8 -0
  28. package/dist/types/cli/doctor/service-targets.d.ts +41 -0
  29. package/dist/types/cli/doctor/types.d.ts +145 -0
  30. package/dist/types/cli/doctor-cli.d.ts +7 -0
  31. package/dist/types/cli/doctor-supervisor.d.ts +121 -0
  32. package/dist/types/cli/doctor-worker.d.ts +29 -0
  33. package/dist/types/cli/install-activation.d.ts +158 -0
  34. package/dist/types/cli/macos-community-app.d.ts +41 -0
  35. package/dist/types/cli/mcp-cli.d.ts +0 -11
  36. package/dist/types/cli/update-cli.d.ts +41 -4
  37. package/dist/types/cli-main.d.ts +174 -0
  38. package/dist/types/cli.d.ts +1 -171
  39. package/dist/types/commands/doctor.d.ts +7 -0
  40. package/dist/types/commands/sdk.d.ts +17 -8
  41. package/dist/types/config/autorouting-tier-map.d.ts +19 -0
  42. package/dist/types/config/file-lock.d.ts +27 -3
  43. package/dist/types/config/model-preset-registry.d.ts +1 -0
  44. package/dist/types/config/model-registry.d.ts +12 -5
  45. package/dist/types/config/model-resolver.d.ts +16 -3
  46. package/dist/types/config/models-config-schema.d.ts +2 -0
  47. package/dist/types/config/settings-schema.d.ts +1 -1
  48. package/dist/types/coordinator-mcp/question-gate-codec.d.ts +1 -1
  49. package/dist/types/coordinator-mcp/session-reaper.d.ts +15 -5
  50. package/dist/types/cursor.d.ts +9 -9
  51. package/dist/types/discovery/agents-md.d.ts +6 -1
  52. package/dist/types/discovery/helpers.d.ts +36 -7
  53. package/dist/types/discovery/index.d.ts +1 -1
  54. package/dist/types/discovery/mcp-json.d.ts +2 -0
  55. package/dist/types/extensibility/extensions/loader.d.ts +22 -1
  56. package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +14 -1
  57. package/dist/types/extensibility/gjc-plugins/paths.d.ts +2 -1
  58. package/dist/types/extensibility/gjc-plugins/types.d.ts +25 -0
  59. package/dist/types/extensibility/plugins/manager.d.ts +33 -4
  60. package/dist/types/extensibility/plugins/marketplace/cache.d.ts +6 -0
  61. package/dist/types/extensibility/plugins/marketplace/manager.d.ts +186 -0
  62. package/dist/types/extensibility/plugins/marketplace/registry.d.ts +27 -0
  63. package/dist/types/extensibility/plugins/marketplace/source-resolver.d.ts +16 -1
  64. package/dist/types/extensibility/runtime-skill-discovery.d.ts +16 -3
  65. package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +6 -0
  66. package/dist/types/gjc-runtime/launch-worktree.d.ts +53 -0
  67. package/dist/types/gjc-runtime/session-layout.d.ts +8 -0
  68. package/dist/types/gjc-runtime/session-state-lock.d.ts +15 -0
  69. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +13 -0
  70. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +6 -0
  71. package/dist/types/main.d.ts +19 -1
  72. package/dist/types/modes/acp/acp-agent.d.ts +40 -0
  73. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  74. package/dist/types/modes/components/model-selector.d.ts +2 -0
  75. package/dist/types/modes/interactive-mode.d.ts +1 -1
  76. package/dist/types/runtime-mcp/config-writer.d.ts +47 -0
  77. package/dist/types/runtime-mcp/policy-json-edit.d.ts +60 -0
  78. package/dist/types/runtime-mcp/startup-policy.d.ts +4 -0
  79. package/dist/types/runtime-mcp/types.d.ts +2 -2
  80. package/dist/types/sdk/acp/adapter.d.ts +5 -1
  81. package/dist/types/sdk/broker/broker.d.ts +51 -0
  82. package/dist/types/sdk/broker/daemon-entry.d.ts +39 -0
  83. package/dist/types/sdk/broker/discovery.d.ts +38 -0
  84. package/dist/types/sdk/broker/doctor-restart.d.ts +79 -0
  85. package/dist/types/sdk/broker/endpoint-authority.d.ts +7 -0
  86. package/dist/types/sdk/broker/ensure.d.ts +14 -0
  87. package/dist/types/sdk/broker/lifecycle.d.ts +2 -0
  88. package/dist/types/sdk/broker/process-incarnation.d.ts +50 -0
  89. package/dist/types/sdk/broker/runtime.d.ts +26 -0
  90. package/dist/types/sdk/broker/session-index.d.ts +13 -4
  91. package/dist/types/sdk/broker/worktree-occupancy.d.ts +14 -0
  92. package/dist/types/sdk/bus/chat-daemon-cli.d.ts +16 -0
  93. package/dist/types/sdk/bus/chat-daemon-control.d.ts +101 -6
  94. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +16 -0
  95. package/dist/types/sdk/bus/daemon-startup-exclusion.d.ts +43 -0
  96. package/dist/types/sdk/bus/doctor-daemon-restart-client.d.ts +51 -0
  97. package/dist/types/sdk/bus/doctor-daemon-restart.d.ts +39 -0
  98. package/dist/types/sdk/bus/index.d.ts +2 -0
  99. package/dist/types/sdk/bus/notification-service.d.ts +3 -0
  100. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +11 -0
  101. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +1 -1
  102. package/dist/types/sdk/bus/telegram-daemon-control.d.ts +5 -0
  103. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +1 -0
  104. package/dist/types/sdk/bus/telegram-daemon.d.ts +36 -5
  105. package/dist/types/sdk/cli/session-cli.d.ts +1 -0
  106. package/dist/types/sdk/host/session-runtime.d.ts +4 -0
  107. package/dist/types/sdk/host/surface-policy.d.ts +3 -1
  108. package/dist/types/sdk/lifecycle/service.d.ts +44 -10
  109. package/dist/types/sdk/prompt-deadline-lease.d.ts +6 -3
  110. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -2
  111. package/dist/types/sdk/prompt-failure.d.ts +47 -0
  112. package/dist/types/sdk/prompt-status.d.ts +19 -0
  113. package/dist/types/sdk/router/session-router.d.ts +3 -4
  114. package/dist/types/sdk/service-artifact-paths.d.ts +16 -0
  115. package/dist/types/sdk/session-authority.d.ts +9 -0
  116. package/dist/types/sdk/session.d.ts +3 -1
  117. package/dist/types/session/agent-session.d.ts +1 -1
  118. package/dist/types/session/blob-store.d.ts +1 -1
  119. package/dist/types/session/fallback-chain-controller.d.ts +3 -6
  120. package/dist/types/session/internal/managed-session-scope.d.ts +44 -0
  121. package/dist/types/session/primary-control-surface.d.ts +4 -0
  122. package/dist/types/session/session-manager.d.ts +6 -0
  123. package/dist/types/system-prompt.d.ts +6 -0
  124. package/dist/types/tools/ask.d.ts +25 -0
  125. package/dist/types/tools/image-gen.d.ts +0 -4
  126. package/dist/types/tools/skill-discovery.d.ts +7 -5
  127. package/dist/types/tools/ultragoal-ask-guard.d.ts +7 -4
  128. package/dist/types/utils/changelog.d.ts +0 -9
  129. package/dist/types/utils/mupdf-wasm.d.ts +1 -0
  130. package/package.json +9 -8
  131. package/scripts/compile-args.ts +8 -4
  132. package/src/capability/fs.ts +395 -17
  133. package/src/capability/index.ts +273 -10
  134. package/src/capability/types.ts +9 -0
  135. package/src/cli/customize-doctor.ts +18 -12
  136. package/src/cli/doctor/args.ts +236 -0
  137. package/src/cli/doctor/checks.ts +431 -0
  138. package/src/cli/doctor/config-repairs.ts +517 -0
  139. package/src/cli/doctor/context.ts +149 -0
  140. package/src/cli/doctor/files.ts +149 -0
  141. package/src/cli/doctor/ids.ts +115 -0
  142. package/src/cli/doctor/install-repairs.ts +335 -0
  143. package/src/cli/doctor/journal.ts +423 -0
  144. package/src/cli/doctor/managed-link.ts +514 -0
  145. package/src/cli/doctor/native-probe.ts +13 -0
  146. package/src/cli/doctor/permission-repairs.ts +242 -0
  147. package/src/cli/doctor/plugin-quarantine.ts +377 -0
  148. package/src/cli/doctor/plugin-restore.ts +59 -0
  149. package/src/cli/doctor/plugin-targets.ts +373 -0
  150. package/src/cli/doctor/probe-client.ts +195 -0
  151. package/src/cli/doctor/probe-types.ts +21 -0
  152. package/src/cli/doctor/probe.ts +42 -0
  153. package/src/cli/doctor/projection-probe.ts +249 -0
  154. package/src/cli/doctor/repairs.ts +1157 -0
  155. package/src/cli/doctor/report.ts +176 -0
  156. package/src/cli/doctor/runner.ts +342 -0
  157. package/src/cli/doctor/safety.ts +40 -0
  158. package/src/cli/doctor/service-repairs.ts +452 -0
  159. package/src/cli/doctor/service-targets.ts +274 -0
  160. package/src/cli/doctor/types.ts +164 -0
  161. package/src/cli/doctor-cli.ts +62 -0
  162. package/src/cli/doctor-supervisor.ts +571 -0
  163. package/src/cli/doctor-worker.ts +181 -0
  164. package/src/cli/install-activation.ts +666 -0
  165. package/src/cli/macos-community-app.ts +1449 -0
  166. package/src/cli/mcp-cli.ts +11 -21
  167. package/src/cli/nofile-limit.ts +5 -1
  168. package/src/cli/plugin-cli.ts +6 -1
  169. package/src/cli/update-cli.ts +362 -264
  170. package/src/cli-main.ts +517 -0
  171. package/src/cli.ts +64 -433
  172. package/src/commands/autoresearch.ts +11 -5
  173. package/src/commands/completion.ts +1 -1
  174. package/src/commands/doctor.ts +13 -0
  175. package/src/commands/sdk.ts +58 -10
  176. package/src/commands/ultragoal.ts +11 -5
  177. package/src/config/autorouting-tier-map.ts +7 -0
  178. package/src/config/file-lock.ts +736 -71
  179. package/src/config/mcp-schema.json +3 -3
  180. package/src/config/model-preset-registry.ts +1 -0
  181. package/src/config/model-registry.ts +80 -27
  182. package/src/config/model-resolver.ts +33 -4
  183. package/src/config/models-config-schema.ts +2 -0
  184. package/src/config/settings-schema.ts +6 -2
  185. package/src/coordinator-mcp/question-gate-codec.ts +1 -0
  186. package/src/coordinator-mcp/server.ts +534 -51
  187. package/src/coordinator-mcp/session-reaper.ts +64 -8
  188. package/src/cursor.ts +223 -53
  189. package/src/discovery/agents-md.ts +74 -8
  190. package/src/discovery/agents.ts +32 -7
  191. package/src/discovery/builtin.ts +184 -75
  192. package/src/discovery/claude-plugins.ts +85 -17
  193. package/src/discovery/cline.ts +38 -10
  194. package/src/discovery/cursor.ts +19 -6
  195. package/src/discovery/gemini.ts +62 -22
  196. package/src/discovery/github.ts +13 -3
  197. package/src/discovery/helpers.ts +483 -89
  198. package/src/discovery/index.ts +1 -0
  199. package/src/discovery/mcp-json.ts +36 -10
  200. package/src/discovery/opencode.ts +36 -19
  201. package/src/discovery/ssh.ts +11 -8
  202. package/src/discovery/windsurf.ts +12 -3
  203. package/src/exec/bash-executor.ts +10 -3
  204. package/src/exec/isolated-shell.ts +15 -2
  205. package/src/extensibility/extensions/loader.ts +88 -26
  206. package/src/extensibility/gjc-plugins/lifecycle.ts +189 -0
  207. package/src/extensibility/gjc-plugins/paths.ts +4 -1
  208. package/src/extensibility/gjc-plugins/types.ts +27 -0
  209. package/src/extensibility/plugins/manager.ts +200 -22
  210. package/src/extensibility/plugins/marketplace/cache.ts +55 -2
  211. package/src/extensibility/plugins/marketplace/manager.ts +1262 -162
  212. package/src/extensibility/plugins/marketplace/registry.ts +153 -0
  213. package/src/extensibility/plugins/marketplace/source-resolver.ts +116 -10
  214. package/src/extensibility/runtime-skill-discovery.ts +61 -9
  215. package/src/extensibility/skill-management.ts +7 -1
  216. package/src/gjc-runtime/autoresearch-runtime.ts +10 -1
  217. package/src/gjc-runtime/launch-worktree.test.ts +248 -0
  218. package/src/gjc-runtime/launch-worktree.ts +275 -38
  219. package/src/gjc-runtime/repository-binding.ts +26 -1
  220. package/src/gjc-runtime/session-layout.ts +10 -0
  221. package/src/gjc-runtime/session-state-lock.ts +330 -23
  222. package/src/gjc-runtime/session-state-sidecar.ts +328 -80
  223. package/src/gjc-runtime/ultragoal-runtime.ts +10 -1
  224. package/src/harness-control-plane/session-lease.ts +2 -2
  225. package/src/internal-urls/docs-index.generated.ts +28 -26
  226. package/src/main.ts +150 -29
  227. package/src/memories/index.ts +24 -2
  228. package/src/modes/acp/acp-agent.ts +522 -68
  229. package/src/modes/components/agent-dashboard.ts +3 -1
  230. package/src/modes/components/model-selector.ts +28 -19
  231. package/src/modes/components/plugin-settings.ts +2 -1
  232. package/src/modes/controllers/selector-controller.ts +15 -9
  233. package/src/modes/interactive-mode.ts +21 -3
  234. package/src/prompts/system/system-prompt.md +5 -1
  235. package/src/prompts/tools/browser.md +1 -1
  236. package/src/prompts/tools/move-session.md +4 -0
  237. package/src/prompts/tools/read.md +2 -1
  238. package/src/prompts/tools/skill-discovery.md +6 -5
  239. package/src/prompts/tools/task.md +1 -0
  240. package/src/runtime-mcp/config-writer.ts +228 -0
  241. package/src/runtime-mcp/oauth-discovery.ts +114 -14
  242. package/src/runtime-mcp/policy-json-edit.ts +129 -0
  243. package/src/runtime-mcp/startup-policy.ts +14 -0
  244. package/src/runtime-mcp/types.ts +2 -2
  245. package/src/sdk/acp/adapter.ts +27 -12
  246. package/src/sdk/broker/broker.ts +273 -44
  247. package/src/sdk/broker/daemon-entry.ts +119 -0
  248. package/src/sdk/broker/discovery.ts +173 -20
  249. package/src/sdk/broker/doctor-restart.ts +206 -0
  250. package/src/sdk/broker/endpoint-authority.ts +36 -0
  251. package/src/sdk/broker/ensure.ts +49 -14
  252. package/src/sdk/broker/lifecycle.ts +174 -42
  253. package/src/sdk/broker/process-incarnation.ts +86 -2
  254. package/src/sdk/broker/runtime.ts +145 -21
  255. package/src/sdk/broker/session-index.ts +136 -22
  256. package/src/sdk/broker/spawn-substrate.ts +4 -1
  257. package/src/sdk/broker/transport.ts +5 -0
  258. package/src/sdk/broker/worktree-occupancy.ts +21 -1
  259. package/src/sdk/bus/chat-daemon-cli.ts +63 -0
  260. package/src/sdk/bus/chat-daemon-control.ts +260 -64
  261. package/src/sdk/bus/chat-daemon-runtime.ts +141 -25
  262. package/src/sdk/bus/daemon-startup-exclusion.ts +119 -0
  263. package/src/sdk/bus/doctor-daemon-restart-client.ts +291 -0
  264. package/src/sdk/bus/doctor-daemon-restart.ts +92 -0
  265. package/src/sdk/bus/index.ts +252 -51
  266. package/src/sdk/bus/kind-aware-reconciliation.ts +76 -41
  267. package/src/sdk/bus/notification-service.ts +21 -3
  268. package/src/sdk/bus/reconciliation-store.ts +17 -11
  269. package/src/sdk/bus/telegram-daemon-cli.ts +91 -5
  270. package/src/sdk/bus/telegram-daemon-contract.ts +1 -1
  271. package/src/sdk/bus/telegram-daemon-control.ts +47 -0
  272. package/src/sdk/bus/telegram-daemon-owner-registry.ts +1 -1
  273. package/src/sdk/bus/telegram-daemon.ts +178 -13
  274. package/src/sdk/cli/session-cli.ts +100 -12
  275. package/src/sdk/host/host.ts +2 -7
  276. package/src/sdk/host/session-runtime.test.ts +329 -8
  277. package/src/sdk/host/session-runtime.ts +202 -50
  278. package/src/sdk/host/surface-policy.ts +8 -1
  279. package/src/sdk/lifecycle/service.ts +199 -22
  280. package/src/sdk/mcp/server.ts +1 -1
  281. package/src/sdk/prompt-deadline-lease.ts +12 -4
  282. package/src/sdk/prompt-deadline-manager.ts +5 -7
  283. package/src/sdk/prompt-failure.ts +148 -0
  284. package/src/sdk/prompt-status.ts +30 -1
  285. package/src/sdk/prompt-watchdog.ts +11 -3
  286. package/src/sdk/protocol/operation-inventory.generated.json +18 -0
  287. package/src/sdk/protocol/operation-registry.ts +20 -8
  288. package/src/sdk/router/session-router.ts +8 -3
  289. package/src/sdk/service-artifact-paths.ts +26 -0
  290. package/src/sdk/session-authority.ts +10 -0
  291. package/src/sdk/session.ts +361 -194
  292. package/src/session/agent-session.ts +398 -93
  293. package/src/session/blob-store.ts +9 -9
  294. package/src/session/fallback-chain-controller.ts +3 -7
  295. package/src/session/internal/managed-session-scope.ts +445 -29
  296. package/src/session/internal/managed-session-storage.ts +38 -6
  297. package/src/session/primary-control-surface.ts +12 -0
  298. package/src/session/session-manager.ts +11 -3
  299. package/src/session/session-storage.ts +1 -1
  300. package/src/session-import/codex.ts +6 -1
  301. package/src/session-import/redact.ts +7 -0
  302. package/src/skill-state/workflow-mutation-guard.ts +645 -39
  303. package/src/slash-commands/builtin-registry.ts +7 -3
  304. package/src/system-prompt.ts +8 -0
  305. package/src/task/executor.ts +36 -3
  306. package/src/task/types.ts +27 -5
  307. package/src/tools/ask.ts +114 -34
  308. package/src/tools/browser/actions.ts +2 -2
  309. package/src/tools/browser/tab-worker.ts +11 -8
  310. package/src/tools/descriptors.ts +6 -1
  311. package/src/tools/fetch.ts +7 -2
  312. package/src/tools/image-gen.ts +33 -34
  313. package/src/tools/read.ts +78 -32
  314. package/src/tools/skill-discovery.ts +17 -7
  315. package/src/tools/tool-catalog.generated.ts +8 -8
  316. package/src/tools/ultragoal-ask-guard.ts +16 -26
  317. package/src/utils/changelog.ts +7 -1
  318. package/src/utils/git.ts +3 -1
  319. package/src/utils/markit.ts +24 -2
  320. package/src/utils/mupdf-wasm.ts +26 -0
  321. package/src/web/search/providers/openai-compatible.ts +191 -14
package/src/cli.ts CHANGED
@@ -1,427 +1,59 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
- /**
4
- * CLI entry point — registers all commands explicitly and delegates to the
5
- * lightweight CLI runner from pi-utils.
6
- */
7
- import "@gajae-code/utils/postmortem";
8
- import { Args, type CliConfig, Command, type CommandEntry, run } from "@gajae-code/utils/cli";
9
- import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION, VERSION } from "@gajae-code/utils/dirs";
10
- import { runFixtureReport } from "./cli/fixture-report";
11
- import { ROOT_LAUNCH_FLAGS } from "./cli/root-flags";
12
- import QuickLane from "./commands/quick-lane";
13
- import { runBashShellGuardian } from "./exec/bash-shell-guardian";
14
- import { runBashShellSupervisor } from "./exec/bash-shell-supervisor";
15
- import { runBashShellWorker } from "./exec/bash-shell-worker";
3
+ /** Lightweight CLI bootstrap. Heavy command registration is loaded only after
4
+ * security admission; `gjc doctor` stays reachable when normal startup breaks. */
5
+ import { APP_NAME, formatBunRuntimeError, MIN_BUN_VERSION } from "@gajae-code/utils/dirs";
6
+ import { startTiming } from "@gajae-code/utils/logger";
16
7
  import {
17
8
  BASH_SHELL_RUNTIME_ARG,
18
9
  BASH_SHELL_SUPERVISOR_ARG,
19
10
  BASH_SHELL_WORKER_ARG,
20
11
  } from "./exec/bash-shell-worker-protocol";
21
- import { smokeTestIsolatedShell } from "./exec/isolated-shell";
22
- import { smokeTestTabWorker } from "./tools/browser/tab-worker-smoke";
23
12
 
24
- if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
25
- process.stderr.write(
26
- formatBunRuntimeError({
27
- currentVersion: Bun.version,
28
- minVersion: MIN_BUN_VERSION,
29
- execPath: process.execPath,
30
- }),
31
- );
32
- process.exit(1);
33
- }
34
-
35
- process.title = APP_NAME;
36
- const rootHelpFlags = ["--help", "-h", "help"];
37
- const versionFlags = ["--version", "-v"];
38
13
  const MANAGED_OWNER_SUPERVISOR_ARG = "--internal-managed-owner-supervisor";
39
14
  const MANAGED_OWNER_CHILD_TOKEN_ENV = "GJC_MANAGED_OWNER_CHILD_TOKEN";
40
15
  const TMUX_OWNER_ISOLATION_ARG = "--internal-tmux-owner-isolation";
41
16
 
42
- export const commands: CommandEntry[] = [
43
- { name: "codex-native-hook", load: () => import("./commands/codex-native-hook").then(m => m.default) },
44
- { name: "state", load: () => import("./commands/state").then(m => m.default) },
45
- { name: "setup", load: () => import("./commands/setup").then(m => m.default) },
46
- { name: "acp", load: () => import("./commands/acp").then(m => m.default) },
47
- { name: "auth-broker", load: () => import("./commands/auth-broker").then(m => m.default) },
48
- { name: "auth-gateway", load: () => import("./commands/auth-gateway").then(m => m.default) },
49
- { name: "skills", load: () => import("./commands/skills").then(m => m.default) },
50
- { name: "session", load: () => import("./commands/session").then(m => m.default) },
51
- { name: "accounts", load: () => import("./commands/accounts").then(m => m.default) },
52
- { name: "harness", load: () => import("./commands/harness").then(m => m.default) },
53
- { name: "coordinator", load: () => import("./commands/coordinator").then(m => m.default) },
54
- { name: "ultragoal", load: () => import("./commands/ultragoal").then(m => m.default) },
55
- { name: "gc", load: () => import("./commands/gc").then(m => m.default) },
56
- { name: "crash", load: () => import("./commands/crash").then(m => m.default) },
57
- { name: "autoresearch", load: () => import("./commands/autoresearch").then(m => m.default) },
58
- { name: "ralplan", load: () => import("./commands/ralplan").then(m => m.default) },
59
- { name: "config", load: () => import("./commands/config").then(m => m.default) },
60
- { name: "stats", load: () => import("./commands/stats").then(m => m.default) },
61
- { name: "notify", load: () => import("./commands/notify").then(m => m.default) },
62
- { name: "sdk", load: () => import("./commands/sdk").then(m => m.default) },
63
- { name: "daemon", load: () => import("./commands/daemon").then(m => m.default) },
64
- { name: "web-search", aliases: ["q"], load: () => import("./commands/web-search").then(m => m.default) },
65
- { name: "local-provider", load: () => import("./commands/local-provider").then(m => m.default) },
66
- { name: "model-presets", load: () => import("./commands/model-presets").then(m => m.default) },
67
- { name: "mcp-serve", load: () => import("./commands/mcp-serve").then(m => m.default) },
68
- { name: "mcp", load: () => import("./commands/mcp").then(m => m.default) },
69
- {
70
- name: "contribute-pr",
71
- aliases: ["contribution-prep"],
72
- load: () => import("./commands/contribution-prep").then(m => m.default),
73
- },
74
- { name: "deep-interview", load: () => import("./commands/deep-interview").then(m => m.default) },
75
- { name: "migrate", load: () => import("./commands/migrate").then(m => m.default) },
76
- { name: "update", load: () => import("./commands/update").then(m => m.default) },
77
- { name: "read", load: () => import("./commands/read").then(m => m.default) },
78
- { name: "customize", load: () => import("./commands/customize").then(m => m.default) },
79
- { name: "plugin", load: () => import("./commands/plugin").then(m => m.default) },
80
- { name: "completion", load: () => import("./commands/completion").then(m => m.default) },
81
- { name: "launch", load: () => import("./commands/launch").then(m => m.default) },
82
- { name: "quick-lane", load: async () => QuickLane },
83
- ];
84
-
85
- async function showHelp(config: CliConfig): Promise<void> {
86
- const { renderRootHelp } = await import("@gajae-code/utils/cli");
87
- const { getExtraHelpText } = await import("./cli/fast-help");
88
- renderRootHelp(config);
89
- const extra = getExtraHelpText();
90
- if (extra.trim().length > 0) {
91
- process.stdout.write(`\n${extra}\n`);
92
- }
93
- }
94
-
95
- async function installRuntimeGlobals(): Promise<void> {
96
- const { installH2Fetch } = await import("@gajae-code/ai/utils/h2-fetch");
97
- // Activate HTTP/2 for all `fetch()` calls (provider streams, OAuth, model
98
- // discovery, web tools). Bun's HTTP/2 client is gated on a startup flag we
99
- // can't toggle from JS, so we patch globalThis.fetch to pass
100
- // `protocol: "http2"` per request, with transparent HTTP/1.1 fallback on
101
- // `HTTP2Unsupported`. See @gajae-code/ai/utils/h2-fetch for details.
102
- installH2Fetch();
103
-
104
- const { warnIfMacOSNoFileLimitTooLow } = await import("./cli/nofile-limit");
105
- warnIfMacOSNoFileLimitTooLow();
106
-
107
- // Secondary in-process scrub of the macOS malloc-stack-logging vars. The real
108
- // boundary is the darwin re-exec guard at the top of runCli(): Bun snapshots the
109
- // spawn-default environment at startup, so deleting these here does NOT clean the
110
- // env children inherit by default — it only tidies `process.env` for code that
111
- // reads it directly. Kept as belt-and-braces for the rare re-exec-unavailable
112
- // fallback; managed spawns already use filterProcessEnv and the native PTY lane
113
- // strips them independently.
114
- delete process.env.MallocStackLogging;
115
- delete process.env.MallocStackLoggingNoCompact;
116
- }
117
-
118
- function isStatsHelpFastPath(argv: string[]): boolean {
119
- return argv[0] === "stats" && (argv.includes("--help") || argv.includes("-h"));
120
- }
121
-
122
- function showStatsFastHelp(): void {
123
- process.stdout.write(`Usage: ${APP_NAME} stats [options]
124
-
125
- View usage statistics
126
-
127
- Options:
128
- -p, --port <number> Port for the dashboard server (default: 3847)
129
- -j, --json Output stats as JSON
130
- -s, --summary Print summary to console
131
- -h, --help Show this help
132
- `);
133
- }
134
-
135
- export function interactiveBootstrapText(
136
- argv: readonly string[],
137
- stdinIsTTY = process.stdin.isTTY,
138
- stdoutIsTTY = process.stdout.isTTY,
139
- ): string | undefined {
140
- if (!stdinIsTTY || !stdoutIsTTY || argv[0] !== "launch") return undefined;
141
- for (let index = 1; index < argv.length; index++) {
142
- const arg = argv[index];
143
- if (
144
- arg === "--print" ||
145
- arg?.startsWith("--print=") ||
146
- arg === "-p" ||
147
- arg === "--export" ||
148
- arg?.startsWith("--export=") ||
149
- arg === "--list-models" ||
150
- arg?.startsWith("--list-models=") ||
151
- arg === "--mode" ||
152
- arg?.startsWith("--mode=") ||
153
- arg === "--help" ||
154
- arg?.startsWith("--help=") ||
155
- arg === "-h" ||
156
- arg === "--version" ||
157
- arg?.startsWith("--version=") ||
158
- arg === "-v"
159
- )
160
- return undefined;
161
- }
162
- return "\u001b[?25h\u001b[38;5;45mGJC\u001b[0m warming workspace\r\n\r\n> ";
163
- }
164
-
165
- function isNotifyDaemonInternalFastPath(argv: string[]): boolean {
166
- return argv[0] === "notify" && argv[1] === "daemon-internal";
167
- }
168
-
169
- async function runNotifyDaemonInternalFastPath(argv: string[]): Promise<void> {
170
- const { parseNotifyArgs, runNotifyCommand } = await import("./cli/notify-cli");
171
- const cmd = parseNotifyArgs(argv);
172
- if (cmd?.action !== "daemon-internal") {
173
- throw new Error("invalid notify daemon-internal fast path");
174
- }
175
- await runNotifyCommand(cmd);
176
- }
177
-
178
- function isChatDaemonInternalFastPath(argv: string[]): boolean {
179
- return argv[0] === "daemon" && (argv[1] === "discord-internal" || argv[1] === "slack-internal");
180
- }
181
-
182
- async function runChatDaemonInternalFastPath(argv: string[]): Promise<void> {
183
- const action = argv[1];
184
- if (action !== "discord-internal" && action !== "slack-internal") {
185
- throw new Error("invalid chat daemon internal fast path");
186
- }
187
- const { runChatDaemonInternal } = await import("./sdk/bus/chat-daemon-cli");
188
- await runChatDaemonInternal(action === "discord-internal" ? "discord" : "slack", argv.slice(2));
17
+ // Anchor startup timing before the heavy CLI module graph is loaded so the
18
+ // printed tree includes runtime/bootstrap costs as well as dispatch work.
19
+ if (process.env.GJC_TIMING || process.env.PI_TIMING) {
20
+ startTiming();
189
21
  }
190
22
 
191
- type MemoryGuardNativeSmokeLoad = () => Record<string, unknown>;
192
- type WindowsJobMemoryProbeResult = Record<string, unknown> & { kind: string };
193
- type MemoryGuardNativeSmokeReceipt = {
194
- api: "memory_guard_windows_job_probe_v1";
195
- source: "pi_natives";
196
- result: WindowsJobMemoryProbeResult;
197
- };
198
-
199
- export function isMemoryGuardNativeSmokeFastPath(argv: readonly string[]): boolean {
200
- return (
201
- argv.length === 3 && argv[0] === "internal" && argv[1] === "memory-guard-native-smoke" && argv[2] === "--json"
202
- );
203
- }
204
-
205
- function parseWindowsJobMemoryProbeResult(value: unknown): WindowsJobMemoryProbeResult {
206
- if (!value || typeof value !== "object") {
207
- throw new Error("memory-guard-native-smoke: native probe returned a non-object result");
208
- }
209
- const result = value as Record<string, unknown>;
210
- if (typeof result.kind !== "string") {
211
- throw new Error("memory-guard-native-smoke: native probe result is missing a string kind tag");
212
- }
213
- return result as WindowsJobMemoryProbeResult;
214
- }
215
-
216
- export function runMemoryGuardNativeSmokeFastPath(
217
- options: { loadNative?: MemoryGuardNativeSmokeLoad; writeStdout?: (text: string) => void } = {},
218
- ): void {
219
- if (!options.loadNative)
220
- throw new Error("memory-guard-native-smoke: native loader is unavailable on the static CLI path");
221
- const probe = options.loadNative().probeWindowsJobMemory;
222
- if (typeof probe !== "function") {
223
- throw new Error("memory-guard-native-smoke: probeWindowsJobMemory export missing from native addon");
224
- }
225
- const receipt: MemoryGuardNativeSmokeReceipt = {
226
- api: "memory_guard_windows_job_probe_v1",
227
- source: "pi_natives",
228
- result: parseWindowsJobMemoryProbeResult((probe as () => unknown)()),
229
- };
230
- (options.writeStdout ?? (text => process.stdout.write(text)))(`${JSON.stringify(receipt)}\n`);
231
- }
232
-
233
- async function runMemoryGuardNativeSmokeFastPathFromCli(): Promise<void> {
234
- const { runMemoryGuardNativeSmoke } = await import("./cli/native-smoke");
235
- runMemoryGuardNativeSmoke();
236
- }
237
-
238
- function isLaunchWorktreeSelector(arg: string): boolean {
239
- return (
240
- arg === "--worktree" ||
241
- arg === "-w" ||
242
- arg.startsWith("--worktree=") ||
243
- arg.startsWith("-w=") ||
244
- (arg.startsWith("-w") && arg.length > 2)
23
+ if (Bun.semver.order(Bun.version, MIN_BUN_VERSION) < 0) {
24
+ process.stderr.write(
25
+ formatBunRuntimeError({ currentVersion: Bun.version, minVersion: MIN_BUN_VERSION, execPath: process.execPath }),
245
26
  );
27
+ process.exit(1);
246
28
  }
29
+ process.title = APP_NAME;
247
30
 
248
- function rootFlagDescriptor(arg: string) {
249
- if (arg.startsWith("--") && !arg.includes("="))
250
- return ROOT_LAUNCH_FLAGS[arg.slice(2) as keyof typeof ROOT_LAUNCH_FLAGS];
251
- if (/^-[^-]$/.test(arg))
252
- return Object.values(ROOT_LAUNCH_FLAGS).find(descriptor => descriptor.char === arg.slice(1));
253
- return undefined;
254
- }
255
-
256
- function rootFlagValueIndex(argv: readonly string[], index: number): number {
257
- const descriptor = rootFlagDescriptor(argv[index] ?? "");
258
- if (!descriptor || descriptor.kind === "boolean") return index;
259
- const value = argv[index + 1];
260
- return value && !value.startsWith("-") ? index + 1 : index;
261
- }
262
-
263
- function rootFixtureArg(argv: string[]): { present: boolean; id: string | undefined } {
264
- for (let i = 0; i < argv.length; i++) {
265
- const arg = argv[i] ?? "";
266
- if (arg === "--" || isSubcommand(arg)) return { present: false, id: undefined };
267
- if (arg === "--fixture") return { present: true, id: argv[i + 1] };
268
- const descriptor = rootFlagDescriptor(arg);
269
- if (descriptor && descriptor.kind !== "boolean") {
270
- const value = argv[i + 1];
271
- if (!value || value.startsWith("-")) return { present: false, id: undefined };
272
- i++;
273
- }
274
- }
275
- return { present: false, id: undefined };
276
- }
277
-
278
- function hasRootFastFlag(argv: string[], flags: readonly string[]): boolean {
279
- for (let i = 0; i < argv.length; i++) {
280
- const arg = argv[i] ?? "";
281
- if (arg === "--" || isSubcommand(arg) || isLaunchWorktreeSelector(arg)) return false;
282
- if (flags.includes(arg)) return true;
283
- i = rootFlagValueIndex(argv, i);
284
- }
285
- return false;
286
- }
287
-
288
- function hasRootHelpFlag(argv: string[]): boolean {
289
- return hasRootFastFlag(argv, rootHelpFlags);
290
- }
291
-
292
- function hasRootVersionFlag(argv: string[]): boolean {
293
- return hasRootFastFlag(argv, versionFlags);
294
- }
295
-
296
- export class RootHelpCommand extends Command {
297
- static description = "Red-claw AI coding assistant";
298
- static hidden = true;
299
- static args = {
300
- messages: Args.string({
301
- description: "Messages to send (prefix files with @)",
302
- required: false,
303
- multiple: true,
304
- }),
305
- };
306
- static flags = ROOT_LAUNCH_FLAGS;
307
- static examples = [
308
- `# Interactive mode\n ${APP_NAME}`,
309
- `# Interactive mode with initial prompt\n ${APP_NAME} "List all .ts files in src/"`,
310
- `# Include files in initial message\n ${APP_NAME} @prompt.md @image.png "What color is the sky?"`,
311
- `# Non-interactive mode (process and exit)\n ${APP_NAME} -p "List all .ts files in src/"`,
312
- `# Continue previous session\n ${APP_NAME} --continue "What did we discuss?"`,
313
- `# Launch in a sibling git worktree\n ${APP_NAME} --worktree`,
314
- `# Use different model (fuzzy matching)\n ${APP_NAME} --model opus "Help me refactor this code"`,
315
- `# Limit model cycling to specific models\n ${APP_NAME} --models claude-sonnet,claude-haiku,gpt-4o`,
316
- `# Pin a stored credential for this session\n ${APP_NAME} --credential email:me@example.com`,
317
- `# Prefer a stored credential, falling back on quota limits\n ${APP_NAME} --prefer-credential id:15`,
318
- `# Activate a model profile for this session\n ${APP_NAME} --mpreset codex-medium`,
319
- `# Persist a model profile as the default\n ${APP_NAME} --mpreset opencodego --default`,
320
- `# Export a session file to HTML\n ${APP_NAME} --export ~/.gjc/agent/sessions/--path--/session.jsonl`,
321
- ];
322
- static strict = false;
323
- async run(): Promise<void> {}
324
- }
325
-
326
- /**
327
- * Determine whether argv[0] is a known subcommand name.
328
- * If not, the entire argv is treated as args to the default "launch" command.
329
- */
330
- function isSubcommand(first: string | undefined): boolean {
331
- if (!first || first.startsWith("-") || first.startsWith("@")) return false;
332
- return commands.some(e => e.name === first || e.aliases?.includes(first));
333
- }
334
-
335
- /**
336
- * Smoke-test entry. Spawns the stats sync worker and the browser tab worker, then verifies their protocol.
337
- *
338
- * Purpose: catch silent compiled-worker load regressions (issues #1011,
339
- * #1027, and #2598). Neither `--version` nor `stats --summary` spawns both
340
- * worker entries on a fresh install. This probe proves each bundled worker
341
- * module resolves and evaluates; the tab-worker probe also completes its
342
- * bootstrap/closed protocol without launching a browser. Wired into
343
- * `scripts/install-tests/run-ci.sh` so binary / source-link / tarball installs
344
- * exercise it on every CI run.
345
- */
346
- async function runSmokeTest(): Promise<void> {
347
- const { smokeTestSyncWorker } = await import("@gajae-code/stats");
348
- await smokeTestSyncWorker();
349
- const { runNativeSmokeTest } = await import("./cli/native-smoke");
350
- await runNativeSmokeTest();
351
- await smokeTestTabWorker();
352
- await smokeTestIsolatedShell();
353
- process.stdout.write("smoke-test: ok\n");
354
- }
355
-
356
- /** Normalize the sole `gjc resume` alias into the value-less launch intent. */
357
- export function normalizeResumeAlias(argv: readonly string[]): string[] {
358
- return argv.length === 1 && argv[0] === "resume" ? ["--resume"] : [...argv];
359
- }
360
-
361
- function routeLegacyRootArgv(argv: readonly string[]): string[] | undefined {
362
- if (argv[0] === "coordinator-mcp") return ["mcp-serve", "coordinator", ...argv.slice(1)];
363
- return undefined;
364
- }
365
-
366
- /**
367
- * Map the common mistaken `models` subcommand spelling to non-agent listing.
368
- *
369
- * Agents frequently run `gjc models` from the bash tool expecting a catalog.
370
- * Without this route, `models` was a positional launch prompt and nested agents
371
- * re-invoked `gjc models`, spawning an unbounded process chain (#3857).
372
- * Always rewrite to `launch --list-models` so the invocation exits after a
373
- * bounded listing and never starts an interactive agent session.
374
- */
375
- export function routeModelsAlias(argv: readonly string[]): string[] | undefined {
376
- if (argv[0] !== "models") return undefined;
377
- const rest = argv.slice(1);
378
- if (rest[0] === "presets") return ["model-presets", ...rest.slice(1)];
379
- if (rest.length === 0) return ["launch", "--list-models"];
380
- // Pure search tokens become a single fuzzy pattern (matches --list-models).
381
- if (rest.every(token => !token.startsWith("-") && !token.startsWith("@"))) {
382
- return ["launch", "--list-models", rest.join(" ")];
383
- }
384
- // Mixed flags still go through list-models first so "models" is never a prompt.
385
- return ["launch", "--list-models", ...rest];
31
+ function isDoctorArgv(argv: readonly string[]): boolean {
32
+ return argv[0] === "doctor";
386
33
  }
387
34
 
388
- /** Apply the same default-launch routing used by runCli after root fast paths. */
389
- export function routeRootArgv(argv: readonly string[]): string[] {
390
- const normalizedArgv = normalizeResumeAlias(argv);
391
- const legacyArgv = routeLegacyRootArgv(normalizedArgv);
392
- if (legacyArgv) return legacyArgv;
393
- const modelsArgv = routeModelsAlias(normalizedArgv);
394
- if (modelsArgv) return modelsArgv;
395
- const first = normalizedArgv[0];
396
- return first === "--help" || first === "-h" || first === "--version" || first === "-v" || first === "help"
397
- ? normalizedArgv
398
- : isSubcommand(first)
399
- ? normalizedArgv
400
- : ["launch", ...normalizedArgv];
35
+ async function runDoctor(argv: string[]): Promise<void> {
36
+ const { runDoctorCli } = await import("./cli/doctor-cli");
37
+ await runDoctorCli(argv.slice(1));
401
38
  }
402
39
 
403
- /** Run the CLI with the given argv (no `process.argv` prefix). */
40
+ /** Run the CLI with argv excluding process.argv prefix. */
404
41
  export async function runCli(argv: string[]): Promise<void> {
405
42
  if (argv.length === 1 && argv[0] === BASH_SHELL_WORKER_ARG) {
43
+ const { runBashShellGuardian } = await import("./exec/bash-shell-guardian");
406
44
  await runBashShellGuardian();
407
45
  return;
408
46
  }
409
47
  if (argv.length === 1 && argv[0] === BASH_SHELL_SUPERVISOR_ARG) {
48
+ const { runBashShellSupervisor } = await import("./exec/bash-shell-supervisor");
410
49
  await runBashShellSupervisor();
411
50
  return;
412
51
  }
413
52
  if (argv.length === 1 && argv[0] === BASH_SHELL_RUNTIME_ARG) {
53
+ const { runBashShellWorker } = await import("./exec/bash-shell-worker");
414
54
  await runBashShellWorker();
415
55
  return;
416
56
  }
417
- // macOS malloc-env launch boundary. Re-exec once with a scrubbed environment
418
- // BEFORE any fast path or subprocess spawn, so the startup env snapshot Bun hands
419
- // to every child lane (Bun.spawn defaults, node:child_process, native PTY, tmux
420
- // owner, plugin installs, subagents) is clean. This runs ahead of the
421
- // tmux-owner-isolation and notify-daemon fast paths so those lanes execute inside
422
- // the already-scrubbed process too. The cheap inline predicate keeps the common
423
- // (uncontaminated / non-darwin) path free of extra module loads; the guard module
424
- // (MACOS_MALLOC_ENV_VARS / GJC_MALLOC_ENV_REEXEC) loads only when a re-exec is due.
425
57
  if (
426
58
  process.platform === "darwin" &&
427
59
  process.env.GJC_MALLOC_ENV_REEXEC === undefined &&
@@ -433,10 +65,10 @@ export async function runCli(argv: string[]): Promise<void> {
433
65
  process.exitCode = code;
434
66
  return;
435
67
  }
436
- // Re-exec could not be spawned; fall through and run in this process.
437
68
  }
438
- if (isMemoryGuardNativeSmokeFastPath(argv)) {
439
- await runMemoryGuardNativeSmokeFastPathFromCli();
69
+ if (argv.length === 3 && argv[0] === "internal" && argv[1] === "memory-guard-native-smoke" && argv[2] === "--json") {
70
+ const { runMemoryGuardNativeSmoke } = await import("./cli/native-smoke");
71
+ runMemoryGuardNativeSmoke();
440
72
  return;
441
73
  }
442
74
  if (argv.length === 1 && argv[0] === TMUX_OWNER_ISOLATION_ARG) {
@@ -460,58 +92,57 @@ export async function runCli(argv: string[]): Promise<void> {
460
92
  return;
461
93
  }
462
94
  }
463
- if (isNotifyDaemonInternalFastPath(argv)) {
464
- await runNotifyDaemonInternalFastPath(argv);
95
+ if (argv.length === 1 && argv[0] === "--supports-macos-community-app") {
96
+ process.stdout.write("macos-community-app-offer\n");
465
97
  return;
466
98
  }
467
- if (isChatDaemonInternalFastPath(argv)) {
468
- await runChatDaemonInternalFastPath(argv);
469
- return;
470
- }
471
- if (argv[0] === "--smoke-test") {
472
- await runSmokeTest();
99
+ if (argv.length === 1 && argv[0] === "--internal-macos-community-app-offer") {
100
+ try {
101
+ const { offerMacosCommunityApp } = await import("./cli/macos-community-app");
102
+ await offerMacosCommunityApp({ log: message => process.stderr.write(`${message}\n`) });
103
+ } catch {
104
+ const { COMMUNITY_APP_REPOSITORY } = await import("./cli/macos-community-app");
105
+ process.stderr.write(
106
+ `Optional community app offer failed; GJC remains installed. https://github.com/${COMMUNITY_APP_REPOSITORY}\n`,
107
+ );
108
+ }
473
109
  return;
474
110
  }
475
- const fixtureArg = rootFixtureArg(argv);
476
- if (fixtureArg.present) {
477
- const id = fixtureArg.id;
478
- if (!id || id.startsWith("-")) {
479
- process.stderr.write(`${APP_NAME} --fixture requires a fixture id\n`);
480
- process.exitCode = 1;
111
+ if (argv[0] === "--internal-doctor-worker") {
112
+ // Non-forgeable route: reachable only with the exact per-spawn token env var
113
+ // AND a non-TTY stdin (isRoutableDoctorWorkerInvocation), so a user's own
114
+ // interactive terminal can never land on the worker's confirmation-refusal
115
+ // path merely by passing this argv marker.
116
+ const { isRoutableDoctorWorkerInvocation, runDoctorWorker } = await import("./cli/doctor-worker");
117
+ if (argv.length !== 1 || !isRoutableDoctorWorkerInvocation(process.env, process.stdin.isTTY)) {
118
+ process.stderr.write("gjc doctor: invalid internal worker invocation\n");
119
+ process.exitCode = 2;
481
120
  return;
482
121
  }
483
- process.exitCode = await runFixtureReport(id);
122
+ await runDoctorWorker();
484
123
  return;
485
124
  }
486
- const normalizedArgv = normalizeResumeAlias(argv);
487
- const legacyArgv = routeLegacyRootArgv(normalizedArgv);
488
- const modelPresetsArgv =
489
- normalizedArgv[0] === "models" && normalizedArgv[1] === "presets" ? routeModelsAlias(normalizedArgv) : undefined;
490
- if (!legacyArgv && !modelPresetsArgv && hasRootHelpFlag(normalizedArgv)) {
491
- const { renderRootHelp } = await import("@gajae-code/utils/cli");
492
- const { getExtraHelpText } = await import("./cli/fast-help");
493
- renderRootHelp({ bin: APP_NAME, version: VERSION, commands: new Map([["launch", RootHelpCommand]]) });
494
- const extra = getExtraHelpText();
495
- if (extra.trim().length > 0) {
496
- process.stdout.write(`\n${extra}\n`);
125
+ if (argv[0] === "--internal-doctor-probe") {
126
+ if (argv.length !== 2 || (argv[1] !== "native" && argv[1] !== "projection")) {
127
+ process.stderr.write("gjc doctor: invalid internal probe invocation\n");
128
+ process.exitCode = 2;
129
+ return;
130
+ }
131
+ try {
132
+ const { runDoctorProbe } = await import("./cli/doctor/probe");
133
+ await runDoctorProbe(argv[1]);
134
+ } catch {
135
+ process.stderr.write("gjc doctor: internal probe unavailable\n");
136
+ process.exitCode = 3;
497
137
  }
498
138
  return;
499
139
  }
500
- if (!legacyArgv && hasRootVersionFlag(normalizedArgv)) {
501
- process.stdout.write(`${APP_NAME}/${VERSION}\n`);
502
- return;
503
- }
504
- const runArgv = legacyArgv ?? modelPresetsArgv ?? routeRootArgv(normalizedArgv);
505
- if (isStatsHelpFastPath(runArgv)) {
506
- showStatsFastHelp();
140
+ if (isDoctorArgv(argv)) {
141
+ await runDoctor(argv);
507
142
  return;
508
143
  }
509
- const bootstrap = interactiveBootstrapText(runArgv);
510
- if (bootstrap) process.stdout.write(bootstrap);
511
- await installRuntimeGlobals();
512
- return run({ bin: APP_NAME, version: VERSION, argv: runArgv, commands, help: showHelp });
144
+ const { runCliAfterAdmission } = await import("./cli-main");
145
+ await runCliAfterAdmission(argv);
513
146
  }
514
147
 
515
- if (import.meta.main) {
516
- await runCli(process.argv.slice(2));
517
- }
148
+ if (import.meta.main) await runCli(process.argv.slice(2));
@@ -1,6 +1,6 @@
1
- import { Command, renderCommandHelp } from "@gajae-code/utils/cli";
1
+ import { Command } from "@gajae-code/utils/cli";
2
2
  import { ensureWorkflowSettingsMigrated } from "../config/settings";
3
- import { runNativeAutoresearchCommand } from "../gjc-runtime/autoresearch-runtime";
3
+ import { isAutoresearchHelpInvocation, runNativeAutoresearchCommand } from "../gjc-runtime/autoresearch-runtime";
4
4
 
5
5
  export default class Autoresearch extends Command {
6
6
  static description = "Run native GJC Autoresearch workflow commands";
@@ -19,9 +19,15 @@ export default class Autoresearch extends Command {
19
19
  async run(): Promise<void> {
20
20
  // A read-only help request must not perform the workflow-settings
21
21
  // migration (which can create/drain agent.db, write config.yml, and
22
- // retire legacy settings.json): render help before the trigger.
23
- if (this.argv.includes("--help") || this.argv.includes("-h")) {
24
- renderCommandHelp("gjc", "autoresearch", Autoresearch);
22
+ // retire legacy settings.json): render help before the trigger. The
23
+ // native runtime owns help rendering because it is verb-aware — dropping
24
+ // to a generic command-level renderer here would discard the verb and
25
+ // hide every per-verb flag (`verdict --help`, `critic --help`, ...).
26
+ if (isAutoresearchHelpInvocation(this.argv)) {
27
+ const help = await runNativeAutoresearchCommand(this.argv, process.cwd());
28
+ if (help.stdout) process.stdout.write(help.stdout);
29
+ if (help.stderr) process.stderr.write(help.stderr);
30
+ process.exitCode = help.status;
25
31
  return;
26
32
  }
27
33
  await ensureWorkflowSettingsMigrated(process.cwd());
@@ -2,7 +2,6 @@
2
2
  * Generate shell completion specs for external completion engines.
3
3
  */
4
4
  import { Args, Command, Flags } from "@gajae-code/utils/cli";
5
- import { commands, RootHelpCommand } from "../cli";
6
5
  import {
7
6
  buildGjcFigSpec,
8
7
  defaultInshellisenseSpecDir,
@@ -10,6 +9,7 @@ import {
10
9
  installGjcInshellisenseSpec,
11
10
  renderFigSpecModule,
12
11
  } from "../cli/completion-cli";
12
+ import { commands, RootHelpCommand } from "../cli-main";
13
13
 
14
14
  const TARGETS = ["inshellisense", "fig"] as const;
15
15
 
@@ -0,0 +1,13 @@
1
+ import { Command } from "@gajae-code/utils/cli";
2
+ import { runDoctorCli } from "../cli/doctor-cli";
3
+
4
+ export default class Doctor extends Command {
5
+ static description = "Diagnose bootstrap, configuration, installation, plugins, and services";
6
+ static strict = false;
7
+ static examples = ["$ gjc doctor", "$ gjc doctor --json", "$ gjc doctor --dry-run --fix"];
8
+
9
+ async run(): Promise<void> {
10
+ const argv = process.argv.slice(3);
11
+ await runDoctorCli(argv);
12
+ }
13
+ }