@gajae-code/coding-agent 0.18.11 → 0.19.0

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 (462) hide show
  1. package/CHANGELOG.md +760 -0
  2. package/dist/types/async/job-manager.d.ts +7 -3
  3. package/dist/types/async/result-formatting.d.ts +2 -0
  4. package/dist/types/autoresearch/git.d.ts +1 -1
  5. package/dist/types/capability/fs.d.ts +2 -2
  6. package/dist/types/capability/rule.d.ts +7 -2
  7. package/dist/types/cli/accounts-cli.d.ts +2 -2
  8. package/dist/types/cli/append-system-prompt.d.ts +6 -0
  9. package/dist/types/cli/args.d.ts +7 -2
  10. package/dist/types/cli/customize-doctor-precedence.d.ts +16 -0
  11. package/dist/types/cli/customize-doctor.d.ts +4 -3
  12. package/dist/types/cli/doctor/install-repairs.d.ts +4 -1
  13. package/dist/types/cli/install-activation.d.ts +10 -4
  14. package/dist/types/cli/public-command-errors.d.ts +2 -0
  15. package/dist/types/cli/root-flags.d.ts +0 -12
  16. package/dist/types/cli/update-cli.d.ts +21 -3
  17. package/dist/types/cli-main.d.ts +0 -6
  18. package/dist/types/cli-ordinary.d.ts +2 -2
  19. package/dist/types/commands/accounts.d.ts +2 -1
  20. package/dist/types/commands/launch.d.ts +0 -6
  21. package/dist/types/commands/migrate.d.ts +1 -1
  22. package/dist/types/commands/sdk.d.ts +13 -0
  23. package/dist/types/commit/changelog/index.d.ts +1 -0
  24. package/dist/types/commit/map-reduce/index.d.ts +4 -4
  25. package/dist/types/config/autorouting-tier-map.d.ts +53 -1
  26. package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
  27. package/dist/types/config/config-hot-reload.d.ts +44 -0
  28. package/dist/types/config/file-lock.d.ts +52 -3
  29. package/dist/types/config/model-discovery-manager.d.ts +2 -0
  30. package/dist/types/config/model-profile-activation.d.ts +79 -9
  31. package/dist/types/config/model-registry.d.ts +72 -8
  32. package/dist/types/config/model-resolver.d.ts +7 -4
  33. package/dist/types/config/models-config-schema.d.ts +10 -0
  34. package/dist/types/config/settings-schema.d.ts +57 -4
  35. package/dist/types/config/settings.d.ts +33 -1
  36. package/dist/types/coordinator-mcp/server.d.ts +4 -0
  37. package/dist/types/customization/import.d.ts +2 -0
  38. package/dist/types/customization/types.d.ts +1 -1
  39. package/dist/types/dap/config.d.ts +8 -4
  40. package/dist/types/dap/session.d.ts +11 -2
  41. package/dist/types/debug/system-info.d.ts +6 -1
  42. package/dist/types/discovery/helpers.d.ts +7 -2
  43. package/dist/types/discovery/mcp-compat.d.ts +3 -1
  44. package/dist/types/edit/index.d.ts +5 -0
  45. package/dist/types/edit/modes/patch.d.ts +14 -0
  46. package/dist/types/edit/modes/replace.d.ts +3 -0
  47. package/dist/types/eval/py/runtime.d.ts +9 -0
  48. package/dist/types/exec/bash-executor.d.ts +12 -0
  49. package/dist/types/export/ttsr.d.ts +19 -0
  50. package/dist/types/extensibility/extensions/types.d.ts +5 -1
  51. package/dist/types/extensibility/slash-commands.d.ts +1 -0
  52. package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
  53. package/dist/types/gjc-runtime/ralplan-current-final.d.ts +54 -0
  54. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +5 -0
  55. package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
  56. package/dist/types/gjc-runtime/state-runtime.d.ts +0 -2
  57. package/dist/types/gjc-runtime/tmux-sessions.d.ts +24 -0
  58. package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +6 -0
  59. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +1 -0
  60. package/dist/types/harness-control-plane/receipt-spool.d.ts +4 -0
  61. package/dist/types/hindsight/content.d.ts +5 -6
  62. package/dist/types/internal-urls/types.d.ts +2 -0
  63. package/dist/types/lsp/clients/swiftlint-client.d.ts +0 -4
  64. package/dist/types/main.d.ts +23 -18
  65. package/dist/types/migrate/action-planner.d.ts +10 -1
  66. package/dist/types/migrate/adapters/codex.d.ts +2 -1
  67. package/dist/types/migrate/adapters/index.d.ts +42 -1
  68. package/dist/types/migrate/executor.d.ts +3 -1
  69. package/dist/types/migrate/hook-module.d.ts +23 -0
  70. package/dist/types/migrate/report.d.ts +2 -1
  71. package/dist/types/migrate/types.d.ts +82 -3
  72. package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
  73. package/dist/types/modes/components/model-selector.d.ts +43 -0
  74. package/dist/types/modes/components/settings-selector.d.ts +6 -0
  75. package/dist/types/modes/controllers/selector-controller.d.ts +2 -0
  76. package/dist/types/modes/prompt-suggestion-controller.d.ts +1 -1
  77. package/dist/types/modes/theme/theme.d.ts +1 -0
  78. package/dist/types/modes/utils/host-status.d.ts +15 -11
  79. package/dist/types/runtime-mcp/content-limits.d.ts +4 -0
  80. package/dist/types/runtime-mcp/manager.d.ts +7 -0
  81. package/dist/types/runtime-mcp/plugin-mcp-name-filter.d.ts +22 -0
  82. package/dist/types/runtime-mcp/project-host-values.d.ts +11 -5
  83. package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
  84. package/dist/types/sdk/broker/broker-exit.d.ts +3 -3
  85. package/dist/types/sdk/broker/broker.d.ts +29 -2
  86. package/dist/types/sdk/broker/daemon-entry.d.ts +11 -1
  87. package/dist/types/sdk/broker/doctor-restart.d.ts +1 -1
  88. package/dist/types/sdk/broker/ensure.d.ts +141 -9
  89. package/dist/types/sdk/broker/hop.d.ts +45 -0
  90. package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
  91. package/dist/types/sdk/broker/lifecycle.d.ts +22 -0
  92. package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
  93. package/dist/types/sdk/broker/session-index.d.ts +6 -1
  94. package/dist/types/sdk/broker/transport.d.ts +2 -0
  95. package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
  96. package/dist/types/sdk/bus/index.d.ts +44 -0
  97. package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
  98. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +9 -1
  99. package/dist/types/sdk/bus/telegram-daemon.d.ts +2 -0
  100. package/dist/types/sdk/bus/threaded-render.d.ts +2 -1
  101. package/dist/types/sdk/cli/session-cli.d.ts +0 -1
  102. package/dist/types/sdk/host/control/operations.d.ts +5 -1
  103. package/dist/types/sdk/host/events.d.ts +4 -0
  104. package/dist/types/sdk/host/host.d.ts +2 -1
  105. package/dist/types/sdk/host/prompt-image-upload.d.ts +43 -0
  106. package/dist/types/sdk/host/session-runtime.d.ts +40 -8
  107. package/dist/types/sdk/host/surface-policy.d.ts +2 -1
  108. package/dist/types/sdk/lifecycle/service.d.ts +12 -0
  109. package/dist/types/sdk/prompt-deadline-flush.d.ts +42 -4
  110. package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -0
  111. package/dist/types/sdk/prompt-status.d.ts +11 -4
  112. package/dist/types/sdk/protocol/adapter-validation.d.ts +10 -4
  113. package/dist/types/sdk/reconciliation-extensions.d.ts +1 -1
  114. package/dist/types/sdk/session-list.d.ts +1 -1
  115. package/dist/types/session/agent-session.d.ts +107 -9
  116. package/dist/types/session/internal/managed-session-scope.d.ts +2 -2
  117. package/dist/types/session/internal/managed-session-storage.d.ts +1 -1
  118. package/dist/types/session/internal/native-publish-outcome.d.ts +1 -1
  119. package/dist/types/session/messages.d.ts +5 -1
  120. package/dist/types/session/session-manager.d.ts +29 -3
  121. package/dist/types/session/startup-auth-config.d.ts +24 -2
  122. package/dist/types/session/streaming-output.d.ts +11 -0
  123. package/dist/types/session/terminal-abort.d.ts +3 -1
  124. package/dist/types/session-import/service.d.ts +1 -1
  125. package/dist/types/skill-state/workflow-mutation-guard.d.ts +20 -4
  126. package/dist/types/slash-commands/helpers/mcp.d.ts +5 -0
  127. package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
  128. package/dist/types/ssh/ssh-executor.d.ts +8 -1
  129. package/dist/types/system-prompt.d.ts +3 -2
  130. package/dist/types/task/executor.d.ts +19 -2
  131. package/dist/types/task/role-body.d.ts +11 -0
  132. package/dist/types/tools/ast-edit-write-path.d.ts +10 -0
  133. package/dist/types/tools/atomic-file-write.d.ts +9 -7
  134. package/dist/types/tools/awaiting-input.d.ts +28 -0
  135. package/dist/types/tools/bash-allowed-prefixes.d.ts +17 -0
  136. package/dist/types/tools/bash-skill-urls.d.ts +4 -0
  137. package/dist/types/tools/bash.d.ts +7 -0
  138. package/dist/types/tools/descriptors.d.ts +15 -2
  139. package/dist/types/tools/fetch.d.ts +7 -1
  140. package/dist/types/tools/index.d.ts +2 -0
  141. package/dist/types/tools/irc.d.ts +5 -3
  142. package/dist/types/tools/python.d.ts +1 -1
  143. package/dist/types/tools/report-issue.d.ts +41 -0
  144. package/dist/types/tools/subagent.d.ts +23 -0
  145. package/dist/types/tools/tmux-self-injection-guard.d.ts +2 -0
  146. package/dist/types/tools/ultragoal-ask-guard.d.ts +1 -1
  147. package/dist/types/tools/write.d.ts +2 -0
  148. package/dist/types/utils/file-mentions.d.ts +5 -0
  149. package/dist/types/utils/image-limits.d.ts +7 -0
  150. package/dist/types/utils/image-loading.d.ts +0 -1
  151. package/dist/types/utils/open.d.ts +0 -1
  152. package/dist/types/utils/pasted-image-loading.d.ts +1 -5
  153. package/dist/types/utils/prompt-suggestion.d.ts +2 -2
  154. package/dist/types/utils/shell-snapshot.d.ts +2 -0
  155. package/dist/types/utils/title-generator.d.ts +13 -3
  156. package/dist/types/web/scrapers/types.d.ts +8 -1
  157. package/dist/types/web/search/providers/codex.d.ts +6 -7
  158. package/dist/types/web/search/providers/insane.d.ts +7 -1
  159. package/dist/types/web/search/providers/searxng.d.ts +5 -0
  160. package/package.json +10 -9
  161. package/scripts/acp-conformance-agent.ts +12 -2
  162. package/scripts/build-binary.ts +2 -1
  163. package/scripts/capture-subagent-compact-panel-showcase.ts +105 -0
  164. package/scripts/generate-docs-index.ts +8 -1
  165. package/scripts/generate-sdk-operation-inventory.ts +38 -4
  166. package/src/async/job-manager.ts +356 -56
  167. package/src/async/result-formatting.ts +40 -0
  168. package/src/autoresearch/git.ts +9 -2
  169. package/src/autoresearch/prompts/prompt-setup.md +1 -1
  170. package/src/capability/fs.ts +58 -22
  171. package/src/capability/index.ts +2 -2
  172. package/src/capability/rule.ts +11 -2
  173. package/src/cli/accounts-cli.ts +176 -8
  174. package/src/cli/append-system-prompt.ts +12 -0
  175. package/src/cli/args.ts +11 -7
  176. package/src/cli/auth-broker-cli.ts +21 -11
  177. package/src/cli/customize-doctor-precedence.ts +31 -0
  178. package/src/cli/customize-doctor.ts +49 -39
  179. package/src/cli/doctor/install-repairs.ts +35 -5
  180. package/src/cli/fast-help.ts +1 -3
  181. package/src/cli/install-activation.ts +47 -4
  182. package/src/cli/migrate-cli.ts +19 -6
  183. package/src/cli/public-command-errors.ts +6 -0
  184. package/src/cli/root-flags.ts +2 -4
  185. package/src/cli/stats-cli.ts +9 -5
  186. package/src/cli/update-cli.ts +471 -13
  187. package/src/cli-ordinary.ts +7 -2
  188. package/src/commands/accounts.ts +10 -5
  189. package/src/commands/harness.ts +25 -15
  190. package/src/commands/migrate.ts +3 -3
  191. package/src/commands/sdk.ts +277 -50
  192. package/src/commands/ultragoal.ts +16 -8
  193. package/src/commit/agentic/agent.ts +6 -6
  194. package/src/commit/analysis/conventional.ts +14 -5
  195. package/src/commit/changelog/index.ts +39 -1
  196. package/src/commit/map-reduce/index.ts +7 -7
  197. package/src/commit/message.ts +10 -3
  198. package/src/commit/pipeline.ts +12 -12
  199. package/src/config/autorouting-tier-map.ts +50 -1
  200. package/src/config/config-file.ts +106 -3
  201. package/src/config/config-hot-reload-trust.ts +148 -0
  202. package/src/config/config-hot-reload.ts +742 -0
  203. package/src/config/file-lock.ts +1615 -328
  204. package/src/config/keybindings.ts +154 -7
  205. package/src/config/model-bindings-applier.ts +85 -47
  206. package/src/config/model-discovery-manager.ts +10 -0
  207. package/src/config/model-profile-activation.ts +889 -148
  208. package/src/config/model-registry.ts +1706 -205
  209. package/src/config/model-resolver.ts +52 -22
  210. package/src/config/models-config-schema.ts +6 -0
  211. package/src/config/settings-schema.ts +73 -4
  212. package/src/config/settings.ts +460 -24
  213. package/src/coordinator-mcp/policy.ts +26 -1
  214. package/src/coordinator-mcp/server.ts +37 -2
  215. package/src/crash/sanitize.ts +7 -1
  216. package/src/customization/import.ts +279 -8
  217. package/src/customization/inventory.ts +24 -8
  218. package/src/customization/types.ts +1 -0
  219. package/src/dap/client.ts +3 -2
  220. package/src/dap/config.ts +31 -11
  221. package/src/dap/defaults.json +1 -1
  222. package/src/dap/session.ts +161 -36
  223. package/src/debug/crash-diagnostics.ts +89 -6
  224. package/src/debug/report-bundle.ts +90 -2
  225. package/src/debug/system-info.ts +8 -3
  226. package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +21 -7
  227. package/src/discovery/agents-md.ts +1 -1
  228. package/src/discovery/builtin.ts +4 -3
  229. package/src/discovery/helpers.ts +25 -16
  230. package/src/discovery/mcp-compat.ts +120 -17
  231. package/src/edit/apply-patch/index.ts +12 -1
  232. package/src/edit/index.ts +204 -22
  233. package/src/edit/modes/patch.ts +214 -8
  234. package/src/edit/modes/replace.ts +136 -0
  235. package/src/eval/js/context-manager.ts +29 -3
  236. package/src/eval/js/worker-entry.ts +51 -18
  237. package/src/eval/py/executor.ts +14 -4
  238. package/src/eval/py/runner.py +144 -5
  239. package/src/eval/py/runtime.ts +44 -4
  240. package/src/exec/bash-executor.ts +81 -4
  241. package/src/exec/bash-shell-guardian.ts +4 -1
  242. package/src/exec/bash-shell-supervisor.ts +8 -4
  243. package/src/exec/isolated-shell.ts +5 -1
  244. package/src/exec/non-interactive-env.ts +0 -1
  245. package/src/export/html/index.ts +86 -6
  246. package/src/export/ttsr.ts +176 -1
  247. package/src/extensibility/custom-tools/wrapper.ts +3 -1
  248. package/src/extensibility/extensions/loader.ts +10 -1
  249. package/src/extensibility/extensions/ouroboros-ooo-bridge.ts +63 -1
  250. package/src/extensibility/extensions/types.ts +5 -1
  251. package/src/extensibility/hooks/loader.ts +10 -2
  252. package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
  253. package/src/extensibility/plugins/marketplace/manager.ts +36 -10
  254. package/src/extensibility/slash-commands.ts +5 -0
  255. package/src/gjc-runtime/gc-runtime.ts +37 -7
  256. package/src/gjc-runtime/launch-tmux.ts +30 -15
  257. package/src/gjc-runtime/launch-worktree.test.ts +148 -0
  258. package/src/gjc-runtime/launch-worktree.ts +101 -14
  259. package/src/gjc-runtime/managed-owner-admission.ts +46 -2
  260. package/src/gjc-runtime/ralplan-current-final.ts +294 -0
  261. package/src/gjc-runtime/ralplan-runtime.ts +95 -1
  262. package/src/gjc-runtime/session-resolution.ts +38 -6
  263. package/src/gjc-runtime/session-state-lock.ts +59 -14
  264. package/src/gjc-runtime/state-runtime.ts +23 -19
  265. package/src/gjc-runtime/state-writer.ts +109 -5
  266. package/src/gjc-runtime/tmux-sessions.ts +93 -13
  267. package/src/gjc-runtime/ultragoal-change-set.ts +90 -11
  268. package/src/gjc-runtime/ultragoal-guard.ts +9 -1
  269. package/src/gjc-runtime/ultragoal-runtime.ts +15 -5
  270. package/src/harness-control-plane/finalize.ts +11 -0
  271. package/src/harness-control-plane/receipt-spool.ts +105 -28
  272. package/src/harness-control-plane/storage.ts +124 -6
  273. package/src/hindsight/content.ts +116 -16
  274. package/src/hindsight/mental-models.ts +22 -10
  275. package/src/hindsight/state.ts +7 -4
  276. package/src/hooks/native-skill-hook.ts +17 -12
  277. package/src/internal-urls/artifact-protocol.ts +3 -1
  278. package/src/internal-urls/docs-index.generated.ts +23 -22
  279. package/src/internal-urls/local-protocol.ts +167 -8
  280. package/src/internal-urls/types.ts +2 -0
  281. package/src/lsp/client.ts +2 -1
  282. package/src/lsp/clients/biome-client.ts +2 -0
  283. package/src/lsp/clients/swiftlint-client.ts +2 -0
  284. package/src/lsp/index.ts +29 -0
  285. package/src/lsp/workspace-path.ts +23 -0
  286. package/src/main.ts +330 -92
  287. package/src/memories/index.ts +25 -2
  288. package/src/migrate/action-planner.ts +574 -2
  289. package/src/migrate/adapters/claude-code.ts +162 -5
  290. package/src/migrate/adapters/codex.ts +77 -7
  291. package/src/migrate/adapters/index.ts +258 -5
  292. package/src/migrate/adapters/opencode.ts +10 -1
  293. package/src/migrate/executor.ts +222 -7
  294. package/src/migrate/hook-module.ts +193 -0
  295. package/src/migrate/report.ts +63 -2
  296. package/src/migrate/types.ts +84 -4
  297. package/src/modes/DESIGN.md +51 -0
  298. package/src/modes/acp/acp-agent.ts +10 -1
  299. package/src/modes/acp/permission-mode.ts +18 -1
  300. package/src/modes/components/agent-dashboard.ts +20 -4
  301. package/src/modes/components/assistant-message.ts +55 -1
  302. package/src/modes/components/customization/customization-dashboard.ts +7 -0
  303. package/src/modes/components/customization/import-wizard.ts +29 -3
  304. package/src/modes/components/model-selector.ts +157 -103
  305. package/src/modes/components/settings-selector.ts +103 -37
  306. package/src/modes/components/welcome.ts +3 -1
  307. package/src/modes/controllers/command-controller.ts +300 -9
  308. package/src/modes/controllers/event-controller.ts +1 -1
  309. package/src/modes/controllers/extension-ui-controller.ts +31 -1
  310. package/src/modes/controllers/goal-mode-controller.ts +79 -10
  311. package/src/modes/controllers/input-controller.ts +2 -0
  312. package/src/modes/controllers/plan-mode-controller.ts +66 -11
  313. package/src/modes/controllers/runtime-mcp-command-controller.ts +7 -6
  314. package/src/modes/controllers/selector-controller.ts +76 -7
  315. package/src/modes/interactive-mode.ts +123 -4
  316. package/src/modes/prompt-suggestion-controller.ts +1 -1
  317. package/src/modes/runtime-init.ts +5 -1
  318. package/src/modes/theme/theme.ts +15 -0
  319. package/src/modes/utils/host-status.ts +21 -10
  320. package/src/prompts/agent-fragments/browser-aside.md +2 -2
  321. package/src/prompts/system/irc-incoming.md +3 -1
  322. package/src/prompts/tools/debug.md +1 -1
  323. package/src/prompts/tools/irc.md +1 -1
  324. package/src/prompts/tools/read.md +1 -1
  325. package/src/prompts/tools/report-issue.md +13 -0
  326. package/src/prompts/tools/task.md +1 -1
  327. package/src/runtime-credential-selector.ts +2 -2
  328. package/src/runtime-mcp/content-limits.ts +7 -0
  329. package/src/runtime-mcp/manager-pool.test.ts +5 -4
  330. package/src/runtime-mcp/manager.ts +40 -3
  331. package/src/runtime-mcp/oauth-flow.ts +32 -6
  332. package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
  333. package/src/runtime-mcp/project-host-values.ts +12 -8
  334. package/src/runtime-mcp/render.ts +16 -1
  335. package/src/runtime-mcp/tool-bridge.ts +194 -21
  336. package/src/runtime-mcp/transports/stdio.ts +2 -1
  337. package/src/sdk/broker/broker-exit.ts +10 -5
  338. package/src/sdk/broker/broker.ts +484 -85
  339. package/src/sdk/broker/daemon-entry.ts +338 -116
  340. package/src/sdk/broker/doctor-restart.ts +2 -1
  341. package/src/sdk/broker/ensure.ts +1214 -268
  342. package/src/sdk/broker/hop.ts +286 -0
  343. package/src/sdk/broker/lifecycle-ledger.ts +38 -11
  344. package/src/sdk/broker/lifecycle.ts +102 -6
  345. package/src/sdk/broker/lock-host-identity.ts +29 -0
  346. package/src/sdk/broker/session-index.ts +91 -16
  347. package/src/sdk/broker/transport.ts +17 -1
  348. package/src/sdk/bus/chat-command-policy.ts +16 -3
  349. package/src/sdk/bus/chat-daemon-control.ts +2 -2
  350. package/src/sdk/bus/index.ts +460 -35
  351. package/src/sdk/bus/reconciliation-store.ts +201 -8
  352. package/src/sdk/bus/session-control.ts +2 -0
  353. package/src/sdk/bus/slack-daemon.ts +105 -9
  354. package/src/sdk/bus/telegram-daemon-contract.ts +9 -1
  355. package/src/sdk/bus/telegram-daemon.ts +10 -2
  356. package/src/sdk/bus/threaded-render.ts +20 -1
  357. package/src/sdk/cli/session-cli.ts +23 -6
  358. package/src/sdk/host/control/dispatch.ts +13 -1
  359. package/src/sdk/host/control/operations.ts +10 -1
  360. package/src/sdk/host/events.ts +67 -4
  361. package/src/sdk/host/host.ts +8 -2
  362. package/src/sdk/host/prompt-image-upload.ts +438 -0
  363. package/src/sdk/host/sdk-surface-parity.test.ts +15 -0
  364. package/src/sdk/host/session-runtime.test.ts +1737 -129
  365. package/src/sdk/host/session-runtime.ts +684 -83
  366. package/src/sdk/host/surface-policy.ts +4 -0
  367. package/src/sdk/host/websocket-transport.lifecycle.test.ts +90 -2
  368. package/src/sdk/host/websocket-transport.ts +19 -7
  369. package/src/sdk/lifecycle/service.ts +15 -1
  370. package/src/sdk/prompt-deadline-flush.ts +78 -5
  371. package/src/sdk/prompt-deadline-manager.ts +68 -14
  372. package/src/sdk/prompt-status.ts +6 -4
  373. package/src/sdk/protocol/adapter-validation.ts +81 -12
  374. package/src/sdk/protocol/operation-inventory.generated.json +261 -2
  375. package/src/sdk/protocol/operation-registry.ts +33 -3
  376. package/src/sdk/reconciliation-extensions.ts +1 -0
  377. package/src/sdk/session-list.ts +1 -0
  378. package/src/sdk/session.ts +237 -97
  379. package/src/session/agent-session.ts +2726 -479
  380. package/src/session/history-storage.ts +182 -12
  381. package/src/session/internal/managed-session-scope.ts +173 -57
  382. package/src/session/internal/managed-session-storage.ts +85 -12
  383. package/src/session/internal/native-publish-outcome.ts +5 -1
  384. package/src/session/messages.ts +47 -6
  385. package/src/session/session-manager.ts +326 -19
  386. package/src/session/startup-auth-config.ts +116 -8
  387. package/src/session/streaming-output.ts +262 -4
  388. package/src/session/terminal-abort.ts +14 -2
  389. package/src/session-import/redact.ts +53 -2
  390. package/src/session-import/service.ts +1 -0
  391. package/src/skill-state/workflow-mutation-guard.ts +2145 -206
  392. package/src/slash-commands/builtin-registry.ts +21 -6
  393. package/src/slash-commands/helpers/credential-switch.ts +10 -5
  394. package/src/slash-commands/helpers/mcp.ts +11 -3
  395. package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
  396. package/src/ssh/ssh-executor.ts +9 -2
  397. package/src/stt/recorder.ts +26 -9
  398. package/src/system-prompt.ts +61 -16
  399. package/src/task/executor.ts +115 -20
  400. package/src/task/index.ts +389 -175
  401. package/src/task/role-body.ts +84 -0
  402. package/src/task/token-log-mode.test.ts +162 -0
  403. package/src/task/token-log.ts +91 -2
  404. package/src/tools/archive-reader.ts +650 -37
  405. package/src/tools/ask.ts +1 -0
  406. package/src/tools/ast-edit-write-path.ts +64 -0
  407. package/src/tools/ast-edit.ts +18 -1
  408. package/src/tools/ast-grep.ts +7 -2
  409. package/src/tools/atomic-file-write.ts +46 -15
  410. package/src/tools/auto-generated-guard.ts +15 -3
  411. package/src/tools/awaiting-input.ts +114 -0
  412. package/src/tools/bash-allowed-prefixes.ts +214 -6
  413. package/src/tools/bash-interactive.ts +14 -2
  414. package/src/tools/bash-skill-urls.ts +58 -5
  415. package/src/tools/bash.ts +113 -26
  416. package/src/tools/browser/tab-worker.ts +39 -13
  417. package/src/tools/browser.ts +17 -7
  418. package/src/tools/cron.ts +10 -1
  419. package/src/tools/debug.ts +16 -8
  420. package/src/tools/descriptors.test.ts +44 -0
  421. package/src/tools/descriptors.ts +50 -6
  422. package/src/tools/eval.ts +15 -0
  423. package/src/tools/fetch.ts +93 -4
  424. package/src/tools/gh.ts +27 -12
  425. package/src/tools/image-gen.ts +20 -6
  426. package/src/tools/index.ts +2 -0
  427. package/src/tools/irc.ts +5 -3
  428. package/src/tools/monitor.ts +9 -1
  429. package/src/tools/output-meta.ts +74 -5
  430. package/src/tools/python.ts +1 -1
  431. package/src/tools/read.ts +26 -37
  432. package/src/tools/recipe/runner.ts +23 -12
  433. package/src/tools/render-utils.ts +2 -2
  434. package/src/tools/report-issue.ts +184 -0
  435. package/src/tools/search.ts +3 -2
  436. package/src/tools/ssh.ts +274 -8
  437. package/src/tools/subagent-render.ts +114 -12
  438. package/src/tools/subagent.ts +118 -5
  439. package/src/tools/tmux-self-injection-guard.ts +3301 -122
  440. package/src/tools/todo-write.ts +41 -3
  441. package/src/tools/tool-catalog.generated.ts +32 -4
  442. package/src/tools/ultragoal-ask-guard.ts +13 -1
  443. package/src/tools/write.ts +42 -3
  444. package/src/tui/tree-list.ts +15 -1
  445. package/src/utils/commit-message-generator.ts +12 -4
  446. package/src/utils/external-editor.ts +21 -7
  447. package/src/utils/file-mentions.ts +75 -7
  448. package/src/utils/git.ts +38 -7
  449. package/src/utils/image-limits.ts +8 -0
  450. package/src/utils/image-loading.ts +1 -1
  451. package/src/utils/open.ts +73 -4
  452. package/src/utils/pasted-image-loading.ts +9 -8
  453. package/src/utils/prompt-suggestion.ts +5 -4
  454. package/src/utils/shell-snapshot.ts +9 -1
  455. package/src/utils/title-generator.ts +72 -22
  456. package/src/web/scrapers/index.ts +3 -1
  457. package/src/web/scrapers/types.ts +8 -0
  458. package/src/web/scrapers/youtube.ts +3 -2
  459. package/src/web/search/index.ts +2 -1
  460. package/src/web/search/providers/codex.ts +29 -32
  461. package/src/web/search/providers/insane.ts +91 -28
  462. package/src/web/search/providers/searxng.ts +62 -10
@@ -25,6 +25,7 @@ import {
25
25
  AuthStorage,
26
26
  type CredentialDisabledEvent,
27
27
  DEFAULT_AUTH_BROKER_BIND,
28
+ formatOAuthIdentityLabel,
28
29
  getEnvApiKey,
29
30
  getOAuthProviders,
30
31
  listProvidersWithEnvKey,
@@ -568,19 +569,21 @@ interface MigrateSkip {
568
569
 
569
570
  function credentialIdentity(provider: string, credential: AuthCredential): string {
570
571
  if (credential.type === "api_key") return "(api key)";
571
- return credential.email ?? credential.accountId ?? credential.projectId ?? `<${provider} oauth>`;
572
+ return formatOAuthIdentityLabel(credential) ?? `<${provider} oauth>`;
572
573
  }
573
574
 
574
575
  /**
575
576
  * Build the set of "identities already on the broker" so re-runs are idempotent.
576
- * For OAuth, identity = email|accountId|projectId. For api_key, we collapse
577
- * to a single marker per provider (broker has no concept of "multiple api keys
578
- * per provider with different identities"; upsert would coalesce them).
577
+ * For OAuth, identity = email|accountId|projectId, scoped to the organization
578
+ * when the credential carries one (one account can sign in to several
579
+ * organizations). For api_key, we collapse to a single marker per provider
580
+ * (broker has no concept of "multiple api keys per provider with different
581
+ * identities"; upsert would coalesce them).
579
582
  */
580
583
  function indexBrokerSnapshot(snapshot: {
581
584
  credentials: Array<{
582
585
  provider: string;
583
- credential: { type: string; email?: string; accountId?: string; projectId?: string };
586
+ credential: { type: string; email?: string; accountId?: string; projectId?: string; organizationId?: string };
584
587
  }>;
585
588
  }): Map<string, Set<string>> {
586
589
  const out = new Map<string, Set<string>>();
@@ -589,22 +592,29 @@ function indexBrokerSnapshot(snapshot: {
589
592
  if (entry.credential.type === "api_key") {
590
593
  ids.add("@api_key");
591
594
  } else {
592
- if (entry.credential.email) ids.add(`email:${entry.credential.email}`);
593
- if (entry.credential.accountId) ids.add(`accountId:${entry.credential.accountId}`);
594
- if (entry.credential.projectId) ids.add(`projectId:${entry.credential.projectId}`);
595
+ const org = organizationSuffix(entry.credential.organizationId);
596
+ if (entry.credential.email) ids.add(`email:${entry.credential.email}${org}`);
597
+ if (entry.credential.accountId) ids.add(`accountId:${entry.credential.accountId}${org}`);
598
+ if (entry.credential.projectId) ids.add(`projectId:${entry.credential.projectId}${org}`);
595
599
  }
596
600
  out.set(entry.provider, ids);
597
601
  }
598
602
  return out;
599
603
  }
600
604
 
605
+ function organizationSuffix(organizationId: string | undefined): string {
606
+ const trimmed = organizationId?.trim();
607
+ return trimmed ? `|org:${trimmed}` : "";
608
+ }
609
+
601
610
  function brokerAlreadyHas(existing: Map<string, Set<string>>, provider: string, credential: AuthCredential): boolean {
602
611
  const ids = existing.get(provider);
603
612
  if (!ids) return false;
604
613
  if (credential.type === "api_key") return ids.has("@api_key");
605
- if (credential.email && ids.has(`email:${credential.email}`)) return true;
606
- if (credential.accountId && ids.has(`accountId:${credential.accountId}`)) return true;
607
- if (credential.projectId && ids.has(`projectId:${credential.projectId}`)) return true;
614
+ const org = organizationSuffix(credential.organizationId);
615
+ if (credential.email && ids.has(`email:${credential.email}${org}`)) return true;
616
+ if (credential.accountId && ids.has(`accountId:${credential.accountId}${org}`)) return true;
617
+ if (credential.projectId && ids.has(`projectId:${credential.projectId}${org}`)) return true;
608
618
  return false;
609
619
  }
610
620
 
@@ -0,0 +1,31 @@
1
+ export interface DiscoveryPrecedenceCandidate {
2
+ key: string | undefined;
3
+ provider: string;
4
+ scope: "user" | "project" | "native";
5
+ eligible: boolean;
6
+ enabled: boolean;
7
+ }
8
+
9
+ export interface DiscoveryPrecedenceResult {
10
+ shadowed: boolean;
11
+ shadowedBy?: { provider: string; scope: DiscoveryPrecedenceCandidate["scope"] };
12
+ }
13
+
14
+ /** Resolve ordered discovery candidates without allowing ineligible or disabled entries to own keys. */
15
+ export function resolveDiscoveryPrecedence(
16
+ candidates: readonly DiscoveryPrecedenceCandidate[],
17
+ ): DiscoveryPrecedenceResult[] {
18
+ const winners = new Map<string, { provider: string; scope: DiscoveryPrecedenceCandidate["scope"] }>();
19
+
20
+ return candidates.map(candidate => {
21
+ if (!candidate.eligible || candidate.key === undefined) return { shadowed: false };
22
+
23
+ const winner = winners.get(candidate.key);
24
+ if (winner) return { shadowed: true, shadowedBy: winner };
25
+
26
+ if (candidate.enabled) {
27
+ winners.set(candidate.key, { provider: candidate.provider, scope: candidate.scope });
28
+ }
29
+ return { shadowed: false };
30
+ });
31
+ }
@@ -54,6 +54,7 @@ import {
54
54
  isCanonicalGjcWorkflowSkillFilesystemAlias,
55
55
  } from "../skill-state/canonical-skills";
56
56
  import { expandTilde } from "../tools/path-utils";
57
+ import { resolveDiscoveryPrecedence } from "./customize-doctor-precedence";
57
58
 
58
59
  // =============================================================================
59
60
  // Public types (stable JSON contract)
@@ -67,9 +68,10 @@ export type CustomizeSurfaceKind = "mcp" | "skill" | "hook" | "tool" | "extensio
67
68
  *
68
69
  * - `canonical`: project/global `.gjc` entries and GJC bundled defaults — the
69
70
  * primary load path and the persisted authority for sessions.
70
- * - `convention`: items from registered non-native conventions that are part of
71
- * the discovery load path (claude-plugins, claude/codex hooks, agents,
72
- * cursor, gemini, opencode, windsurf, cline, github, mcp-json, ssh).
71
+ * - `convention`: items exposed by registered non-native discovery providers
72
+ * (claude-plugins, claude/codex hooks, agents, cursor, gemini, opencode,
73
+ * windsurf, cline, github, mcp-json, ssh). The item status identifies whether
74
+ * a discovered item is active, stored-only, or otherwise excluded at runtime.
73
75
  * - `import-candidate`: Claude Code / Codex project (+ global) files on
74
76
  * surfaces GJC deliberately never loads. Reported for provenance only; never
75
77
  * active runtime authority. Candidates for a future import flow (#4291).
@@ -267,7 +269,7 @@ const SOURCE_CLASS_DESCRIPTIONS: Array<{ sourceClass: CustomizeSourceClass; desc
267
269
  {
268
270
  sourceClass: "convention",
269
271
  description:
270
- "Items from other registered conventions (claude-plugins, claude/codex hooks, agents, cursor, gemini, opencode, windsurf, cline, github, mcp-json, ssh) that are part of the discovery load path.",
272
+ "Items exposed by registered convention providers (claude-plugins, claude/codex hooks, agents, cursor, gemini, opencode, windsurf, cline, github, mcp-json, ssh); item status identifies runtime eligibility.",
271
273
  },
272
274
  {
273
275
  sourceClass: "import-candidate",
@@ -394,6 +396,7 @@ async function discoverCapability<T extends { _source: SourceMeta }>(
394
396
  nameOf: (item: T) => string;
395
397
  pathOf: (item: T) => string;
396
398
  extensionIdOf?: (item: T) => string | undefined;
399
+ precedenceEligible?: (item: T) => boolean;
397
400
  },
398
401
  ): Promise<DiscoveredSet<T>> {
399
402
  const disabledProviders = new Set(activeSettings.get("disabledProviders"));
@@ -405,41 +408,34 @@ async function discoverCapability<T extends { _source: SourceMeta }>(
405
408
  includeDisabledProviders: true,
406
409
  });
407
410
 
408
- // First item per dedup key wins (highest priority provider first in `all`).
409
- const winners = new Map<string, { provider: string; scope: "user" | "project" | "native" }>();
410
- const entries: DiscoveredEntry<T>[] = [];
411
- for (const item of result.all) {
412
- const key = capability.key(item);
413
- const scope = scopeOf(item._source);
414
- let shadowed = (item as { _shadowed?: boolean })._shadowed === true;
415
- let shadowedBy: { provider: string; scope: string } | undefined;
416
- if (key !== undefined) {
417
- const winner = winners.get(key);
418
- if (winner) {
419
- shadowed = true;
420
- shadowedBy = winner;
421
- } else if (!disabledProviders.has(item._source.provider)) {
422
- // Only enabled providers can own a dedup key; a disabled
423
- // higher-priority provider must never shadow an enabled
424
- // lower-priority source (includeDisabledProviders reports it
425
- // as a listed item without giving it effective precedence).
426
- winners.set(key, { provider: item._source.provider, scope });
427
- }
428
- }
429
- entries.push({
411
+ // Resolve provider-order winners only after applying surface eligibility and
412
+ // the configured provider-disabled policy.
413
+ const resolvedPrecedence = resolveDiscoveryPrecedence(
414
+ result.all.map(item => ({
415
+ key: capability.key(item),
416
+ provider: item._source.provider,
417
+ scope: scopeOf(item._source),
418
+ eligible: options.precedenceEligible?.(item) ?? true,
419
+ enabled: !disabledProviders.has(item._source.provider),
420
+ })),
421
+ );
422
+ const entries: DiscoveredEntry<T>[] = result.all.map((item, index) => {
423
+ const precedence = resolvedPrecedence[index];
424
+ if (!precedence) throw new Error("discovery precedence result is missing an item");
425
+ return {
430
426
  item,
431
427
  name: options.nameOf(item),
432
428
  path: options.pathOf(item),
433
429
  provider: item._source.provider,
434
430
  providerName: item._source.providerName,
435
- scope,
431
+ scope: scopeOf(item._source),
436
432
  priority: capability.providers.find(p => p.id === item._source.provider)?.priority ?? 0,
437
- shadowed,
438
- shadowedBy,
433
+ shadowed: precedence.shadowed,
434
+ shadowedBy: precedence.shadowedBy,
439
435
  invalidReason: capability.validate?.(item),
440
436
  extensionId: options.extensionIdOf?.(item),
441
- });
442
- }
437
+ };
438
+ });
443
439
 
444
440
  entries.sort((a, b) => a.name.localeCompare(b.name) || a.provider.localeCompare(b.provider));
445
441
 
@@ -954,6 +950,7 @@ async function collectHooks(cwd: string, activeSettings: SettingsInstance): Prom
954
950
  return collectNotExecutedAtStartup("hook", hookCapability, cwd, activeSettings, {
955
951
  nameOf: hook => hook.name,
956
952
  pathOf: hook => hook.path,
953
+ precedenceEligible: hook => hook.level !== "project",
957
954
  notExecutedDetail:
958
955
  "Trusted filesystem hook module discovered for session-start activation. Doctor does not execute the module, so dynamic Function Hook registrations and effective runtime order remain opaque until a session loads it.",
959
956
  notExecutedRemediation: [
@@ -989,6 +986,7 @@ async function collectExtensions(cwd: string, activeSettings: SettingsInstance):
989
986
  interface NotExecutedOptions<T extends { _source: SourceMeta }> {
990
987
  nameOf: (item: T) => string;
991
988
  pathOf: (item: T) => string;
989
+ precedenceEligible?: (item: T) => boolean;
992
990
  notExecutedDetail: string;
993
991
  notExecutedRemediation: string[];
994
992
  }
@@ -1004,6 +1002,7 @@ async function collectNotExecutedAtStartup<T extends { _source: SourceMeta }>(
1004
1002
  nameOf: options.nameOf,
1005
1003
  pathOf: options.pathOf,
1006
1004
  extensionIdOf: item => capability.toExtensionId?.(item),
1005
+ precedenceEligible: options.precedenceEligible,
1007
1006
  });
1008
1007
  const disabledExts = disabledExtensionIds(activeSettings);
1009
1008
  const disabledProviders = new Set(activeSettings.get("disabledProviders"));
@@ -1019,6 +1018,18 @@ async function collectNotExecutedAtStartup<T extends { _source: SourceMeta }>(
1019
1018
  [`Fix ${entry.path}`],
1020
1019
  );
1021
1020
  }
1021
+ if (kind === "hook" && entry.scope === "project") {
1022
+ return finalizeItem(
1023
+ base,
1024
+ "stored-only",
1025
+ "storage-only",
1026
+ "Project-scoped hooks are stored for inspection, but ordinary sessions do not load repository hook modules.",
1027
+ [
1028
+ "Import the hook into Global .gjc to load it for future sessions",
1029
+ "or configure an explicit hook path if repository-local activation is intentional",
1030
+ ],
1031
+ );
1032
+ }
1022
1033
  if (entry.extensionId !== undefined && disabledExts.has(entry.extensionId)) {
1023
1034
  return finalizeItem(
1024
1035
  base,
@@ -1360,13 +1371,12 @@ async function collectPluginBundles(cwd: string): Promise<CustomizeDoctorSurface
1360
1371
  // Foreign conventions (Claude project / Codex project)
1361
1372
  //
1362
1373
  // Claude Code / Codex project hooks are discovered by the registered
1363
- // claude-hooks/codex-hooks providers (see discovery/index.ts) and appear in the
1364
- // Hooks surface above; sessions surface them in the extension dashboard but do
1365
- // not execute hook files. Every OTHER `.claude`/`.codex` surface (MCP, skills,
1366
- // tools, extensions, commands, prompts, settings) is deliberately not part of
1367
- // the load path: the doctor reports those files by invoking the canonical
1368
- // provider load functions directly (without registering the providers) and
1369
- // marks every such item as `ignored`.
1374
+ // claude-hooks/codex-hooks providers (see discovery/index.ts), but like native
1375
+ // project hooks are stored-only and are not imported by ordinary sessions.
1376
+ // Every OTHER `.claude`/`.codex` surface (MCP, skills, tools, extensions,
1377
+ // commands, prompts, settings) is deliberately not part of the load path: the
1378
+ // doctor reports those files by invoking canonical provider load functions
1379
+ // directly (without registering the providers) and marks them `ignored`.
1370
1380
  // =============================================================================
1371
1381
 
1372
1382
  interface ForeignConventionDescriptor {
@@ -1468,7 +1478,7 @@ function foreignItem(
1468
1478
  async function collectForeignConventions(cwd: string): Promise<ForeignConventionCollection> {
1469
1479
  const ctx: LoadContext = { cwd, home: os.homedir(), repoRoot: await findRepoRoot(cwd) };
1470
1480
  const itemsByKind: Map<CustomizeSurfaceKind, CustomizeDoctorItem[]> = new Map();
1471
- const policyNote = `${FOREIGN_CONVENTIONS.map(d => d.dirName).join(" and ")} project hooks are discovered by GJC (see the Hooks surface); all other ${FOREIGN_CONVENTIONS.map(d => d.providerName).join(" / ")} project config surfaces (MCP servers, skills, tools, extensions, commands, prompts, settings) are not part of the GJC load path. Those files are reported below as import candidates for provenance but are never discovered by sessions.`;
1481
+ const policyNote = `${FOREIGN_CONVENTIONS.map(d => d.dirName).join(" and ")} project hooks are shown as stored-only (see the Hooks surface); ordinary sessions do not load repository hook modules. All other ${FOREIGN_CONVENTIONS.map(d => d.providerName).join(" / ")} project config surfaces (MCP servers, skills, tools, extensions, commands, prompts, settings) are not part of the GJC load path and are reported below as import candidates for provenance.`;
1472
1482
 
1473
1483
  for (const desc of FOREIGN_CONVENTIONS) {
1474
1484
  const inspection = await desc.inspect(ctx);
@@ -14,7 +14,7 @@ import { randomUUID } from "node:crypto";
14
14
  import { realpathSync } from "node:fs";
15
15
  import * as fs from "node:fs/promises";
16
16
  import * as path from "node:path";
17
- import { isCompiledBinary, VERSION } from "@gajae-code/utils";
17
+ import { isCompiledBinary, logger, VERSION } from "@gajae-code/utils";
18
18
  import { isUpdateChannel } from "../../config/update-channel";
19
19
  import {
20
20
  activationRecordPath,
@@ -27,8 +27,10 @@ import {
27
27
  snapshotRegularFile,
28
28
  } from "../install-activation";
29
29
  import {
30
+ ActivationRetryCandidateRepointError,
30
31
  acquireBinaryUpdateLock,
31
32
  fetchAndVerifyOfficialPinnedCandidate,
33
+ InstallationAccessDeniedError,
32
34
  isProtectedSourcePathForInstall,
33
35
  replaceBinaryForUpdate,
34
36
  smokeTestPinnedCandidate,
@@ -111,8 +113,10 @@ export interface InstallRepairResult {
111
113
  readonly reason?: string;
112
114
  readonly recordPath?: string;
113
115
  readonly sideEffectStarted: boolean;
114
- /** Present only for a pre-mutation Windows sharing violation (nothing was renamed). */
116
+ /** Native Windows status returned by exact replacement. */
115
117
  readonly windowsErrorCode?: string;
118
+ readonly stagingCleanupWarning?: string;
119
+ readonly retainedPaths?: InstallationAccessDeniedError["retainedPaths"];
116
120
  readonly before?: { readonly identity?: FileIdentity; readonly digest?: string };
117
121
  readonly after?: { readonly identity?: FileIdentity; readonly digest?: string; readonly version?: string };
118
122
  }
@@ -317,17 +321,43 @@ export async function repairStandaloneBinary(
317
321
  };
318
322
  } catch (error) {
319
323
  const pendingActivation = error instanceof Error && error.message === "installation_pending_activation";
324
+ const accessDeniedError = error instanceof InstallationAccessDeniedError ? error : undefined;
325
+ const repointError = error instanceof ActivationRetryCandidateRepointError ? error : undefined;
320
326
  const reason = pendingActivation
321
327
  ? "sharing_violation"
322
- : error instanceof Error && /^[a-z][a-z0-9_]{0,63}$/.test(error.message)
323
- ? error.message
324
- : "installation_execution_unverified";
328
+ : accessDeniedError
329
+ ? accessDeniedError.code
330
+ : repointError
331
+ ? repointError.reasonCode
332
+ : error instanceof Error && /^[a-z][a-z0-9_]{0,63}$/.test(error.message)
333
+ ? error.message
334
+ : "installation_execution_unverified";
335
+ if (accessDeniedError)
336
+ logger.warn("Doctor standalone binary restore failed with access denied", {
337
+ targetPath,
338
+ code: accessDeniedError.code,
339
+ ...(accessDeniedError.windowsErrorCode ? { windowsErrorCode: accessDeniedError.windowsErrorCode } : {}),
340
+ ...(accessDeniedError.stagingCleanupWarning
341
+ ? { stagingCleanupWarning: accessDeniedError.stagingCleanupWarning }
342
+ : {}),
343
+ ...(accessDeniedError.retainedPaths ? { retainedPaths: accessDeniedError.retainedPaths } : {}),
344
+ });
345
+ if (repointError)
346
+ logger.warn("Doctor standalone binary restore retained a retry candidate after record repoint failed", {
347
+ path: repointError.candidatePath,
348
+ reason: repointError.reasonCode,
349
+ });
325
350
  return {
326
351
  state: pendingActivation ? "pending_activation" : started ? "failed" : "blocked",
327
352
  reason,
328
353
  sideEffectStarted: started,
329
354
  before,
330
355
  recordPath,
356
+ ...(accessDeniedError?.windowsErrorCode ? { windowsErrorCode: accessDeniedError.windowsErrorCode } : {}),
357
+ ...(accessDeniedError?.stagingCleanupWarning
358
+ ? { stagingCleanupWarning: accessDeniedError.stagingCleanupWarning }
359
+ : {}),
360
+ ...(accessDeniedError?.retainedPaths ? { retainedPaths: accessDeniedError.retainedPaths } : {}),
331
361
  };
332
362
  } finally {
333
363
  await release();
@@ -8,7 +8,7 @@ export function getExtraHelpText(): string {
8
8
  ${APP_NAME} session - List, inspect, create, remove, or attach sessions
9
9
  ${APP_NAME} state - Inspect or manage persisted GJC state
10
10
  ${APP_NAME} auth-broker - Manage the auth-broker (credential vault)
11
- ${APP_NAME} accounts - List, check, pin, and remove stored OAuth accounts
11
+ ${APP_NAME} accounts - List, check, pin, prefer, and remove stored OAuth accounts
12
12
  ${APP_NAME} models presets - Inspect, refresh, pin, rollback, or disable the signed model preset registry
13
13
  ${APP_NAME} auth-gateway - Run an auth-gateway forward proxy
14
14
  ${APP_NAME} harness - Run harness control-plane commands
@@ -81,8 +81,6 @@ Environment Variables:
81
81
  GJC_CODING_AGENT_DIR - Session storage directory (default: ~/${CONFIG_DIR_NAME}/agent)
82
82
  GJC_UI_LANGUAGE - Explicit first-use onboarding language (en, ko, zh, or ja); invalid values use English without prompting
83
83
  GJC_PACKAGE_DIR - Override package directory (for Nix/Guix store paths)
84
- GJC_SMOL_MODEL - Override smol/fast model (see --smol)
85
- GJC_SLOW_MODEL - Override slow/reasoning model (see --slow)
86
84
  GJC_PLAN_MODEL - Override planning model (see --plan)
87
85
  GJC_MODEL_PRESET_REGISTRY_URL - HTTPS latest.json override for the signed preset registry
88
86
  GJC_MODEL_PRESET_REGISTRY_DISABLED - Disable registry fetch/use (1/true/yes/on)
@@ -504,8 +504,12 @@ export interface ReconcileResult {
504
504
  readonly record?: ActivationRecordV1;
505
505
  readonly recordIdentity?: FileIdentity;
506
506
  readonly reason?: string;
507
- /** Present only for a pre-mutation Windows sharing violation on the destination open. */
507
+ /** Present only for a pre-mutation Windows exact-replacement failure. */
508
508
  readonly windowsErrorCode?: string;
509
+ readonly detachedPath?: string;
510
+ readonly retainedSuccessorPath?: string;
511
+ readonly retainedPlaceholderPath?: string;
512
+ readonly retainedUnknownPath?: string;
509
513
  }
510
514
 
511
515
  /**
@@ -519,9 +523,11 @@ export interface ReconcileResult {
519
523
  * records are re-verified and advanced to `verified` once the target
520
524
  * digest/identity matches the candidate. `verified` records are read-only
521
525
  * re-confirmations. Anything else (target/parent drift, missing staged
522
- * candidate, an already-occupied backup name, a pre-mutation Windows
523
- * sharing violation) is reported as `conflict` with the exact reason and
524
- * never silently promoted.
526
+ * candidate, an already-occupied backup name) is reported as `conflict` with
527
+ * the exact reason and never silently promoted. A pre-mutation Windows
528
+ * sharing violation becomes `pending_activation`; an access-denied result is
529
+ * also recorded as pending for safe reuse but remains a `conflict` so the
530
+ * caller reports the publication failure.
525
531
  */
526
532
  export async function reconcileActivationRecord(
527
533
  targetPath: string,
@@ -637,11 +643,48 @@ export async function reconcileActivationRecord(
637
643
  };
638
644
  }
639
645
  }
646
+ if (
647
+ record.targetIdentity &&
648
+ record.stagingIdentity &&
649
+ result.code === "access_denied" &&
650
+ (process.platform === "win32" || result.windowsErrorCode === "0xC0000022") &&
651
+ !result.detachedPath &&
652
+ !result.retainedSuccessorPath &&
653
+ !result.retainedUnknownPath &&
654
+ !result.retainedPlaceholderPath
655
+ ) {
656
+ const unchangedTarget = await snapshotRegularFile(targetPath);
657
+ const unchangedStaging = await snapshotRegularFile(record.stagingPath);
658
+ if (
659
+ unchangedTarget &&
660
+ unchangedStaging &&
661
+ sameFileIdentity(record.targetIdentity, unchangedTarget.identity) &&
662
+ sameFileIdentity(record.stagingIdentity, unchangedStaging.identity)
663
+ ) {
664
+ const pending: ActivationRecordV1 = { ...record, phase: "pending_activation" };
665
+ const pendingIdentity = await updateActivationRecordFile(pending, recordIdentity);
666
+ return {
667
+ status: "conflict",
668
+ record: pending,
669
+ recordIdentity: pendingIdentity,
670
+ reason: "access_denied",
671
+ ...(result.windowsErrorCode ? { windowsErrorCode: result.windowsErrorCode } : {}),
672
+ };
673
+ }
674
+ }
640
675
  return {
641
676
  status: "conflict",
642
677
  record,
643
678
  reason: result.code ?? "activation_promotion_failed",
644
679
  ...(result.windowsErrorCode ? { windowsErrorCode: result.windowsErrorCode } : {}),
680
+ ...(result.detachedPath !== undefined ? { detachedPath: result.detachedPath } : {}),
681
+ ...(result.retainedSuccessorPath !== undefined
682
+ ? { retainedSuccessorPath: result.retainedSuccessorPath }
683
+ : {}),
684
+ ...(result.retainedPlaceholderPath !== undefined
685
+ ? { retainedPlaceholderPath: result.retainedPlaceholderPath }
686
+ : {}),
687
+ ...(result.retainedUnknownPath !== undefined ? { retainedUnknownPath: result.retainedUnknownPath } : {}),
645
688
  };
646
689
  }
647
690
  const promoted = await snapshotRegularFile(targetPath);
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `gjc migrate` — import MCP servers and skills from other coding agents.
2
+ * `gjc migrate` — import MCP servers, skills, slash commands, and instruction files from other coding agents.
3
3
  */
4
4
  import * as os from "node:os";
5
5
  import * as path from "node:path";
@@ -53,8 +53,20 @@ export function resolveSources(from: string[]): MigrateSource[] {
53
53
 
54
54
  function resolveDestinations(project: boolean, cwd: string): MigrateDestinations {
55
55
  const scope = project ? "project" : "user";
56
- const skillsDir = project ? path.join(getProjectAgentDir(cwd), "skills") : path.join(getAgentDir(), "skills");
57
- return { mcpConfigPath: getMCPConfigPath(scope, cwd), skillsDir };
56
+ const agentDir = project ? getProjectAgentDir(cwd) : getAgentDir();
57
+ const skillsDir = path.join(agentDir, "skills");
58
+ const commandsDir = path.join(agentDir, "commands");
59
+ const agentsDir = path.join(agentDir, "agents");
60
+ const hooksDir = path.join(agentDir, "hooks");
61
+ const instructionsPath = path.join(agentDir, "AGENTS.md");
62
+ return {
63
+ mcpConfigPath: getMCPConfigPath(scope, cwd),
64
+ skillsDir,
65
+ commandsDir,
66
+ agentsDir,
67
+ hooksDir,
68
+ instructionsPath,
69
+ };
58
70
  }
59
71
 
60
72
  /** Run the migration and return the report (does not set process.exitCode). */
@@ -66,15 +78,16 @@ export async function runMigrate(args: MigrateCommandArgs): Promise<MigrateRepor
66
78
 
67
79
  const results: AdapterResult[] = [];
68
80
  for (const source of sources) {
69
- results.push(await getAdapter(source).collect({ homeDir }));
81
+ results.push(await getAdapter(source).collect({ homeDir, cwd, scope: args.project ? "project" : "user" }));
70
82
  }
71
83
 
72
- const { actions, warnings } = await planMigration({ results, destinations, force: args.force });
73
- const finalActions = args.dryRun ? actions : await executeActions(actions);
84
+ const { actions, warnings, manualActions } = await planMigration({ results, destinations, force: args.force });
85
+ const finalActions = args.dryRun ? actions : await executeActions(actions, { project: args.project });
74
86
 
75
87
  return buildReport({
76
88
  actions: finalActions,
77
89
  warnings,
90
+ manualActions,
78
91
  sources,
79
92
  destinations,
80
93
  dryRun: args.dryRun,
@@ -111,6 +111,12 @@ export const PUBLIC_COMMAND_DIAGNOSTICS = {
111
111
  // of them and never implies that another key would be safe.
112
112
  lifecycle_idempotency_conflict:
113
113
  "The broker reported an idempotency conflict. Reconcile existing lifecycle state before deciding whether another request is safe.",
114
+ lifecycle_legacy_history_ambiguous:
115
+ "The broker refused admission because legacy lifecycle history cannot prove this target is unrelated. This request was not dispatched; this refusal does not settle earlier effects. Preserve the ledger and original operation, request key, and target. For a prior session.create, use read-only session.lookup with its original key and create target; not_found is not proof of no effect. An empty transcript, stopped host, or fresh key does not resolve this fence. Do not edit the ledger, force deletion, or retry with another key; missing identity or terminal effect evidence requires operator investigation.",
116
+ // Refusals of the request payload itself: the broker's own text names the missing field
117
+ // (a required `sessionPath`, for one), and it is never rendered, so the class is named here.
118
+ lifecycle_input_refused:
119
+ "The broker refused the request as invalid input. Correct the request payload and reconcile existing lifecycle state before deciding whether another request is safe.",
114
120
  usage_transport_exclusive: "Specify exactly one of --stdio or --socket <path>.",
115
121
  usage_duplicate_option: "Each option on this command may occur at most once.",
116
122
  usage_unknown_argument: "An unrecognized argument was supplied; re-read the command help for its accepted grammar.",
@@ -10,8 +10,6 @@ export type RootThinkingLevel = (typeof ROOT_THINKING_LEVELS)[number];
10
10
  /** Public launch flags shared by root help, completion, and the launch command. */
11
11
  export const ROOT_LAUNCH_FLAGS = {
12
12
  model: Flags.string({ description: 'Model to use (fuzzy match: "opus", "gpt-5.2", or "openai/gpt-5.2")' }),
13
- smol: Flags.string({ description: "Smol/fast model for lightweight tasks (or GJC_SMOL_MODEL env)" }),
14
- slow: Flags.string({ description: "Slow/reasoning model for thorough analysis (or GJC_SLOW_MODEL env)" }),
15
13
  plan: Flags.string({ description: "Plan model for architectural planning (or GJC_PLAN_MODEL env)" }),
16
14
  mpreset: Flags.string({ description: "Model profile preset to activate for this session" }),
17
15
  default: Flags.boolean({ description: "Persist --mpreset as the default model profile" }),
@@ -19,11 +17,11 @@ export const ROOT_LAUNCH_FLAGS = {
19
17
  "api-key": Flags.string({ description: "API key (defaults to env vars)" }),
20
18
  credential: Flags.string({
21
19
  description:
22
- "Stored credential selector: email:<addr>, id:<n>, account:<id>, project:<id>, or provider/email:<addr>",
20
+ "Stored credential selector: email:<addr>, id:<n>, account:<id>, project:<id>, org:<id|name>, or provider/email:<addr>",
23
21
  }),
24
22
  "prefer-credential": Flags.string({
25
23
  description:
26
- "Preferred stored credential with quota fallback: email:<addr>, id:<n>, account:<id>, project:<id>, or provider/id:<n>",
24
+ "Preferred stored credential with quota fallback: email:<addr>, id:<n>, account:<id>, project:<id>, org:<id|name>, or provider/id:<n>",
27
25
  }),
28
26
  "system-prompt": Flags.string({ description: "System prompt (default: coding assistant prompt)" }),
29
27
  "append-system-prompt": Flags.string({ description: "Append text or file contents to the system prompt" }),
@@ -4,7 +4,7 @@
4
4
  * Handles `gjc stats` subcommand for viewing AI usage statistics.
5
5
  */
6
6
 
7
- import { APP_NAME, formatDuration, formatNumber, formatPercent } from "@gajae-code/utils";
7
+ import { APP_NAME, formatDuration, formatNumber, formatPercent, sanitizeDisplayLine } from "@gajae-code/utils";
8
8
  import chalk from "chalk";
9
9
  import { openPath } from "../utils/open";
10
10
 
@@ -168,7 +168,7 @@ async function printStatsSummary(): Promise<void> {
168
168
  console.log(chalk.bold("\nBy Model:"));
169
169
  for (const m of byModel.slice(0, 10)) {
170
170
  console.log(
171
- ` ${m.model}: ${formatNumber(m.totalRequests)} reqs, ${formatCost(m.totalCost)}, ${formatPercent(m.cacheRate)} cache`,
171
+ ` ${sanitizeDisplayLine(m.model)}: ${formatNumber(m.totalRequests)} reqs, ${formatCost(m.totalCost)}, ${formatPercent(m.cacheRate)} cache`,
172
172
  );
173
173
  }
174
174
  }
@@ -177,7 +177,7 @@ async function printStatsSummary(): Promise<void> {
177
177
  console.log(chalk.bold("\nBy Agent Role:"));
178
178
  for (const agent of byAgent) {
179
179
  console.log(
180
- ` ${agent.agent}: ${formatNumber(agent.totalRequests)} reqs, ${formatNumber(agent.totalInputTokens)} input / ${formatNumber(agent.totalOutputTokens)} output, ${formatPercent(agent.cacheRate)} cache, ${formatCost(agent.totalCost)}`,
180
+ ` ${sanitizeDisplayLine(agent.agent)}: ${formatNumber(agent.totalRequests)} reqs, ${formatNumber(agent.totalInputTokens)} input / ${formatNumber(agent.totalOutputTokens)} output, ${formatPercent(agent.cacheRate)} cache, ${formatCost(agent.totalCost)}`,
181
181
  );
182
182
  }
183
183
  }
@@ -185,7 +185,9 @@ async function printStatsSummary(): Promise<void> {
185
185
  if (byFolder.length > 0) {
186
186
  console.log(chalk.bold("\nBy Folder:"));
187
187
  for (const f of byFolder.slice(0, 10)) {
188
- console.log(` ${f.folder}: ${formatNumber(f.totalRequests)} reqs, ${formatCost(f.totalCost)}`);
188
+ console.log(
189
+ ` ${sanitizeDisplayLine(f.folder)}: ${formatNumber(f.totalRequests)} reqs, ${formatCost(f.totalCost)}`,
190
+ );
189
191
  }
190
192
  }
191
193
 
@@ -201,7 +203,9 @@ async function printStatsSummary(): Promise<void> {
201
203
  console.log(` Provider-side (prefix intact): ${formatNumber(misses.providerSideMisses)}`);
202
204
  console.log(` Model switch: ${formatNumber(misses.modelSwitchMisses)}`);
203
205
  for (const cause of misses.byCause) {
204
- const label = cause.divergedRole ? `${cause.change} (${cause.divergedRole})` : cause.change;
206
+ const label = sanitizeDisplayLine(
207
+ cause.divergedRole ? `${cause.change} (${cause.divergedRole})` : cause.change,
208
+ );
205
209
  console.log(` ${label}: ${formatNumber(cause.misses)}`);
206
210
  }
207
211
  }