@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
@@ -9,6 +9,7 @@
9
9
  import * as fsSync from "node:fs";
10
10
  import * as fs from "node:fs/promises";
11
11
  import * as path from "node:path";
12
+ import { getTrustedHomeDir } from "@gajae-code/utils";
12
13
  import { upsertMCPServer } from "../runtime-mcp/config-writer";
13
14
  import type { MigrateAction } from "./types";
14
15
 
@@ -19,17 +20,23 @@ function trustedSkillDestinationBase(destination: string): string {
19
20
  return path.basename(scopeRoot) === ".gjc" ? path.dirname(scopeRoot) : scopeRoot;
20
21
  }
21
22
 
22
- async function ensureRealDirectoryPathNoFollow(directory: string, trustedBase: string): Promise<void> {
23
+ async function ensureRealDirectoryPathNoFollow(
24
+ directory: string,
25
+ trustedBase: string,
26
+ label = "skill destination",
27
+ createMissing = true,
28
+ mode?: number,
29
+ ): Promise<void> {
23
30
  const resolvedBase = path.resolve(trustedBase);
24
31
  const resolvedDirectory = path.resolve(directory);
25
32
  const relative = path.relative(resolvedBase, resolvedDirectory);
26
33
  if (relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative)) {
27
- throw new Error(`skill destination escapes trusted base: ${resolvedDirectory}`);
34
+ throw new Error(`${label} escapes trusted base: ${resolvedDirectory}`);
28
35
  }
29
36
 
30
37
  const baseStat = await fs.stat(resolvedBase);
31
38
  if (!baseStat.isDirectory()) {
32
- throw new Error(`skill destination base is not a directory: ${resolvedBase}`);
39
+ throw new Error(`${label} base is not a directory: ${resolvedBase}`);
33
40
  }
34
41
 
35
42
  let current = resolvedBase;
@@ -38,14 +45,17 @@ async function ensureRealDirectoryPathNoFollow(directory: string, trustedBase: s
38
45
  try {
39
46
  const stat = await fs.lstat(current);
40
47
  if (!stat.isDirectory() || stat.isSymbolicLink()) {
41
- throw new Error(`skill destination ancestor is not a real directory: ${current}`);
48
+ throw new Error(`${label} ancestor is not a real directory: ${current}`);
42
49
  }
43
50
  } catch (error) {
44
51
  if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
45
- await fs.mkdir(current);
52
+ // A missing project `.gjc` is created by the MCP writer (mode 0o700).
53
+ // Do not mkdir here, or that mode is lost. An existing symlink still fails above.
54
+ if (!createMissing) return;
55
+ await fs.mkdir(current, mode === undefined ? undefined : { mode });
46
56
  const stat = await fs.lstat(current);
47
57
  if (!stat.isDirectory() || stat.isSymbolicLink()) {
48
- throw new Error(`skill destination ancestor is not a real directory: ${current}`);
58
+ throw new Error(`${label} ancestor is not a real directory: ${current}`);
49
59
  }
50
60
  }
51
61
  }
@@ -66,7 +76,161 @@ async function writeSkillFileNoFollow(destination: string, content: string): Pro
66
76
  }
67
77
  }
68
78
 
69
- export async function executeActions(actions: MigrateAction[]): Promise<MigrateAction[]> {
79
+ async function ensureInstructionDirectory(
80
+ directory: string,
81
+ project: boolean,
82
+ label = "instruction destination",
83
+ ): Promise<void> {
84
+ let trustedBase = path.dirname(directory);
85
+ if (!project) {
86
+ const home = path.resolve(getTrustedHomeDir());
87
+ const resolvedDirectory = path.resolve(directory);
88
+ const relative = path.relative(home, resolvedDirectory);
89
+ const isWithinHome =
90
+ relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
91
+ if (isWithinHome) {
92
+ trustedBase = home;
93
+ } else {
94
+ let current = path.dirname(resolvedDirectory);
95
+ while (true) {
96
+ try {
97
+ const stat = await fs.lstat(current);
98
+ if (!stat.isDirectory() || stat.isSymbolicLink()) {
99
+ throw new Error(`user ${label} ancestor is not a real directory: ${current}`);
100
+ }
101
+ trustedBase = current;
102
+ break;
103
+ } catch (error) {
104
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
105
+ const parent = path.dirname(current);
106
+ if (parent === current) throw error;
107
+ current = parent;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ await ensureRealDirectoryPathNoFollow(directory, trustedBase, label, true, 0o700);
113
+ }
114
+
115
+ async function writeInstructionFileNoFollow(destination: string, content: string, project: boolean): Promise<void> {
116
+ await ensureInstructionDirectory(path.dirname(destination), project);
117
+ const handle = await fs.open(
118
+ destination,
119
+ fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_TRUNC | fsSync.constants.O_NOFOLLOW,
120
+ 0o666,
121
+ );
122
+ try {
123
+ await handle.writeFile(content, "utf-8");
124
+ } finally {
125
+ await handle.close();
126
+ }
127
+ }
128
+
129
+ async function writeAgentFileNoFollow(
130
+ destination: string,
131
+ content: string,
132
+ project: boolean,
133
+ createOnly: boolean,
134
+ ): Promise<void> {
135
+ const destinationDirectory = path.dirname(destination);
136
+ if (project) {
137
+ const agentsRoot = path.dirname(destinationDirectory);
138
+ const agentRoot = path.dirname(agentsRoot);
139
+ await ensureRealDirectoryPathNoFollow(agentRoot, path.dirname(agentRoot), "agent destination", true, 0o700);
140
+ await ensureRealDirectoryPathNoFollow(agentsRoot, agentRoot, "agent destination", true, 0o700);
141
+ await ensureRealDirectoryPathNoFollow(destinationDirectory, agentsRoot, "agent destination", true, 0o700);
142
+ } else {
143
+ await ensureInstructionDirectory(destinationDirectory, false, "agent destination");
144
+ }
145
+ const handle = await fs.open(
146
+ destination,
147
+ createOnly
148
+ ? fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_EXCL | fsSync.constants.O_NOFOLLOW
149
+ : fsSync.constants.O_WRONLY |
150
+ fsSync.constants.O_CREAT |
151
+ fsSync.constants.O_TRUNC |
152
+ fsSync.constants.O_NOFOLLOW,
153
+ 0o666,
154
+ );
155
+ try {
156
+ await handle.writeFile(content, "utf-8");
157
+ } finally {
158
+ await handle.close();
159
+ }
160
+ }
161
+
162
+ /** Generated hook modules live beside the agent's own hooks, so they use the same no-follow rules. */
163
+ async function writeHookModuleNoFollow(destination: string, content: string, createOnly: boolean): Promise<void> {
164
+ await ensureInstructionDirectory(path.dirname(destination), false, "hook destination");
165
+ const handle = await fs.open(
166
+ destination,
167
+ createOnly
168
+ ? fsSync.constants.O_WRONLY | fsSync.constants.O_CREAT | fsSync.constants.O_EXCL | fsSync.constants.O_NOFOLLOW
169
+ : fsSync.constants.O_WRONLY |
170
+ fsSync.constants.O_CREAT |
171
+ fsSync.constants.O_TRUNC |
172
+ fsSync.constants.O_NOFOLLOW,
173
+ 0o666,
174
+ );
175
+ try {
176
+ await handle.writeFile(content, "utf-8");
177
+ } finally {
178
+ await handle.close();
179
+ }
180
+ }
181
+
182
+ async function writeCommandFileNoFollow(
183
+ destination: string,
184
+ content: string,
185
+ name: string,
186
+ project: boolean,
187
+ createOnly: boolean,
188
+ ): Promise<void> {
189
+ const destinationDirectory = path.dirname(destination);
190
+ if (project) {
191
+ const nameParts = name.split(":");
192
+ let commandsRoot = destinationDirectory;
193
+ for (let index = 1; index < nameParts.length; index++) commandsRoot = path.dirname(commandsRoot);
194
+ const agentRoot = path.dirname(commandsRoot);
195
+ await ensureRealDirectoryPathNoFollow(
196
+ agentRoot,
197
+ path.dirname(agentRoot),
198
+ "slash command destination",
199
+ true,
200
+ 0o700,
201
+ );
202
+ await ensureRealDirectoryPathNoFollow(commandsRoot, agentRoot, "slash command destination", true, 0o700);
203
+ await ensureRealDirectoryPathNoFollow(
204
+ destinationDirectory,
205
+ commandsRoot,
206
+ "slash command destination",
207
+ true,
208
+ 0o700,
209
+ );
210
+ } else {
211
+ await ensureInstructionDirectory(destinationDirectory, false, "slash command destination");
212
+ }
213
+
214
+ const handle = await fs.open(
215
+ destination,
216
+ fsSync.constants.O_WRONLY |
217
+ fsSync.constants.O_CREAT |
218
+ fsSync.constants.O_TRUNC |
219
+ fsSync.constants.O_NOFOLLOW |
220
+ (createOnly ? fsSync.constants.O_EXCL : 0),
221
+ 0o666,
222
+ );
223
+ try {
224
+ await handle.writeFile(content, "utf-8");
225
+ } finally {
226
+ await handle.close();
227
+ }
228
+ }
229
+
230
+ export async function executeActions(
231
+ actions: MigrateAction[],
232
+ options?: { project?: boolean },
233
+ ): Promise<MigrateAction[]> {
70
234
  const out: MigrateAction[] = [];
71
235
  for (const action of actions) {
72
236
  if (action.operation !== "create" && action.operation !== "update") {
@@ -75,6 +239,17 @@ export async function executeActions(actions: MigrateAction[]): Promise<MigrateA
75
239
  }
76
240
  try {
77
241
  if (action.type === "mcp" && action.mcp && action.name && action.destination) {
242
+ // `project` is the migrate scope, not a guess from the directory name.
243
+ // A user agent dir may itself be named `.gjc`.
244
+ if (options?.project) {
245
+ const directory = path.dirname(action.destination);
246
+ await ensureRealDirectoryPathNoFollow(
247
+ directory,
248
+ path.dirname(path.resolve(directory)),
249
+ "mcp destination",
250
+ false,
251
+ );
252
+ }
78
253
  await upsertMCPServer(action.destination, action.name, action.mcp.config, {
79
254
  force: action.operation === "update",
80
255
  });
@@ -82,10 +257,50 @@ export async function executeActions(actions: MigrateAction[]): Promise<MigrateA
82
257
  } else if (action.type === "skill" && action.skill && action.destination) {
83
258
  await writeSkillFileNoFollow(action.destination, action.skill.content);
84
259
  out.push(action);
260
+ } else if (action.type === "instruction" && action.instruction && action.destination) {
261
+ await writeInstructionFileNoFollow(
262
+ action.destination,
263
+ action.instruction.content,
264
+ options?.project ?? false,
265
+ );
266
+ out.push(action);
267
+ } else if (action.type === "hook" && action.hook && action.destination) {
268
+ await writeHookModuleNoFollow(action.destination, action.hook.content, action.operation === "create");
269
+ out.push(action);
270
+ } else if (action.type === "agent" && action.agent && action.destination) {
271
+ await writeAgentFileNoFollow(
272
+ action.destination,
273
+ action.agent.content,
274
+ options?.project ?? false,
275
+ action.operation === "create",
276
+ );
277
+ out.push(action);
278
+ } else if (action.type === "command" && action.command && action.destination && action.name) {
279
+ await writeCommandFileNoFollow(
280
+ action.destination,
281
+ action.command.content,
282
+ action.name,
283
+ options?.project ?? false,
284
+ action.operation === "create",
285
+ );
286
+ out.push(action);
85
287
  } else {
86
288
  out.push(action);
87
289
  }
88
290
  } catch (error) {
291
+ if (
292
+ (action.type === "command" || action.type === "agent") &&
293
+ action.operation === "create" &&
294
+ (error as NodeJS.ErrnoException).code === "EEXIST"
295
+ ) {
296
+ out.push({
297
+ ...action,
298
+ operation: "skip",
299
+ status: "skipped_exists",
300
+ reason: "destination appeared after planning; refusing to overwrite it",
301
+ });
302
+ continue;
303
+ }
89
304
  out.push({
90
305
  ...action,
91
306
  operation: "fail",
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Render a gjc hook module from imported foreign hook commands.
3
+ *
4
+ * Claude Code hooks are shell commands: the runtime writes a JSON payload to
5
+ * stdin and reads the exit code. `PreToolUse` blocks on exit 2 with stderr as the
6
+ * reason; every other event is observational. gjc hooks are TypeScript modules
7
+ * that subscribe to events in-process, so the importer reproduces the foreign
8
+ * contract rather than rewriting the commands.
9
+ *
10
+ * Only events whose semantics are unambiguous are translated. The payload keeps
11
+ * the foreign field names so an existing script that reads its JSON keeps working;
12
+ * fields this host cannot supply are omitted instead of guessed, which the module
13
+ * header states.
14
+ */
15
+ import type { HookCandidate, MigrateSource } from "./types";
16
+
17
+ /** Foreign event -> gjc hook event. Blocking events are marked separately. */
18
+ const EVENT_MAP: Record<string, { event: string; blocking: boolean }> = {
19
+ PreToolUse: { event: "tool_call", blocking: true },
20
+ PostToolUse: { event: "tool_result", blocking: false },
21
+ SessionStart: { event: "session_start", blocking: false },
22
+ Stop: { event: "turn_end", blocking: false },
23
+ };
24
+
25
+ export function isSupportedHookEvent(event: string): boolean {
26
+ return event in EVENT_MAP;
27
+ }
28
+
29
+ /** Foreign events this importer translates, for user-facing messages. */
30
+ export const SUPPORTED_HOOK_EVENTS: readonly string[] = Object.keys(EVENT_MAP);
31
+
32
+ interface RenderedHook {
33
+ event: string;
34
+ blocking: boolean;
35
+ matcher?: string;
36
+ command: string;
37
+ sourceEvent: string;
38
+ }
39
+
40
+ function constantName(event: string): string {
41
+ return event.replace(/[^a-z_]/g, "_").toUpperCase();
42
+ }
43
+
44
+ function renderHookLiteral(hook: RenderedHook): string {
45
+ const parts = [`event: ${JSON.stringify(hook.sourceEvent)}`, `command: ${JSON.stringify(hook.command)}`];
46
+ if (hook.matcher) parts.push(`matcher: ${JSON.stringify(hook.matcher)}`);
47
+ return `\t{ ${parts.join(", ")} },`;
48
+ }
49
+
50
+ /**
51
+ * Build the module source. The result is deterministic for a given candidate
52
+ * list, so a dry-run report and a live write describe the same file.
53
+ */
54
+ export function renderHookModule(source: MigrateSource, candidates: readonly HookCandidate[]): string {
55
+ const hooks: RenderedHook[] = [];
56
+ for (const candidate of candidates) {
57
+ const mapped = EVENT_MAP[candidate.event];
58
+ if (!mapped) continue;
59
+ hooks.push({
60
+ event: mapped.event,
61
+ blocking: mapped.blocking,
62
+ matcher: candidate.matcher,
63
+ command: candidate.command,
64
+ sourceEvent: candidate.event,
65
+ });
66
+ }
67
+ const byEvent = new Map<string, RenderedHook[]>();
68
+ for (const hook of hooks) {
69
+ const list = byEvent.get(hook.event) ?? [];
70
+ list.push(hook);
71
+ byEvent.set(hook.event, list);
72
+ }
73
+ const eventNames = [...byEvent.keys()].sort();
74
+ const blocks = eventNames
75
+ .map(event => {
76
+ const entries = (byEvent.get(event) ?? []).map(renderHookLiteral).join("\n");
77
+ return `const ${constantName(event)}_HOOKS: readonly ImportedHook[] = [\n${entries}\n];`;
78
+ })
79
+ .join("\n\n");
80
+ const registrations = eventNames
81
+ .map(event => {
82
+ const blocking = byEvent.get(event)?.some(hook => hook.blocking) ?? false;
83
+ const register = blocking ? "registerBlocking" : "registerObservational";
84
+ return `\t${register}(api, ${JSON.stringify(event)}, ${constantName(event)}_HOOKS);`;
85
+ })
86
+ .join("\n");
87
+
88
+ return `/**
89
+ * Generated by \`gjc migrate --from ${source}\`. Re-run with --force to regenerate.
90
+ *
91
+ * These hooks were shell commands in ${source}. Each command receives a JSON
92
+ * payload on stdin under the origin's field names; fields this runtime cannot
93
+ * supply (session id, transcript path) are omitted rather than invented.
94
+ * \`PreToolUse\` blocks the tool when the command exits 2 and uses its stderr as
95
+ * the reason, which is the origin contract; the other events only run the
96
+ * command.
97
+ */
98
+ import { spawn } from "node:child_process";
99
+
100
+ interface ImportedHook {
101
+ event: string;
102
+ command: string;
103
+ matcher?: string;
104
+ }
105
+
106
+ interface HookCommandResult {
107
+ code: number;
108
+ stdout: string;
109
+ stderr: string;
110
+ }
111
+
112
+ interface HookApi {
113
+ on(event: string, handler: (payload: unknown, context: { cwd?: string }) => unknown): void;
114
+ }
115
+
116
+ ${blocks}
117
+
118
+ function matches(matcher: string | undefined, toolName: string | undefined): boolean {
119
+ if (!matcher || !matcher.trim()) return true;
120
+ if (!toolName) return false;
121
+ try {
122
+ return new RegExp(\`^(?:\${matcher})$\`).test(toolName);
123
+ } catch {
124
+ return matcher === toolName;
125
+ }
126
+ }
127
+
128
+ function shellCommand(command: string): string[] {
129
+ return process.platform === "win32"
130
+ ? [process.env.ComSpec ?? "cmd.exe", "/d", "/s", "/c", command]
131
+ : ["/bin/bash", "-lc", command];
132
+ }
133
+
134
+ async function runHook(hook: ImportedHook, payload: unknown): Promise<HookCommandResult> {
135
+ const [file, ...args] = shellCommand(hook.command);
136
+ const child = spawn(file, args, { stdio: ["pipe", "pipe", "pipe"] });
137
+ child.stdin?.end(JSON.stringify(payload));
138
+ let stdout = "";
139
+ let stderr = "";
140
+ child.stdout?.on("data", chunk => {
141
+ stdout += String(chunk);
142
+ });
143
+ child.stderr?.on("data", chunk => {
144
+ stderr += String(chunk);
145
+ });
146
+ const code = await new Promise<number>(resolve => {
147
+ child.on("error", () => resolve(1));
148
+ child.on("close", value => resolve(value ?? 1));
149
+ });
150
+ return { code, stdout, stderr };
151
+ }
152
+
153
+ function registerBlocking(api: HookApi, event: string, hooks: readonly ImportedHook[]): void {
154
+ api.on(event, async (payload, context) => {
155
+ const record = payload as { toolName?: string; input?: unknown };
156
+ for (const hook of hooks) {
157
+ if (!matches(hook.matcher, record?.toolName)) continue;
158
+ const result = await runHook(hook, {
159
+ hook_event_name: hook.event,
160
+ tool_name: record?.toolName,
161
+ tool_input: record?.input,
162
+ cwd: context?.cwd,
163
+ });
164
+ if (result.code === 2) {
165
+ return { block: true, reason: result.stderr.trim() || \`blocked by imported \${hook.event} hook\` };
166
+ }
167
+ }
168
+ return undefined;
169
+ });
170
+ }
171
+
172
+ function registerObservational(api: HookApi, event: string, hooks: readonly ImportedHook[]): void {
173
+ api.on(event, async (payload, context) => {
174
+ const record = payload as { toolName?: string; input?: unknown; turnIndex?: number };
175
+ for (const hook of hooks) {
176
+ if (event === "tool_result" && !matches(hook.matcher, record?.toolName)) continue;
177
+ await runHook(hook, {
178
+ hook_event_name: hook.event,
179
+ tool_name: record?.toolName,
180
+ tool_input: record?.input,
181
+ turn_index: record?.turnIndex,
182
+ cwd: context?.cwd,
183
+ });
184
+ }
185
+ return undefined;
186
+ });
187
+ }
188
+
189
+ export default (api: HookApi): void => {
190
+ ${registrations}
191
+ };
192
+ `;
193
+ }
@@ -7,6 +7,7 @@
7
7
  import {
8
8
  emptyStatusCounts,
9
9
  isFailureStatus,
10
+ type ManualAction,
10
11
  type MigrateAction,
11
12
  type MigrateDestinations,
12
13
  type MigrateReport,
@@ -20,6 +21,7 @@ export interface BuildReportInput {
20
21
  warnings: MigrateWarning[];
21
22
  sources: MigrateSource[];
22
23
  destinations: MigrateDestinations;
24
+ manualActions: ManualAction[];
23
25
  dryRun: boolean;
24
26
  project: boolean;
25
27
  force: boolean;
@@ -27,7 +29,15 @@ export interface BuildReportInput {
27
29
 
28
30
  export function buildReport(input: BuildReportInput): MigrateReport {
29
31
  const total = emptyStatusCounts();
30
- const byType = { mcp: emptyStatusCounts(), skill: emptyStatusCounts(), source: emptyStatusCounts() };
32
+ const byType = {
33
+ mcp: emptyStatusCounts(),
34
+ skill: emptyStatusCounts(),
35
+ command: emptyStatusCounts(),
36
+ agent: emptyStatusCounts(),
37
+ hook: emptyStatusCounts(),
38
+ instruction: emptyStatusCounts(),
39
+ source: emptyStatusCounts(),
40
+ };
31
41
  const bySource = {} as Record<MigrateSource, StatusCounts>;
32
42
  for (const source of input.sources) bySource[source] = emptyStatusCounts();
33
43
 
@@ -47,6 +57,7 @@ export function buildReport(input: BuildReportInput): MigrateReport {
47
57
  sources: input.sources,
48
58
  destinations: input.destinations,
49
59
  summary: { total, byType, bySource },
60
+ manualActions: input.manualActions,
50
61
  actions: input.actions.map(action => ({
51
62
  source: action.source,
52
63
  type: action.type,
@@ -75,10 +86,52 @@ export function renderHuman(report: MigrateReport): string {
75
86
  const mode = report.dryRun ? " (dry-run)" : "";
76
87
  lines.push(`gjc migrate${mode}: ${report.ok ? "ok" : "completed with failures"}`);
77
88
  lines.push(`Sources: ${report.sources.join(", ") || "none"}`);
78
- lines.push(`Destination: mcp=${report.destinations.mcpConfigPath} skills=${report.destinations.skillsDir}`);
89
+ lines.push(
90
+ `Destination: mcp=${report.destinations.mcpConfigPath} skills=${report.destinations.skillsDir} commands=${report.destinations.commandsDir} agents=${report.destinations.agentsDir} hooks=${report.destinations.hooksDir} instructions=${report.destinations.instructionsPath}`,
91
+ );
79
92
  lines.push("");
80
93
  lines.push(`MCP: ${summarizeCounts(report.summary.byType.mcp)}`);
81
94
  lines.push(`Skills: ${summarizeCounts(report.summary.byType.skill)}`);
95
+ lines.push(`Commands: ${summarizeCounts(report.summary.byType.command)}`);
96
+ lines.push(`Agents: ${summarizeCounts(report.summary.byType.agent)}`);
97
+ lines.push(`Hooks: ${summarizeCounts(report.summary.byType.hook)}`);
98
+ lines.push(`Instructions: ${summarizeCounts(report.summary.byType.instruction)}`);
99
+ const commandActions = report.actions.filter(action => action.type === "command");
100
+ if (commandActions.length > 0) {
101
+ lines.push("Slash commands:");
102
+ for (const action of commandActions) {
103
+ lines.push(
104
+ ` - [${action.source}] /${action.name ?? ""}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
105
+ );
106
+ }
107
+ }
108
+ const agentActions = report.actions.filter(action => action.type === "agent");
109
+ if (agentActions.length > 0) {
110
+ lines.push("Subagents:");
111
+ for (const action of agentActions) {
112
+ lines.push(
113
+ ` - [${action.source}] ${action.name ?? ""}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
114
+ );
115
+ }
116
+ }
117
+ const hookActions = report.actions.filter(action => action.type === "hook");
118
+ if (hookActions.length > 0) {
119
+ lines.push("Hooks:");
120
+ for (const action of hookActions) {
121
+ lines.push(
122
+ ` - [${action.source}] ${action.name ?? ""}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
123
+ );
124
+ }
125
+ }
126
+ const instructionActions = report.actions.filter(action => action.type === "instruction");
127
+ if (instructionActions.length > 0) {
128
+ lines.push("Instruction files:");
129
+ for (const action of instructionActions) {
130
+ lines.push(
131
+ ` - [${action.source}] ${action.name ?? "AGENTS.md"}: ${action.status}${action.reason ? ` (${action.reason})` : ""}`,
132
+ );
133
+ }
134
+ }
82
135
  if (Object.values(report.summary.byType.source).some(n => n > 0)) {
83
136
  lines.push(`Source: ${summarizeCounts(report.summary.byType.source)}`);
84
137
  }
@@ -92,6 +145,14 @@ export function renderHuman(report: MigrateReport): string {
92
145
  }
93
146
  }
94
147
 
148
+ if (report.manualActions.length > 0) {
149
+ lines.push("");
150
+ lines.push("Manual actions:");
151
+ for (const m of report.manualActions) {
152
+ lines.push(` - [${m.source}] ${m.area}: ${m.detail}`);
153
+ }
154
+ }
155
+
95
156
  if (report.warnings.length > 0) {
96
157
  lines.push("");
97
158
  lines.push("Warnings:");