@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
@@ -540,6 +540,76 @@ function isUnwritableResidentCacheFailure(error: unknown): boolean {
540
540
  );
541
541
  }
542
542
 
543
+ /** Nearest real directory at or above `start`. A file or missing path is not a root. */
544
+ function nearestExistingDirectory(start: string): string | null {
545
+ let current = path.resolve(start);
546
+ for (let depth = 0; depth < 64; depth++) {
547
+ try {
548
+ if (fs.lstatSync(current).isDirectory()) return current;
549
+ } catch {
550
+ // Missing components are not worktree roots.
551
+ }
552
+ const parent = path.dirname(current);
553
+ if (parent === current) return null;
554
+ current = parent;
555
+ }
556
+ return null;
557
+ }
558
+
559
+ /**
560
+ * Canonical path of `start`, following a symlink ancestor.
561
+ * The unmatched suffix is appended so a not-yet-created cache root classifies
562
+ * the directory `openVerifiedResidentCacheInstanceDir` would create it in.
563
+ */
564
+ function canonicalCachePath(start: string): string | null {
565
+ let current = path.resolve(start);
566
+ const pending: string[] = [];
567
+ for (let depth = 0; depth < 64; depth++) {
568
+ try {
569
+ const stat = fs.lstatSync(current);
570
+ if (stat.isDirectory() || stat.isSymbolicLink()) {
571
+ const real = fs.realpathSync(current);
572
+ return pending.length === 0 ? real : path.join(real, ...pending.reverse());
573
+ }
574
+ } catch {
575
+ // Missing components are resolved from the nearest existing ancestor.
576
+ }
577
+ const parent = path.dirname(current);
578
+ if (parent === current) return null;
579
+ pending.push(path.basename(current));
580
+ current = parent;
581
+ }
582
+ return null;
583
+ }
584
+
585
+ function cacheDirectoryInsideGitWorktree(directory: string): boolean {
586
+ return git.repo.resolveSync(directory) !== null;
587
+ }
588
+
589
+ /**
590
+ * Resident text is a second plaintext copy of assistant and tool output.
591
+ * A cache root inside a Git worktree can be staged by a later `git add`, so
592
+ * that root stays in memory. Both the lexical directory and the canonical
593
+ * directory are classified: a symlink outside the worktree must not hide a
594
+ * target inside it, and a lexical worktree path stays refused when its
595
+ * canonical target is outside. A missing or non-directory root still reaches
596
+ * the resident-cache trust check when both views are outside a worktree.
597
+ * No existing directory within 64 ancestors, or a resolver error, stays in memory.
598
+ */
599
+ export function residentTextCacheRootAllowsDisk(cacheRoot: string): boolean {
600
+ try {
601
+ const lexical = nearestExistingDirectory(cacheRoot);
602
+ if (lexical === null || cacheDirectoryInsideGitWorktree(lexical)) return false;
603
+ const canonical = canonicalCachePath(cacheRoot);
604
+ if (canonical === null) return false;
605
+ const canonicalDirectory = nearestExistingDirectory(canonical);
606
+ if (canonicalDirectory === null || cacheDirectoryInsideGitWorktree(canonicalDirectory)) return false;
607
+ return true;
608
+ } catch {
609
+ return false;
610
+ }
611
+ }
612
+
543
613
  export interface SessionEntryBase {
544
614
  type: string;
545
615
  id: string;
@@ -3634,7 +3704,15 @@ function isLinkedWorktreePeer(a: string, b: string): boolean {
3634
3704
  * Read the terminal breadcrumb for the current terminal, scoped to a cwd.
3635
3705
  * Returns the session file path if it exists and matches the cwd, null otherwise.
3636
3706
  */
3637
- async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
3707
+ async function readTerminalBreadcrumb(
3708
+ cwd: string,
3709
+ options: {
3710
+ sessionsRoot?: string;
3711
+ allowExplicitOutsideRoot?: boolean;
3712
+ /** Managed continuation inventory, including project-local transcripts. */
3713
+ continuationInventory?: readonly SessionInfo[];
3714
+ } = {},
3715
+ ): Promise<string | null> {
3638
3716
  const terminalId = getTerminalId();
3639
3717
  if (!terminalId) return null;
3640
3718
 
@@ -3656,9 +3734,9 @@ async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
3656
3734
 
3657
3735
  if (isStagedSessionPath(sessionFile)) return null;
3658
3736
  const inspected = inspectResumeSessionFile(sessionFile, new FileSessionStorage());
3737
+ const sessionsRoot = options.sessionsRoot ?? getSessionsDir();
3659
3738
  if ("kind" in inspected) {
3660
3739
  if (inspected.reason !== "missing") return null;
3661
- const sessionsRoot = getSessionsDir();
3662
3740
  const resolved = resolveManagedScope({
3663
3741
  cwd: breadcrumbCwd,
3664
3742
  agentDir: path.resolve(sessionsRoot, ".."),
@@ -3675,7 +3753,6 @@ async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
3675
3753
  }
3676
3754
  const header = inspected.entries[0] as SessionHeader;
3677
3755
  if (resolveEquivalentPath(header.cwd) !== resolveEquivalentPath(breadcrumbCwd)) return null;
3678
- const sessionsRoot = getSessionsDir();
3679
3756
  const resolved = resolveManagedScope({
3680
3757
  cwd: header.cwd,
3681
3758
  agentDir: path.resolve(sessionsRoot, ".."),
@@ -3693,7 +3770,22 @@ async function readTerminalBreadcrumb(cwd: string): Promise<string | null> {
3693
3770
  candidate => !isStagedSessionPath(candidate.path) && candidate.sessionId === header.id,
3694
3771
  );
3695
3772
  if (byIdentity) return byIdentity.path;
3696
- return pathIsWithin(sessionsRoot, path.resolve(sessionFile)) ? null : path.resolve(sessionFile);
3773
+ // Not an owned managed candidate. A file inside the sessions root stays
3774
+ // rejected. A file outside that root is resumed only when this continuation
3775
+ // inventory already contains it. An explicit destination still receives an
3776
+ // unmatched outside path; the caller applies containment.
3777
+ const resolvedFile = path.resolve(sessionFile);
3778
+ const insideSessionsRoot = pathIsWithin(sessionsRoot, resolvedFile);
3779
+ if (
3780
+ !insideSessionsRoot &&
3781
+ options.continuationInventory?.some(
3782
+ session => session.id === header.id && path.resolve(session.path) === resolvedFile,
3783
+ )
3784
+ ) {
3785
+ return resolvedFile;
3786
+ }
3787
+ if (!options.allowExplicitOutsideRoot || insideSessionsRoot) return null;
3788
+ return resolvedFile;
3697
3789
  } catch (err) {
3698
3790
  if (!isEnoent(err)) logger.debug("Terminal breadcrumb read failed", { err });
3699
3791
  // Breadcrumb doesn't exist or is corrupt — fall through
@@ -7289,6 +7381,17 @@ function sessionMatchesResumeArg(session: SessionInfo, sessionArg: string): bool
7289
7381
  return fileSessionId.startsWith(normalizedArg);
7290
7382
  }
7291
7383
 
7384
+ /**
7385
+ * Equal session id first, the same `id ===` check managed resume already uses.
7386
+ * Prefix matching stays for every other argument, in list order.
7387
+ */
7388
+ export function pickResumableSession(sessions: readonly SessionInfo[], sessionArg: string): SessionInfo | undefined {
7389
+ return (
7390
+ sessions.find(session => session.id === sessionArg) ??
7391
+ sessions.find(session => sessionMatchesResumeArg(session, sessionArg))
7392
+ );
7393
+ }
7394
+
7292
7395
  export async function resolveResumableSession(
7293
7396
  sessionArg: string,
7294
7397
  cwd: string,
@@ -7299,7 +7402,7 @@ export async function resolveResumableSession(
7299
7402
  const localSessions = sessionDir
7300
7403
  ? await SessionManager.list(cwd, sessionDir, storage)
7301
7404
  : await SessionManager.listManagedForResumePickerReadOnly(cwd, managedAgentDir, storage);
7302
- const localMatch = localSessions.find(session => sessionMatchesResumeArg(session, sessionArg));
7405
+ const localMatch = pickResumableSession(localSessions, sessionArg);
7303
7406
  if (localMatch) {
7304
7407
  return { session: localMatch, scope: "local" };
7305
7408
  }
@@ -7309,7 +7412,7 @@ export async function resolveResumableSession(
7309
7412
  }
7310
7413
 
7311
7414
  const globalSessions = await SessionManager.listAll(storage, managedAgentDir);
7312
- const globalMatch = globalSessions.find(session => sessionMatchesResumeArg(session, sessionArg));
7415
+ const globalMatch = pickResumableSession(globalSessions, sessionArg);
7313
7416
  if (!globalMatch) {
7314
7417
  return undefined;
7315
7418
  }
@@ -7576,14 +7679,14 @@ type ManagedDestinationTransition = {
7576
7679
  /**
7577
7680
  * Freshness snapshot captured with every async whole-session persistence
7578
7681
  * preparation. Immediately before the synchronous persistence transaction, the
7579
- * live values are compared: a `sessionFile`/`lifecycleId` change aborts (lifecycle
7580
- * switch); a revision change discards the prepared bytes and re-prepares (bounded),
7682
+ * live values are compared: a logical lifecycle change aborts; a verified storage
7683
+ * relocation or revision change discards prepared bytes and re-prepares (bounded),
7581
7684
  * so a stale snapshot is never published.
7582
7685
  */
7583
7686
  export interface PersistenceInputToken {
7584
7687
  /** Canonical session file path the prepared bytes target. */
7585
7688
  sessionFile: string;
7586
- /** Per-manager lifecycle identity (`sessionId@sessionFile`); changes on switch/open/reset. */
7689
+ /** Logical lifecycle identity; storage-only relocation preserves its verified origin. */
7587
7690
  lifecycleId: string;
7588
7691
  /** Revision of #fileEntries affecting persisted bytes. */
7589
7692
  entryRevision: number;
@@ -7800,6 +7903,10 @@ export class SessionManager {
7800
7903
  #artifactManager: ArtifactManager | null = null;
7801
7904
  #artifactManagerSessionFile: string | null = null;
7802
7905
  #managedTranscriptStoreCache: { directory: string; store: ManagedSessionDescendantStore } | null = null;
7906
+ #managedTranscriptRelocationResolver: (() => ArtifactManager) | undefined;
7907
+ #managedTranscriptRelocationResolverToken: symbol | undefined;
7908
+ #managedTranscriptRelocationFileOrigin: string | undefined;
7909
+ #managedTranscriptRelocationParentArtifacts: ArtifactManager | undefined;
7803
7910
  #ownedManagedAuthority: ManagedSessionDescendantStore | undefined;
7804
7911
  #managedSidecarCacheStore: EphemeralBlobStore | undefined;
7805
7912
  readonly #managedSidecarCleanupStores = new Set<EphemeralBlobStore>();
@@ -8066,9 +8173,13 @@ export class SessionManager {
8066
8173
  this.#residentCacheWin32FallbackCount++;
8067
8174
  return { store: this.#newCanonicalResidentTextStore(), ownsStore: false };
8068
8175
  }
8069
- const instanceDir = openVerifiedResidentCacheInstanceDir(
8070
- getResidentCacheRootDir(this.#residentCacheProfileAgentDir()),
8071
- );
8176
+ const cacheRoot = getResidentCacheRootDir(this.#residentCacheProfileAgentDir());
8177
+ // Not a provisioning failure: retain-and-throw must still commit, with no file to stage.
8178
+ if (!residentTextCacheRootAllowsDisk(cacheRoot)) {
8179
+ this.#residentCacheAdoptFallbackCount++;
8180
+ return { store: this.#newCanonicalResidentTextStore(), ownsStore: false };
8181
+ }
8182
+ const instanceDir = openVerifiedResidentCacheInstanceDir(cacheRoot);
8072
8183
  return { store: EphemeralBlobStore.adoptVerifiedDir(instanceDir), ownsStore: true };
8073
8184
  }
8074
8185
 
@@ -10289,6 +10400,7 @@ export class SessionManager {
10289
10400
  }
10290
10401
  this.#artifactManager = null;
10291
10402
  this.#artifactManagerSessionFile = null;
10403
+ this.#clearManagedTranscriptRelocationResolver();
10292
10404
  this.#artifactLifecycle = Symbol("session-artifact-adoption");
10293
10405
  installedGeneration = this.#artifactLifecycle;
10294
10406
  installedSessionId = this.#sessionId;
@@ -10402,6 +10514,7 @@ export class SessionManager {
10402
10514
  throw error;
10403
10515
  }
10404
10516
  managedTransition?.adopt();
10517
+ this.#clearManagedTranscriptRelocationResolver();
10405
10518
  this.#sessionFile = resolvedSessionFile;
10406
10519
  this.#sessionId = sessionId;
10407
10520
  this.#sessionName = header?.title;
@@ -10489,6 +10602,7 @@ export class SessionManager {
10489
10602
  prepared.dispose();
10490
10603
  throw error;
10491
10604
  }
10605
+ this.#clearManagedTranscriptRelocationResolver();
10492
10606
  managedTransition?.settle();
10493
10607
  this.#pendingStrictAdoption = undefined;
10494
10608
  await this.#rewriteFile();
@@ -10958,6 +11072,7 @@ export class SessionManager {
10958
11072
  this.#adoptedArtifactManager = null;
10959
11073
  this.#managedPersistExpectedIdentity = expectedIdentity;
10960
11074
  this.#commitResidentTextStoreTransition(transition);
11075
+ this.#clearManagedTranscriptRelocationResolver();
10961
11076
  this.#retireEphemeralArtifacts();
10962
11077
  stage.committed = true;
10963
11078
  this.#preparedNewSessions.delete(stage);
@@ -12196,6 +12311,9 @@ export class SessionManager {
12196
12311
  path.basename(oldArtifactDir),
12197
12312
  managedPublishedArtifacts,
12198
12313
  );
12314
+ // The restored namespace has a new directory identity, even at the same path.
12315
+ this.#artifactManager = null;
12316
+ this.#artifactManagerSessionFile = null;
12199
12317
  }
12200
12318
  if (managedTranscript && !managedSourceStore.readExpected(path.basename(oldSessionFile)))
12201
12319
  await managedSourceStore.publishNoReplace(path.basename(oldSessionFile), managedTranscript.bytes);
@@ -12303,6 +12421,8 @@ export class SessionManager {
12303
12421
  path.basename(oldArtifactDir),
12304
12422
  managedPublishedArtifacts,
12305
12423
  );
12424
+ this.#artifactManager = null;
12425
+ this.#artifactManagerSessionFile = null;
12306
12426
  const restored = managedSourceStore.captureTree(path.basename(oldArtifactDir));
12307
12427
  if (!retainedTreeSnapshotEqualsAfterRename(restored, managedArtifacts))
12308
12428
  throw new Error("managed_move_source_restore_mismatch");
@@ -12653,7 +12773,7 @@ export class SessionManager {
12653
12773
  #capturePersistenceInputToken(): PersistenceInputToken {
12654
12774
  return {
12655
12775
  sessionFile: this.#sessionFile ?? "",
12656
- lifecycleId: `${this.#sessionId}@${this.#sessionFile ?? ""}`,
12776
+ lifecycleId: `${this.#sessionId}@${this.#managedTranscriptRelocationFileOrigin ?? this.#sessionFile ?? ""}`,
12657
12777
  entryRevision: this.#entryRevision,
12658
12778
  headerRevision: this.#headerExportRevision,
12659
12779
  residentBlobRevision: this.#residentBlobRevision,
@@ -12667,9 +12787,10 @@ export class SessionManager {
12667
12787
  */
12668
12788
  #persistenceInputTokenMatches(token: PersistenceInputToken): boolean {
12669
12789
  const live = this.#capturePersistenceInputToken();
12670
- if (live.sessionFile !== token.sessionFile || live.lifecycleId !== token.lifecycleId) {
12790
+ if (live.lifecycleId !== token.lifecycleId) {
12671
12791
  throw new Error("session_persistence_lifecycle_changed");
12672
12792
  }
12793
+ if (live.sessionFile !== token.sessionFile) return false;
12673
12794
  return (
12674
12795
  live.entryRevision === token.entryRevision &&
12675
12796
  live.headerRevision === token.headerRevision &&
@@ -12935,10 +13056,162 @@ export class SessionManager {
12935
13056
  this.#ownedManagedAuthority = undefined;
12936
13057
  }
12937
13058
 
13059
+ /**
13060
+ * Register the same-owner task capability used to follow a parent's managed
13061
+ * artifact root after its session move. The synchronous resolver must return
13062
+ * only the current ArtifactManager for the same parent ID and parent transcript
13063
+ * basename; it retains the last verified manager on a logical successor.
13064
+ * Registration captures the exact original manager identity. Unchanged identity
13065
+ * keeps using the child's retained store; a changed identity triggers strict
13066
+ * destination transcript verification before re-rooting.
13067
+ */
13068
+ registerManagedTranscriptRelocationResolver(resolver: () => ArtifactManager): () => void {
13069
+ if (this.destination.kind !== "managed")
13070
+ throw new Error("Managed transcript relocation requires a managed session");
13071
+ if (this.#managedTranscriptRelocationResolver)
13072
+ throw new Error("Managed transcript relocation resolver is already registered");
13073
+ const originalParentArtifacts = resolver();
13074
+ const registrationToken = Symbol("managed-transcript-relocation");
13075
+ this.#managedTranscriptRelocationResolver = resolver;
13076
+ this.#managedTranscriptRelocationResolverToken = registrationToken;
13077
+ this.#managedTranscriptRelocationParentArtifacts = originalParentArtifacts;
13078
+ return () => {
13079
+ if (this.#managedTranscriptRelocationResolverToken === registrationToken)
13080
+ this.#clearManagedTranscriptRelocationResolver();
13081
+ };
13082
+ }
13083
+
13084
+ #clearManagedTranscriptRelocationResolver(): void {
13085
+ this.#managedTranscriptRelocationResolver = undefined;
13086
+ this.#managedTranscriptRelocationResolverToken = undefined;
13087
+ this.#managedTranscriptRelocationFileOrigin = undefined;
13088
+ this.#managedTranscriptRelocationParentArtifacts = undefined;
13089
+ }
13090
+
13091
+ #refreshManagedTranscriptRelocation(sessionFile = this.#sessionFile): void {
13092
+ const currentSessionFile = this.#sessionFile;
13093
+ const resolver = this.#managedTranscriptRelocationResolver;
13094
+ if (this.destination.kind !== "managed" || !currentSessionFile || sessionFile !== currentSessionFile || !resolver)
13095
+ return;
13096
+
13097
+ const parentArtifacts = resolver();
13098
+ const nextDirectory = path.resolve(parentArtifacts.dir);
13099
+ const parentArtifactsChanged = this.#managedTranscriptRelocationParentArtifacts !== parentArtifacts;
13100
+ if (nextDirectory === path.resolve(this.destination.directory) && !parentArtifactsChanged) return;
13101
+ parentArtifacts.assertManagedBinding();
13102
+ const parentStore = parentArtifacts.getManagedStore();
13103
+ if (!parentStore || path.resolve(parentStore.dir) !== nextDirectory)
13104
+ throw new Error("managed_transcript_relocation_parent_authority_unavailable");
13105
+ parentStore.assertBound();
13106
+ if (path.resolve(path.dirname(currentSessionFile)) !== path.resolve(this.destination.directory))
13107
+ throw new Error("managed_transcript_relocation_source_path_unverified");
13108
+ const transcriptName = path.basename(currentSessionFile);
13109
+ const nextSessionFile = path.join(nextDirectory, transcriptName);
13110
+ if (path.basename(nextSessionFile) !== transcriptName)
13111
+ throw new Error("managed_transcript_relocation_transcript_name_mismatch");
13112
+
13113
+ if (this.#stagedPublication) throw new Error("managed_transcript_relocation_staged_publication_unavailable");
13114
+ if (this.#persistWriter || this.#persistWriterPath)
13115
+ throw new Error("managed_transcript_relocation_writer_unavailable");
13116
+ if (this.#boundedManagedSource) throw new Error("managed_transcript_relocation_bounded_source_unavailable");
13117
+ if (this.#coldSidecarActive() || (this.#sidecarRuntime?.coldEntries.size ?? 0) > 0)
13118
+ throw new Error("managed_transcript_relocation_cold_sidecar_unavailable");
13119
+ if (this.#recoveryHydrationContext || this.#recoveryPromotionTranscriptPath || this.#pendingStrictAdoption)
13120
+ throw new Error("managed_transcript_relocation_recovery_state_unavailable");
13121
+
13122
+ const expectedIdentity = this.#managedPersistExpectedIdentity;
13123
+ if (
13124
+ !expectedIdentity ||
13125
+ !Number.isSafeInteger(expectedIdentity.size) ||
13126
+ expectedIdentity.size < 0 ||
13127
+ typeof expectedIdentity.sha256 !== "string" ||
13128
+ !/^[0-9a-f]{64}$/.test(expectedIdentity.sha256)
13129
+ )
13130
+ throw new Error("managed_transcript_relocation_original_identity_unavailable");
13131
+
13132
+ let nextDestination: SessionDestination | undefined;
13133
+ let nextStore: ManagedSessionDescendantStore | undefined;
13134
+ let adopted = false;
13135
+ try {
13136
+ nextDestination = SessionManager.nestedManagedDestination(parentStore, nextDirectory);
13137
+ if (nextDestination.kind !== "managed")
13138
+ throw new Error("managed_transcript_relocation_destination_unavailable");
13139
+ nextStore = managedStoreFromContext(nextDestination.securityContext, nextDirectory);
13140
+ nextStore.verifyRootSecurity();
13141
+ nextStore.assertBound();
13142
+ const destinationTranscript = nextStore.readExpected(transcriptName);
13143
+ if (!destinationTranscript) throw new Error("managed_transcript_relocation_destination_missing");
13144
+ const destinationSha256 = crypto.createHash("sha256").update(destinationTranscript.bytes).digest("hex");
13145
+ if (
13146
+ destinationTranscript.identity.size !== expectedIdentity.size ||
13147
+ destinationTranscript.bytes.byteLength !== expectedIdentity.size ||
13148
+ destinationTranscript.identity.sha256 !== expectedIdentity.sha256 ||
13149
+ destinationSha256 !== expectedIdentity.sha256
13150
+ )
13151
+ throw new Error("managed_transcript_relocation_destination_identity_mismatch");
13152
+
13153
+ parentArtifacts.assertManagedBinding();
13154
+ parentStore.assertBound();
13155
+ nextStore.assertBound();
13156
+
13157
+ const previousDestination = this.destination;
13158
+ const previousCache = this.#managedTranscriptStoreCache;
13159
+ const previousOwnedAuthority = this.#ownedManagedAuthority;
13160
+ const previousArtifactStore = this.#artifactManager?.getManagedStore();
13161
+ // A hot/shadow sidecar remains a disposable cache over the same verified
13162
+ // transcript bytes. Keep its resident state and cache root; only retag the
13163
+ // cache key. Cold and bounded source state was rejected above because it
13164
+ // pins descriptor/path state that cannot be retargeted without rebuilding.
13165
+ if (this.#managedSidecarCacheStore) this.#managedSidecarCacheSessionFile = nextSessionFile;
13166
+ this.#boundedReadStorageProxy = undefined;
13167
+ this.#managedTranscriptRelocationFileOrigin ??= currentSessionFile;
13168
+ this.destination = nextDestination;
13169
+ this.sessionDir = nextDirectory;
13170
+ this.#sessionFile = nextSessionFile;
13171
+ this.#managedTranscriptStoreCache = { directory: nextDirectory, store: nextStore };
13172
+ this.#managedPersistExpectedIdentity = { ...destinationTranscript.identity };
13173
+ this.#managedRangeExpectedDescriptor = {
13174
+ dev: destinationTranscript.identity.dev,
13175
+ ino: destinationTranscript.identity.ino,
13176
+ nlink: destinationTranscript.identity.nlink,
13177
+ size: destinationTranscript.identity.size,
13178
+ mtimeNs: destinationTranscript.identity.mtimeNs,
13179
+ ctimeNs: destinationTranscript.identity.ctimeNs,
13180
+ };
13181
+ this.#adoptedArtifactManager = parentArtifacts;
13182
+ this.#managedTranscriptRelocationParentArtifacts = parentArtifacts;
13183
+ this.#artifactManager = null;
13184
+ this.#artifactManagerSessionFile = null;
13185
+ this.#ownedManagedAuthority = undefined;
13186
+ adopted = true;
13187
+
13188
+ // These stores were created by this manager. Their close methods release
13189
+ // only authorities they actually own; the borrowed parent manager remains
13190
+ // untouched.
13191
+ previousCache?.store.close();
13192
+ if (previousOwnedAuthority && previousOwnedAuthority !== previousCache?.store) previousOwnedAuthority.close();
13193
+ if (previousArtifactStore && previousArtifactStore !== parentStore && previousArtifactStore !== nextStore)
13194
+ previousArtifactStore.close();
13195
+ if (previousDestination.kind === "managed") previousDestination.securityContext.retainedAuthority?.close();
13196
+ } catch (error) {
13197
+ if (!adopted) {
13198
+ nextStore?.close();
13199
+ if (nextDestination?.kind === "managed") nextDestination.securityContext.retainedAuthority?.close();
13200
+ }
13201
+ throw error;
13202
+ }
13203
+ }
13204
+
12938
13205
  #managedTranscriptStore(sessionFile = this.#sessionFile): ManagedSessionDescendantStore {
12939
13206
  if (this.destination.kind !== "managed" || !sessionFile) {
12940
13207
  throw new Error("Managed transcript authority is unavailable");
12941
13208
  }
13209
+ const previousSessionFile = this.#sessionFile;
13210
+ if (sessionFile === previousSessionFile) {
13211
+ this.#refreshManagedTranscriptRelocation(sessionFile);
13212
+ if (this.#sessionFile !== previousSessionFile) sessionFile = this.#sessionFile;
13213
+ }
13214
+ if (!sessionFile) throw new Error("Managed transcript authority is unavailable");
12942
13215
  const sessionDir = path.resolve(path.dirname(sessionFile));
12943
13216
  if (sessionDir !== path.resolve(this.destination.directory)) {
12944
13217
  throw new Error("Managed transcript escaped its session directory");
@@ -16592,6 +16865,7 @@ export class SessionManager {
16592
16865
  // aborts. A stale snapshot is never published.
16593
16866
  let written = false;
16594
16867
  for (let attempt = 0; attempt <= 2 && !written; attempt++) {
16868
+ this.#refreshManagedTranscriptRelocation();
16595
16869
  this.#ensureFullHotView();
16596
16870
  const token = this.#capturePersistenceInputToken();
16597
16871
  await this.#closePersistWriterInternal();
@@ -16601,6 +16875,7 @@ export class SessionManager {
16601
16875
  ),
16602
16876
  );
16603
16877
  written = this.#withSessionPersistenceFenceSync(() => {
16878
+ this.#refreshManagedTranscriptRelocation();
16604
16879
  if (!this.#persistenceInputTokenMatches(token)) return false;
16605
16880
  this.#writeEntriesAtomicallySync(entries);
16606
16881
  return true;
@@ -16624,6 +16899,7 @@ export class SessionManager {
16624
16899
 
16625
16900
  #rewriteFileSync(): void {
16626
16901
  if (!this.persist || !this.#sessionFile) return;
16902
+ this.#refreshManagedTranscriptRelocation();
16627
16903
  this.#withSessionPersistenceFenceSync(() => {
16628
16904
  this.#ensureFullHotView();
16629
16905
  // Sync lane: capture and check the token immediately (always fresh absent
@@ -16958,6 +17234,7 @@ export class SessionManager {
16958
17234
  }
16959
17235
 
16960
17236
  #releaseClosedSessionState(): void {
17237
+ this.#clearManagedTranscriptRelocationResolver();
16961
17238
  const runtime = this.#sidecarRuntime;
16962
17239
  if (runtime) {
16963
17240
  runtime.enabled = false;
@@ -18552,6 +18829,7 @@ export class SessionManager {
18552
18829
  }
18553
18830
 
18554
18831
  #appendManagedRecordsSync(records: readonly (FileEntry | SessionPatchRecord)[]): void {
18832
+ this.#refreshManagedTranscriptRelocation();
18555
18833
  if (!this.#sessionFile) throw new Error("Managed transcript path is unavailable");
18556
18834
  this.#withSessionPersistenceFenceSync(() => {
18557
18835
  const sessionFile = this.#sessionFile!;
@@ -18580,12 +18858,23 @@ export class SessionManager {
18580
18858
 
18581
18859
  async #persistPatches(records: readonly SessionPatchRecord[]): Promise<void> {
18582
18860
  if (records.length === 0) return;
18583
- if (this.#coldSidecarActive()) this.#deactivateColdForBranchMutation();
18584
- if (!this.persist || !this.#sessionFile || !this.#storage.existsSync(this.#sessionFile)) return;
18585
- const sessionFile = this.#sessionFile;
18861
+ try {
18862
+ this.#refreshManagedTranscriptRelocation();
18863
+ } catch (error) {
18864
+ this.#recordPersistError(error);
18865
+ throw this.#persistError ?? toError(error);
18866
+ }
18867
+ if (!this.persist || !this.#sessionFile || !this.#storage.existsSync(this.#sessionFile)) {
18868
+ if (this.#coldSidecarActive()) this.#deactivateColdForBranchMutation();
18869
+ return;
18870
+ }
18871
+ let sessionFile = this.#sessionFile;
18586
18872
  const publishResumeBreadcrumb = this.#readOnlyResume;
18587
18873
  await this.#queuePersistTask(async () => {
18588
18874
  for (let attempt = 0; attempt <= 2; attempt++) {
18875
+ this.#refreshManagedTranscriptRelocation();
18876
+ if (this.#coldSidecarActive()) this.#deactivateColdForBranchMutation();
18877
+ sessionFile = this.#sessionFile!;
18589
18878
  const token = this.#capturePersistenceInputToken();
18590
18879
  const header = this.#fileEntries.find(entry => entry.type === "session") as SessionHeader | undefined;
18591
18880
  if (
@@ -18594,6 +18883,7 @@ export class SessionManager {
18594
18883
  (header?.version ?? 1) < CURRENT_SESSION_VERSION
18595
18884
  ) {
18596
18885
  await this.#rewriteFileContents();
18886
+ sessionFile = this.#sessionFile!;
18597
18887
  if (publishResumeBreadcrumb) writeTerminalBreadcrumb(this.cwd, sessionFile);
18598
18888
  this.#readOnlyResume = false;
18599
18889
  return;
@@ -18613,6 +18903,7 @@ export class SessionManager {
18613
18903
  SessionManagerTestHooks.beforePersistPatchFence?.(attempt);
18614
18904
  let persisted = false;
18615
18905
  const written = this.#withSessionPersistenceFenceSync(() => {
18906
+ this.#refreshManagedTranscriptRelocation();
18616
18907
  if (!this.#persistenceInputTokenMatches(token)) return false;
18617
18908
  if (this.destination.kind === "managed") {
18618
18909
  this.#appendManagedRecordsSync(persistedRecords);
@@ -18645,8 +18936,14 @@ export class SessionManager {
18645
18936
  _persist(entry: SessionEntry): void {
18646
18937
  if (!this.persist || !this.#sessionFile) return;
18647
18938
  if (this.#strictClosePending) throw new Error("Session manager is closing.");
18648
- const publishResumeBreadcrumb = this.#readOnlyResume;
18649
18939
  if (this.#persistError) throw this.#persistError;
18940
+ try {
18941
+ this.#refreshManagedTranscriptRelocation();
18942
+ } catch (error) {
18943
+ this.#recordPersistError(error);
18944
+ throw this.#persistError ?? toError(error);
18945
+ }
18946
+ const publishResumeBreadcrumb = this.#readOnlyResume;
18650
18947
 
18651
18948
  // Normally we wait for the first assistant message before persisting to avoid
18652
18949
  // creating files for sessions that never produce output. Once ensureOnDisk() has
@@ -20553,6 +20850,7 @@ export class SessionManager {
20553
20850
  }
20554
20851
  this.#sessionId = newSessionId;
20555
20852
  this.#sessionFile = newSessionFile;
20853
+ this.#clearManagedTranscriptRelocationResolver();
20556
20854
  this.#flushed = true;
20557
20855
  this.#commitResidentTextStoreTransition(transition);
20558
20856
  this.#adoptManagedPersistIdentity(newSessionFile);
@@ -20587,6 +20885,7 @@ export class SessionManager {
20587
20885
  "retain-and-throw",
20588
20886
  );
20589
20887
  this.#sessionId = newSessionId;
20888
+ this.#clearManagedTranscriptRelocationResolver();
20590
20889
  this.#commitResidentTextStoreTransition(transition);
20591
20890
  return undefined;
20592
20891
  }
@@ -23045,7 +23344,15 @@ export class SessionManager {
23045
23344
  storage,
23046
23345
  );
23047
23346
 
23048
- const terminalSession = await readTerminalBreadcrumb(cwd);
23347
+ const terminalSession = await readTerminalBreadcrumb(cwd, {
23348
+ ...(destination.kind === "managed"
23349
+ ? {
23350
+ sessionsRoot: destination.securityContext.sessionsRoot,
23351
+ continuationInventory: managedCandidates,
23352
+ }
23353
+ : {}),
23354
+ allowExplicitOutsideRoot: destination.kind === "explicit",
23355
+ });
23049
23356
  const terminalSessionIsInExplicitRoot = (() => {
23050
23357
  if (destination.kind === "managed" || !terminalSession) return destination.kind === "managed";
23051
23358
  const canonicalRoot = canonicalizeTrustedPath(destination.directory);