@gajae-code/coding-agent 0.13.2 → 0.14.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 (610) hide show
  1. package/CHANGELOG.md +215 -8
  2. package/README.md +2 -0
  3. package/bin/gajaessi.js +4 -0
  4. package/dist/types/async/job-manager.d.ts +55 -2
  5. package/dist/types/async/support.d.ts +14 -0
  6. package/dist/types/capability/mcp.d.ts +6 -0
  7. package/dist/types/capability/types.d.ts +6 -0
  8. package/dist/types/cli/accounts-cli.d.ts +19 -0
  9. package/dist/types/cli/args.d.ts +3 -0
  10. package/dist/types/cli/config-cli.d.ts +6 -0
  11. package/dist/types/cli/crash-cli.d.ts +10 -0
  12. package/dist/types/cli/customize-doctor.d.ts +145 -0
  13. package/dist/types/cli/daemon-cli.d.ts +3 -1
  14. package/dist/types/cli/mcp-cli.d.ts +11 -0
  15. package/dist/types/cli/notify-cli.d.ts +1 -1
  16. package/dist/types/cli/root-flags.d.ts +12 -0
  17. package/dist/types/cli/setup-cli.d.ts +3 -1
  18. package/dist/types/cli/skills-cli.d.ts +2 -1
  19. package/dist/types/cli/update-cli.d.ts +19 -1
  20. package/dist/types/cli.d.ts +6 -0
  21. package/dist/types/commands/accounts.d.ts +40 -0
  22. package/dist/types/commands/crash.d.ts +24 -0
  23. package/dist/types/commands/customize.d.ts +22 -0
  24. package/dist/types/commands/daemon.d.ts +1 -1
  25. package/dist/types/commands/launch.d.ts +6 -0
  26. package/dist/types/commands/setup.d.ts +6 -0
  27. package/dist/types/commands/skills.d.ts +6 -1
  28. package/dist/types/commands/update.d.ts +7 -0
  29. package/dist/types/config/atomic-yaml-patch-worker.d.ts +25 -0
  30. package/dist/types/config/atomic-yaml-patch.d.ts +62 -2
  31. package/dist/types/config/config-schema-version.d.ts +10 -0
  32. package/dist/types/config/file-lock.d.ts +18 -0
  33. package/dist/types/config/model-profile-activation.d.ts +3 -1
  34. package/dist/types/config/model-registry.d.ts +10 -1
  35. package/dist/types/config/models-config-schema.d.ts +2 -0
  36. package/dist/types/config/settings-schema.d.ts +73 -9
  37. package/dist/types/config/settings.d.ts +63 -0
  38. package/dist/types/config/skill-settings-defaults.d.ts +26 -0
  39. package/dist/types/config/task-delegation.d.ts +39 -0
  40. package/dist/types/config/update-channel.d.ts +10 -0
  41. package/dist/types/coordinator-mcp/server.d.ts +5 -1
  42. package/dist/types/crash/index-store.d.ts +87 -0
  43. package/dist/types/crash/nudge.d.ts +50 -0
  44. package/dist/types/crash/record-loader.d.ts +17 -0
  45. package/dist/types/crash/report.d.ts +134 -0
  46. package/dist/types/crash/sanitize.d.ts +25 -0
  47. package/dist/types/cursor.d.ts +13 -2
  48. package/dist/types/customization/import.d.ts +37 -0
  49. package/dist/types/customization/index.d.ts +4 -0
  50. package/dist/types/customization/inventory.d.ts +25 -0
  51. package/dist/types/customization/mutations.d.ts +32 -0
  52. package/dist/types/customization/types.d.ts +115 -0
  53. package/dist/types/daemon/control-types.d.ts +8 -1
  54. package/dist/types/daemon/operator-contract.d.ts +4 -4
  55. package/dist/types/discovery/claude.d.ts +39 -1
  56. package/dist/types/discovery/codex.d.ts +39 -1
  57. package/dist/types/discovery/index.d.ts +2 -0
  58. package/dist/types/discovery/mcp-compat.d.ts +30 -0
  59. package/dist/types/edit/renderer.d.ts +23 -0
  60. package/dist/types/extensibility/extensions/runner.d.ts +3 -0
  61. package/dist/types/extensibility/extensions/types.d.ts +21 -4
  62. package/dist/types/extensibility/gjc-plugins/observability.d.ts +6 -1
  63. package/dist/types/extensibility/gjc-plugins/registry.d.ts +8 -1
  64. package/dist/types/extensibility/hooks/loader.d.ts +19 -5
  65. package/dist/types/extensibility/runtime-skill-discovery.d.ts +22 -1
  66. package/dist/types/extensibility/skill-management.d.ts +107 -0
  67. package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +3 -1
  68. package/dist/types/gjc-runtime/launch-worktree.d.ts +8 -0
  69. package/dist/types/gjc-runtime/linux-proc.d.ts +3 -0
  70. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +10 -6
  71. package/dist/types/gjc-runtime/session-state-lock.d.ts +104 -0
  72. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +120 -2
  73. package/dist/types/gjc-runtime/state-writer.d.ts +10 -1
  74. package/dist/types/gjc-runtime/ultragoal-guard.d.ts +4 -2
  75. package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +8 -6
  76. package/dist/types/gjc-runtime/workflow-settings.d.ts +109 -0
  77. package/dist/types/hooks/events.d.ts +60 -0
  78. package/dist/types/hooks/normalize.d.ts +83 -0
  79. package/dist/types/hooks/skill-state.d.ts +9 -2
  80. package/dist/types/main.d.ts +2 -1
  81. package/dist/types/modes/acp/abort-scope.d.ts +13 -0
  82. package/dist/types/modes/acp/acp-agent.d.ts +7 -4
  83. package/dist/types/modes/components/customization/customization-dashboard.d.ts +44 -0
  84. package/dist/types/modes/components/customization/import-wizard.d.ts +21 -0
  85. package/dist/types/modes/components/customization/index.d.ts +1 -0
  86. package/dist/types/modes/components/dynamic-theme-text.d.ts +9 -0
  87. package/dist/types/modes/components/gajae-pet-widget.d.ts +6 -28
  88. package/dist/types/modes/components/irc-sidebar.d.ts +1 -0
  89. package/dist/types/modes/components/iterm-pet-transport.d.ts +122 -0
  90. package/dist/types/modes/components/oauth-selector.d.ts +10 -4
  91. package/dist/types/modes/components/pet-capability.d.ts +7 -21
  92. package/dist/types/modes/components/settings-selector.d.ts +5 -0
  93. package/dist/types/modes/components/status-line/gh.d.ts +6 -2
  94. package/dist/types/modes/controllers/extension-ui-controller.d.ts +1 -1
  95. package/dist/types/modes/controllers/selector-controller.d.ts +7 -8
  96. package/dist/types/modes/controllers/stt-controller.d.ts +1 -1
  97. package/dist/types/modes/interactive-mode.d.ts +1 -0
  98. package/dist/types/modes/theme/defaults/index.d.ts +118 -0
  99. package/dist/types/modes/types.d.ts +1 -0
  100. package/dist/types/modes/utils/injected-user-submission.d.ts +10 -0
  101. package/dist/types/runtime-mcp/config.d.ts +9 -0
  102. package/dist/types/runtime-mcp/manager.d.ts +26 -1
  103. package/dist/types/runtime-mcp/oauth-discovery.d.ts +4 -0
  104. package/dist/types/runtime-mcp/oauth-flow.d.ts +24 -1
  105. package/dist/types/runtime-mcp/pool-key.d.ts +2 -0
  106. package/dist/types/runtime-mcp/protocol.d.ts +278 -0
  107. package/dist/types/runtime-mcp/scope-config.d.ts +29 -0
  108. package/dist/types/runtime-mcp/tool-bridge.d.ts +15 -13
  109. package/dist/types/runtime-mcp/transports/http.d.ts +9 -0
  110. package/dist/types/runtime-mcp/types.d.ts +102 -10
  111. package/dist/types/sdk/acp/adapter.d.ts +26 -5
  112. package/dist/types/sdk/broker/broker.d.ts +3 -55
  113. package/dist/types/sdk/broker/lifecycle.d.ts +18 -12
  114. package/dist/types/sdk/broker/session-index.d.ts +14 -5
  115. package/dist/types/sdk/broker/startup-failure.d.ts +16 -1
  116. package/dist/types/sdk/bus/chat-daemon-control.d.ts +51 -1
  117. package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -41
  118. package/dist/types/sdk/bus/config.d.ts +11 -0
  119. package/dist/types/sdk/bus/conversation-store.d.ts +0 -1
  120. package/dist/types/sdk/bus/daemon-paths.d.ts +6 -0
  121. package/dist/types/sdk/bus/discord-conversation.d.ts +2 -0
  122. package/dist/types/sdk/bus/discord-daemon.d.ts +17 -12
  123. package/dist/types/sdk/bus/existing-thread-readiness.d.ts +4 -34
  124. package/dist/types/sdk/bus/inbound-reaction-ordering.d.ts +61 -0
  125. package/dist/types/sdk/bus/index.d.ts +85 -99
  126. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +29 -7
  127. package/dist/types/sdk/bus/managed-daemon.d.ts +2 -32
  128. package/dist/types/sdk/bus/notification-service.d.ts +52 -0
  129. package/dist/types/sdk/bus/operator-runtime.d.ts +1 -1
  130. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +16 -5
  131. package/dist/types/sdk/bus/reconciliation-store.d.ts +113 -5
  132. package/dist/types/sdk/bus/session-control.d.ts +25 -1
  133. package/dist/types/sdk/bus/slack-conversation.d.ts +4 -0
  134. package/dist/types/sdk/bus/slack-daemon.d.ts +9 -17
  135. package/dist/types/sdk/bus/slack-live-provider.d.ts +3 -1
  136. package/dist/types/sdk/bus/slack-provider.d.ts +4 -0
  137. package/dist/types/sdk/bus/slack-thread-binding.d.ts +6 -40
  138. package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +30 -104
  139. package/dist/types/sdk/bus/telegram-daemon-cli.d.ts +10 -0
  140. package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +262 -19
  141. package/dist/types/sdk/bus/telegram-daemon-orphan-reap.d.ts +125 -0
  142. package/dist/types/sdk/bus/telegram-daemon-owner-registry.d.ts +22 -0
  143. package/dist/types/sdk/bus/telegram-daemon.d.ts +119 -310
  144. package/dist/types/sdk/bus/telegram-reference.d.ts +1 -47
  145. package/dist/types/sdk/bus/threaded-render.d.ts +1 -0
  146. package/dist/types/sdk/bus/topic-registry.d.ts +33 -17
  147. package/dist/types/sdk/cli/rows.d.ts +2 -11
  148. package/dist/types/sdk/cli/session-cli.d.ts +15 -25
  149. package/dist/types/sdk/client/client.d.ts +97 -1
  150. package/dist/types/sdk/host/control/dispatch.d.ts +0 -7
  151. package/dist/types/sdk/host/control/index.d.ts +1 -1
  152. package/dist/types/sdk/host/control/operations.d.ts +18 -5
  153. package/dist/types/sdk/host/control/runtime-gate.d.ts +19 -0
  154. package/dist/types/sdk/host/host.d.ts +15 -1
  155. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  156. package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
  157. package/dist/types/sdk/host/session-runtime.d.ts +127 -7
  158. package/dist/types/sdk/host/types.d.ts +1 -1
  159. package/dist/types/sdk/host/websocket-transport.d.ts +1 -1
  160. package/dist/types/sdk/index.d.ts +2 -1
  161. package/dist/types/sdk/lifecycle/broker-client.d.ts +8 -0
  162. package/dist/types/sdk/lifecycle/client.d.ts +59 -0
  163. package/dist/types/sdk/lifecycle/index.d.ts +3 -0
  164. package/dist/types/sdk/lifecycle/service.d.ts +232 -0
  165. package/dist/types/sdk/mcp/server.d.ts +9 -6
  166. package/dist/types/sdk/prompt-deadline-lease.d.ts +43 -0
  167. package/dist/types/sdk/prompt-deadline-manager.d.ts +28 -0
  168. package/dist/types/sdk/prompt-status.d.ts +10 -3
  169. package/dist/types/sdk/protocol/operation-registry.d.ts +5 -0
  170. package/dist/types/sdk/receipt-state.d.ts +17 -0
  171. package/dist/types/sdk/reconciliation-extensions.d.ts +2 -0
  172. package/dist/types/sdk/router/index.d.ts +1 -0
  173. package/dist/types/sdk/router/session-router.d.ts +152 -0
  174. package/dist/types/sdk/session-list.d.ts +22 -0
  175. package/dist/types/sdk/session-reconnect.d.ts +43 -1
  176. package/dist/types/sdk/session.d.ts +34 -1
  177. package/dist/types/sdk/transport/serve-cli.d.ts +1 -4
  178. package/dist/types/session/account-inventory.d.ts +86 -0
  179. package/dist/types/session/agent-session.d.ts +145 -6
  180. package/dist/types/session/agent-storage.d.ts +10 -0
  181. package/dist/types/session/coordinator-tool-label.d.ts +28 -0
  182. package/dist/types/session/internal/managed-session-storage.d.ts +23 -4
  183. package/dist/types/session/messages.d.ts +1 -1
  184. package/dist/types/session/secure-token-file.d.ts +3 -0
  185. package/dist/types/session/session-manager.d.ts +47 -1
  186. package/dist/types/session/startup-auth-config.d.ts +44 -0
  187. package/dist/types/session/terminal-abort.d.ts +378 -0
  188. package/dist/types/session/yield-queue.d.ts +7 -0
  189. package/dist/types/session-import/claude.d.ts +26 -0
  190. package/dist/types/session-import/codex.d.ts +88 -0
  191. package/dist/types/session-import/command.d.ts +35 -0
  192. package/dist/types/session-import/detect.d.ts +22 -0
  193. package/dist/types/session-import/index.d.ts +7 -0
  194. package/dist/types/session-import/provider-codex.d.ts +22 -0
  195. package/dist/types/session-import/provider-service.d.ts +38 -0
  196. package/dist/types/session-import/redact.d.ts +23 -0
  197. package/dist/types/session-import/service.d.ts +47 -0
  198. package/dist/types/session-import/types.d.ts +120 -0
  199. package/dist/types/setup/paseo/check.d.ts +16 -0
  200. package/dist/types/setup/paseo/install-saga.d.ts +115 -0
  201. package/dist/types/setup/paseo/json-publisher.d.ts +76 -0
  202. package/dist/types/setup/paseo/orchestration-preferences.d.ts +24 -0
  203. package/dist/types/setup/paseo/paseo-ownership.d.ts +87 -0
  204. package/dist/types/setup/paseo/paseo-setup.d.ts +29 -0
  205. package/dist/types/setup/paseo/provider-config.d.ts +35 -0
  206. package/dist/types/setup/paseo/remove.d.ts +14 -0
  207. package/dist/types/setup/paseo/result-types.d.ts +59 -0
  208. package/dist/types/setup/paseo/setup-deps.d.ts +73 -0
  209. package/dist/types/setup/paseo/skills-bridge.d.ts +44 -0
  210. package/dist/types/skill-state/active-state.d.ts +5 -1
  211. package/dist/types/slash-commands/acp-builtins.d.ts +5 -1
  212. package/dist/types/slash-commands/builtin-registry.d.ts +2 -0
  213. package/dist/types/slash-commands/helpers/credential-switch.d.ts +12 -0
  214. package/dist/types/slash-commands/helpers/usage-report.d.ts +5 -6
  215. package/dist/types/slash-commands/types.d.ts +7 -1
  216. package/dist/types/task/executor.d.ts +10 -0
  217. package/dist/types/task/index.d.ts +3 -1
  218. package/dist/types/tools/ask-answer-registry.d.ts +6 -3
  219. package/dist/types/tools/bash-sleep-advisory.d.ts +14 -0
  220. package/dist/types/tools/bash.d.ts +2 -6
  221. package/dist/types/tools/browser/attach.d.ts +11 -0
  222. package/dist/types/tools/browser/launch.d.ts +20 -0
  223. package/dist/types/tools/browser/profile-discovery.d.ts +6 -0
  224. package/dist/types/tools/browser/render.d.ts +1 -0
  225. package/dist/types/tools/browser.d.ts +3 -1
  226. package/dist/types/tools/image-gen.d.ts +10 -2
  227. package/dist/types/tools/index.d.ts +8 -0
  228. package/dist/types/tools/monitor.d.ts +1 -1
  229. package/dist/types/tools/skill-discovery.d.ts +8 -1
  230. package/dist/types/tools/subagent.d.ts +2 -0
  231. package/dist/types/tools/ultragoal-ask-guard.d.ts +2 -2
  232. package/dist/types/utils/herdr-pane.d.ts +76 -0
  233. package/package.json +19 -9
  234. package/scripts/build-binary.ts +2 -1
  235. package/scripts/build-sdk-package-smoke.ts +2 -13
  236. package/scripts/capture-sticky-viewport-showcase.ts +0 -1
  237. package/scripts/compile-args.ts +2 -0
  238. package/scripts/generate-sdk-adapter-parity-manifest.ts +31 -16
  239. package/scripts/generate-sdk-operation-inventory.ts +28 -0
  240. package/scripts/generate-telegram-baseline-manifest.ts +1 -0
  241. package/scripts/generate-tool-catalog.ts +6 -4
  242. package/scripts/verify-gjc-sdk-canonicalization.ts +5 -39
  243. package/src/async/job-manager.ts +352 -17
  244. package/src/async/support.ts +25 -0
  245. package/src/autoresearch/dashboard.ts +28 -13
  246. package/src/capability/index.ts +3 -1
  247. package/src/capability/mcp.ts +6 -0
  248. package/src/capability/types.ts +6 -0
  249. package/src/cli/accounts-cli.ts +395 -0
  250. package/src/cli/args.ts +23 -0
  251. package/src/cli/auth-broker-cli.ts +136 -66
  252. package/src/cli/auth-gateway-cli.ts +94 -70
  253. package/src/cli/config-cli.ts +27 -2
  254. package/src/cli/crash-cli.ts +78 -0
  255. package/src/cli/customize-doctor.ts +1605 -0
  256. package/src/cli/daemon-cli.ts +12 -3
  257. package/src/cli/fast-help.ts +1 -0
  258. package/src/cli/mcp-cli.ts +128 -60
  259. package/src/cli/notify-cli.ts +8 -14
  260. package/src/cli/root-flags.ts +8 -0
  261. package/src/cli/setup-cli.ts +145 -0
  262. package/src/cli/skills-cli.ts +38 -2
  263. package/src/cli/update-cli.ts +167 -12
  264. package/src/cli.ts +4 -0
  265. package/src/commands/accounts.ts +71 -0
  266. package/src/commands/crash.ts +35 -0
  267. package/src/commands/customize.ts +84 -0
  268. package/src/commands/daemon.ts +2 -2
  269. package/src/commands/deep-interview.ts +2 -0
  270. package/src/commands/launch.ts +1 -0
  271. package/src/commands/mcp.ts +12 -7
  272. package/src/commands/ralplan.ts +2 -0
  273. package/src/commands/sdk.ts +65 -32
  274. package/src/commands/setup.ts +5 -0
  275. package/src/commands/skills.ts +14 -4
  276. package/src/commands/ultragoal.ts +10 -1
  277. package/src/commands/update.ts +26 -15
  278. package/src/config/atomic-yaml-patch-worker.ts +57 -0
  279. package/src/config/atomic-yaml-patch.ts +769 -29
  280. package/src/config/config-schema-version.ts +10 -0
  281. package/src/config/file-lock.ts +70 -1
  282. package/src/config/mcp-schema.json +52 -14
  283. package/src/config/model-profile-activation.ts +23 -2
  284. package/src/config/model-profiles.ts +88 -21
  285. package/src/config/model-registry.ts +147 -21
  286. package/src/config/models-config-schema.ts +1 -1
  287. package/src/config/settings-schema.ts +77 -7
  288. package/src/config/settings.ts +4038 -199
  289. package/src/config/skill-settings-defaults.ts +41 -3
  290. package/src/config/task-delegation.ts +87 -0
  291. package/src/config/update-channel.ts +23 -0
  292. package/src/coordinator-mcp/server.ts +377 -308
  293. package/src/crash/index-store.ts +723 -0
  294. package/src/crash/nudge.ts +89 -0
  295. package/src/crash/record-loader.ts +149 -0
  296. package/src/crash/report.ts +551 -0
  297. package/src/crash/sanitize.ts +129 -0
  298. package/src/cursor.ts +36 -10
  299. package/src/customization/import.ts +946 -0
  300. package/src/customization/index.ts +4 -0
  301. package/src/customization/inventory.ts +335 -0
  302. package/src/customization/mutations.ts +141 -0
  303. package/src/customization/types.ts +223 -0
  304. package/src/daemon/control-types.ts +8 -1
  305. package/src/daemon/operator-contract.ts +6 -6
  306. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +31 -6
  307. package/src/defaults/gjc/skills/deep-interview/SKILL.md +11 -22
  308. package/src/defaults/gjc/skills/ralplan/SKILL.md +36 -23
  309. package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
  310. package/src/discovery/claude-hooks.ts +38 -0
  311. package/src/discovery/claude.ts +142 -209
  312. package/src/discovery/codex-hooks.ts +38 -0
  313. package/src/discovery/codex.ts +132 -198
  314. package/src/discovery/helpers.ts +8 -1
  315. package/src/discovery/index.ts +2 -0
  316. package/src/discovery/mcp-compat.ts +234 -0
  317. package/src/discovery/mcp-json.ts +6 -0
  318. package/src/edit/renderer.ts +40 -0
  319. package/src/edit/streaming.ts +4 -2
  320. package/src/exec/bash-executor.ts +24 -20
  321. package/src/export/html/index.ts +51 -2
  322. package/src/extensibility/extensions/loader.ts +9 -1
  323. package/src/extensibility/extensions/runner.ts +17 -4
  324. package/src/extensibility/extensions/types.ts +31 -6
  325. package/src/extensibility/gjc-plugins/constrained-hooks.ts +33 -0
  326. package/src/extensibility/gjc-plugins/installer.ts +9 -5
  327. package/src/extensibility/gjc-plugins/observability.ts +8 -2
  328. package/src/extensibility/gjc-plugins/registry.ts +13 -2
  329. package/src/extensibility/gjc-plugins/runtime-adapters.ts +3 -1
  330. package/src/extensibility/gjc-plugins/schema.ts +222 -39
  331. package/src/extensibility/hooks/loader.ts +154 -10
  332. package/src/extensibility/runtime-skill-discovery.ts +257 -60
  333. package/src/extensibility/skill-management.ts +368 -0
  334. package/src/extensibility/skills.ts +52 -16
  335. package/src/gjc-runtime/deep-interview-runtime.ts +45 -61
  336. package/src/gjc-runtime/launch-worktree.ts +56 -2
  337. package/src/gjc-runtime/linux-proc.ts +7 -1
  338. package/src/gjc-runtime/ralplan-runtime.ts +100 -164
  339. package/src/gjc-runtime/session-state-lock.ts +992 -0
  340. package/src/gjc-runtime/session-state-sidecar.ts +644 -142
  341. package/src/gjc-runtime/state-writer.ts +39 -14
  342. package/src/gjc-runtime/tmux-owner-isolation.ts +5 -4
  343. package/src/gjc-runtime/ultragoal-guard.ts +11 -4
  344. package/src/gjc-runtime/ultragoal-runtime.ts +44 -41
  345. package/src/gjc-runtime/workflow-settings.ts +596 -0
  346. package/src/goals/tools/goal-tool.ts +6 -1
  347. package/src/hooks/events.ts +291 -0
  348. package/src/hooks/native-skill-hook.ts +4 -0
  349. package/src/hooks/normalize.ts +369 -0
  350. package/src/hooks/skill-state.ts +165 -46
  351. package/src/internal-urls/docs-index.generated.ts +41 -32
  352. package/src/main.ts +36 -5
  353. package/src/migrate/mcp-mapper.ts +25 -2
  354. package/src/modes/acp/abort-scope.ts +29 -0
  355. package/src/modes/acp/acp-agent.ts +423 -98
  356. package/src/modes/components/assistant-message.ts +6 -1
  357. package/src/modes/components/chrome.ts +4 -3
  358. package/src/modes/components/customization/customization-dashboard.ts +443 -0
  359. package/src/modes/components/customization/import-wizard.ts +372 -0
  360. package/src/modes/components/customization/index.ts +1 -0
  361. package/src/modes/components/dynamic-theme-text.ts +22 -0
  362. package/src/modes/components/gajae-pet-widget.ts +607 -193
  363. package/src/modes/components/irc-sidebar.ts +11 -0
  364. package/src/modes/components/iterm-pet-transport.ts +585 -0
  365. package/src/modes/components/model-selector.ts +1 -6
  366. package/src/modes/components/oauth-selector.ts +277 -86
  367. package/src/modes/components/pet-capability.ts +35 -31
  368. package/src/modes/components/settings-selector.ts +29 -5
  369. package/src/modes/components/status-line/gh.ts +45 -1
  370. package/src/modes/components/status-line/segments.ts +19 -4
  371. package/src/modes/components/tool-status-header.ts +13 -3
  372. package/src/modes/controllers/command-controller.ts +20 -8
  373. package/src/modes/controllers/extension-ui-controller.ts +56 -257
  374. package/src/modes/controllers/input-controller.ts +10 -0
  375. package/src/modes/controllers/runtime-mcp-command-controller.ts +16 -3
  376. package/src/modes/controllers/selector-controller.ts +238 -77
  377. package/src/modes/controllers/stt-controller.ts +3 -3
  378. package/src/modes/interactive-mode.ts +88 -16
  379. package/src/modes/print-mode.ts +35 -6
  380. package/src/modes/runtime-init.ts +21 -68
  381. package/src/modes/theme/defaults/index.ts +2 -0
  382. package/src/modes/theme/defaults/ouroboros.json +118 -0
  383. package/src/modes/types.ts +1 -0
  384. package/src/modes/utils/injected-user-submission.ts +25 -0
  385. package/src/modes/utils/terminal-bell.ts +15 -1
  386. package/src/prompts/agent-fragments/ralplan-persistence.md +1 -1
  387. package/src/prompts/agent-fragments/restricted-bash.md +1 -1
  388. package/src/prompts/agents/critic.md +1 -1
  389. package/src/prompts/system/rlm-research.md +1 -1
  390. package/src/prompts/system/system-prompt.md +0 -2
  391. package/src/prompts/tools/bash.md +7 -1
  392. package/src/prompts/tools/browser.md +1 -1
  393. package/src/prompts/tools/cron.md +6 -6
  394. package/src/prompts/tools/read.md +0 -2
  395. package/src/prompts/tools/skill-discovery.md +4 -2
  396. package/src/runtime-mcp/client.ts +427 -23
  397. package/src/runtime-mcp/config.ts +37 -5
  398. package/src/runtime-mcp/manager-pool.test.ts +56 -0
  399. package/src/runtime-mcp/manager.ts +52 -2
  400. package/src/runtime-mcp/oauth-discovery.ts +13 -0
  401. package/src/runtime-mcp/oauth-flow.ts +46 -1
  402. package/src/runtime-mcp/pool-key.ts +5 -1
  403. package/src/runtime-mcp/pool.test.ts +9 -0
  404. package/src/runtime-mcp/protocol.test.ts +353 -0
  405. package/src/runtime-mcp/protocol.ts +624 -0
  406. package/src/runtime-mcp/scope-config.ts +78 -0
  407. package/src/runtime-mcp/tool-bridge.ts +44 -10
  408. package/src/runtime-mcp/transports/http.ts +84 -13
  409. package/src/runtime-mcp/types.ts +123 -12
  410. package/src/sdk/acp/adapter.ts +328 -97
  411. package/src/sdk/broker/broker.ts +160 -741
  412. package/src/sdk/broker/ensure.ts +9 -1
  413. package/src/sdk/broker/lifecycle.ts +510 -116
  414. package/src/sdk/broker/operation-receipt-ledger.ts +11 -2
  415. package/src/sdk/broker/process-incarnation.ts +19 -0
  416. package/src/sdk/broker/session-index.ts +516 -117
  417. package/src/sdk/broker/startup-failure.ts +28 -5
  418. package/src/sdk/broker/transport.ts +1 -13
  419. package/src/sdk/bus/chat-daemon-cli.ts +4 -2
  420. package/src/sdk/bus/chat-daemon-control.ts +67 -6
  421. package/src/sdk/bus/chat-daemon-runtime.ts +183 -859
  422. package/src/sdk/bus/config.ts +13 -0
  423. package/src/sdk/bus/conversation-store.ts +59 -171
  424. package/src/sdk/bus/daemon-paths.ts +20 -0
  425. package/src/sdk/bus/discord-conversation.ts +2 -0
  426. package/src/sdk/bus/discord-daemon.ts +524 -126
  427. package/src/sdk/bus/discord-live-provider.ts +206 -79
  428. package/src/sdk/bus/existing-thread-readiness.ts +4 -97
  429. package/src/sdk/bus/inbound-reaction-ordering.ts +122 -0
  430. package/src/sdk/bus/index.ts +2480 -456
  431. package/src/sdk/bus/kind-aware-reconciliation.ts +204 -34
  432. package/src/sdk/bus/lifecycle-commands.ts +2 -2
  433. package/src/sdk/bus/managed-daemon.ts +2 -145
  434. package/src/sdk/bus/notification-service.ts +196 -0
  435. package/src/sdk/bus/operator-runtime.ts +1 -1
  436. package/src/sdk/bus/prompt-reconciliation.ts +24 -15
  437. package/src/sdk/bus/reconciliation-store.ts +553 -24
  438. package/src/sdk/bus/session-control.ts +49 -3
  439. package/src/sdk/bus/slack-conversation.ts +4 -0
  440. package/src/sdk/bus/slack-daemon.ts +733 -134
  441. package/src/sdk/bus/slack-live-provider.ts +65 -15
  442. package/src/sdk/bus/slack-provider.ts +4 -0
  443. package/src/sdk/bus/slack-thread-binding.ts +9 -104
  444. package/src/sdk/bus/telegram-adoption-intent.ts +299 -209
  445. package/src/sdk/bus/telegram-daemon-cli.ts +194 -7
  446. package/src/sdk/bus/telegram-daemon-contract.ts +265 -19
  447. package/src/sdk/bus/telegram-daemon-control.ts +3 -13
  448. package/src/sdk/bus/telegram-daemon-orphan-reap.ts +498 -0
  449. package/src/sdk/bus/telegram-daemon-owner-registry.ts +176 -0
  450. package/src/sdk/bus/telegram-daemon.ts +2552 -2280
  451. package/src/sdk/bus/telegram-reference.ts +1 -226
  452. package/src/sdk/bus/telegram-setup.ts +2 -2
  453. package/src/sdk/bus/threaded-render.ts +1 -0
  454. package/src/sdk/bus/topic-registry.ts +279 -146
  455. package/src/sdk/cli/rows.ts +2 -35
  456. package/src/sdk/cli/session-cli.ts +776 -700
  457. package/src/sdk/client/client.ts +892 -1
  458. package/src/sdk/host/control/dispatch.ts +93 -58
  459. package/src/sdk/host/control/index.ts +1 -1
  460. package/src/sdk/host/control/operations.ts +18 -10
  461. package/src/sdk/host/control/runtime-gate.ts +40 -0
  462. package/src/sdk/host/host.ts +63 -12
  463. package/src/sdk/host/query/handlers.ts +66 -7
  464. package/src/sdk/host/reverse-leases.ts +2 -2
  465. package/src/sdk/host/sdk-surface-parity.test.ts +1 -1
  466. package/src/sdk/host/session-runtime.test.ts +2787 -34
  467. package/src/sdk/host/session-runtime.ts +1489 -101
  468. package/src/sdk/host/surface-policy.ts +12 -8
  469. package/src/sdk/host/types.ts +1 -1
  470. package/src/sdk/host/websocket-transport.lifecycle.test.ts +31 -59
  471. package/src/sdk/host/websocket-transport.ts +85 -50
  472. package/src/sdk/index.ts +2 -1
  473. package/src/sdk/lifecycle/broker-client.ts +53 -0
  474. package/src/sdk/lifecycle/client.ts +234 -0
  475. package/src/sdk/lifecycle/index.ts +3 -0
  476. package/src/sdk/{bus/recent-activity.ts → lifecycle/recent-sessions.ts} +5 -2
  477. package/src/sdk/lifecycle/service.ts +720 -0
  478. package/src/sdk/mcp/server.ts +226 -188
  479. package/src/sdk/prompt-deadline-lease.ts +55 -0
  480. package/src/sdk/prompt-deadline-manager.ts +148 -0
  481. package/src/sdk/prompt-status.ts +11 -3
  482. package/src/sdk/protocol/operation-inventory.generated.json +272 -129
  483. package/src/sdk/protocol/operation-registry.ts +71 -8
  484. package/src/sdk/receipt-state.ts +43 -0
  485. package/src/sdk/reconciliation-extensions.ts +14 -0
  486. package/src/sdk/router/index.ts +1 -0
  487. package/src/sdk/router/session-router.ts +1658 -0
  488. package/src/sdk/session-list.ts +93 -0
  489. package/src/sdk/session-reconnect.ts +45 -1
  490. package/src/sdk/session.ts +716 -120
  491. package/src/sdk/transport/serve-cli.ts +18 -34
  492. package/src/session/account-inventory.ts +603 -0
  493. package/src/session/agent-session.ts +2873 -559
  494. package/src/session/agent-storage.ts +35 -0
  495. package/src/session/blob-store.ts +32 -1
  496. package/src/session/coordinator-tool-label.ts +40 -0
  497. package/src/session/internal/managed-session-scope.ts +4 -0
  498. package/src/session/internal/managed-session-storage.ts +199 -31
  499. package/src/session/messages.ts +1 -1
  500. package/src/session/secure-token-file.ts +80 -0
  501. package/src/session/session-manager.ts +757 -57
  502. package/src/session/session-storage.ts +25 -16
  503. package/src/session/startup-auth-config.ts +297 -0
  504. package/src/session/terminal-abort.ts +1253 -0
  505. package/src/session/yield-queue.ts +57 -15
  506. package/src/session-import/claude.ts +334 -0
  507. package/src/session-import/codex.ts +1033 -0
  508. package/src/session-import/command.ts +77 -0
  509. package/src/session-import/detect.ts +133 -0
  510. package/src/session-import/index.ts +7 -0
  511. package/src/session-import/provider-codex.ts +327 -0
  512. package/src/session-import/provider-service.ts +457 -0
  513. package/src/session-import/redact.ts +128 -0
  514. package/src/session-import/service.ts +1264 -0
  515. package/src/session-import/types.ts +148 -0
  516. package/src/setup/paseo/check.ts +213 -0
  517. package/src/setup/paseo/install-saga.ts +293 -0
  518. package/src/setup/paseo/json-publisher.ts +263 -0
  519. package/src/setup/paseo/orchestration-preferences.ts +86 -0
  520. package/src/setup/paseo/paseo-ownership.ts +224 -0
  521. package/src/setup/paseo/paseo-setup.ts +253 -0
  522. package/src/setup/paseo/provider-config.ts +139 -0
  523. package/src/setup/paseo/remove.ts +183 -0
  524. package/src/setup/paseo/result-types.ts +79 -0
  525. package/src/setup/paseo/setup-deps.ts +175 -0
  526. package/src/setup/paseo/skills-bridge.ts +260 -0
  527. package/src/skill-state/active-state.ts +21 -11
  528. package/src/slash-commands/acp-builtins.ts +9 -1
  529. package/src/slash-commands/builtin-registry.ts +117 -19
  530. package/src/slash-commands/helpers/credential-switch.ts +143 -0
  531. package/src/slash-commands/helpers/mcp.ts +9 -3
  532. package/src/slash-commands/helpers/usage-report.ts +61 -56
  533. package/src/slash-commands/types.ts +7 -2
  534. package/src/task/executor.ts +30 -11
  535. package/src/task/index.ts +66 -7
  536. package/src/task/render.ts +23 -9
  537. package/src/tools/ask-answer-registry.ts +23 -7
  538. package/src/tools/ask.ts +8 -4
  539. package/src/tools/bash-sleep-advisory.ts +115 -0
  540. package/src/tools/bash.ts +98 -18
  541. package/src/tools/browser/attach.ts +71 -3
  542. package/src/tools/browser/launch.ts +86 -13
  543. package/src/tools/browser/profile-discovery.ts +57 -7
  544. package/src/tools/browser/render.ts +8 -1
  545. package/src/tools/browser.ts +130 -21
  546. package/src/tools/computer.enforcement.test.ts +1 -1
  547. package/src/tools/computer.ts +3 -2
  548. package/src/tools/cron.ts +12 -1
  549. package/src/tools/image-gen.ts +349 -142
  550. package/src/tools/index.ts +8 -0
  551. package/src/tools/job.ts +33 -6
  552. package/src/tools/monitor.ts +41 -2
  553. package/src/tools/skill-discovery.ts +21 -29
  554. package/src/tools/subagent.ts +142 -24
  555. package/src/tools/todo-contract.ts +55 -3
  556. package/src/tools/todo-write.ts +4 -3
  557. package/src/tools/tool-catalog.generated.ts +6 -6
  558. package/src/tools/ultragoal-ask-guard.ts +10 -3
  559. package/src/utils/herdr-pane.ts +345 -0
  560. package/src/utils/title-generator.ts +2 -0
  561. package/src/web/scrapers/index.ts +6 -4
  562. package/dist/types/cli/malloc-env-guard.test.d.ts +0 -1
  563. package/dist/types/defaults/gjc-defaults.test.d.ts +0 -1
  564. package/dist/types/memory-backend/lazy-loading.test.d.ts +0 -1
  565. package/dist/types/runtime/boot-ordering.test.d.ts +0 -1
  566. package/dist/types/runtime/lazy-service.test.d.ts +0 -1
  567. package/dist/types/runtime/network-prewarm-service.test.d.ts +0 -1
  568. package/dist/types/runtime/workspace-tree-service.test.d.ts +0 -1
  569. package/dist/types/runtime-mcp/config.test.d.ts +0 -1
  570. package/dist/types/runtime-mcp/http.test.d.ts +0 -1
  571. package/dist/types/runtime-mcp/manager-pool.test.d.ts +0 -1
  572. package/dist/types/runtime-mcp/pool-key.test.d.ts +0 -1
  573. package/dist/types/runtime-mcp/pool.test.d.ts +0 -1
  574. package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +0 -117
  575. package/dist/types/sdk/bus/lifecycle-orchestrator.d.ts +0 -141
  576. package/dist/types/sdk/bus/telegram-cli.d.ts +0 -31
  577. package/dist/types/sdk/elevation/allowlist.d.ts +0 -20
  578. package/dist/types/sdk/elevation/audit.d.ts +0 -93
  579. package/dist/types/sdk/elevation/capability.d.ts +0 -3
  580. package/dist/types/sdk/elevation/digest.d.ts +0 -72
  581. package/dist/types/sdk/elevation/dispatch-receipt.d.ts +0 -85
  582. package/dist/types/sdk/elevation/grant-ledger.d.ts +0 -163
  583. package/dist/types/sdk/elevation/owner.d.ts +0 -48
  584. package/dist/types/sdk/host/import-graph.test.d.ts +0 -1
  585. package/dist/types/sdk/host/sdk-surface-parity.test.d.ts +0 -1
  586. package/dist/types/sdk/host/session-runtime.test.d.ts +0 -1
  587. package/dist/types/sdk/host/websocket-transport.lifecycle.test.d.ts +0 -1
  588. package/dist/types/session/auth-broker-config.d.ts +0 -13
  589. package/dist/types/session/heap-eviction-artifacts.test.d.ts +0 -1
  590. package/dist/types/skills/skills.test.d.ts +0 -1
  591. package/dist/types/slash-commands/notify-command.test.d.ts +0 -1
  592. package/dist/types/task/token-log.test.d.ts +0 -1
  593. package/dist/types/tools/computer.enforcement.test.d.ts +0 -1
  594. package/dist/types/tools/descriptors.test.d.ts +0 -1
  595. package/scripts/g005-daemon-smoke.ts +0 -180
  596. package/scripts/g011-daemon-path-smoke.ts +0 -153
  597. package/src/sdk/bus/lifecycle-control-runtime.ts +0 -1733
  598. package/src/sdk/bus/lifecycle-orchestrator.ts +0 -489
  599. package/src/sdk/bus/telegram-cli.ts +0 -212
  600. package/src/sdk/elevation/allowlist.ts +0 -54
  601. package/src/sdk/elevation/audit.ts +0 -208
  602. package/src/sdk/elevation/capability.ts +0 -41
  603. package/src/sdk/elevation/digest.ts +0 -129
  604. package/src/sdk/elevation/dispatch-receipt.ts +0 -184
  605. package/src/sdk/elevation/grant-ledger.ts +0 -1142
  606. package/src/sdk/elevation/owner.ts +0 -109
  607. package/src/session/auth-broker-config.ts +0 -109
  608. /package/dist/types/{ai-core-import-gate.test.d.ts → discovery/claude-hooks.d.ts} +0 -0
  609. /package/dist/types/{cli/fixture-report.test.d.ts → discovery/codex-hooks.d.ts} +0 -0
  610. /package/dist/types/sdk/{bus/recent-activity.d.ts → lifecycle/recent-sessions.d.ts} +0 -0
package/src/tools/bash.ts CHANGED
@@ -30,6 +30,11 @@ import {
30
30
  truncateHeadBytes,
31
31
  truncateTailBytes,
32
32
  } from "../session/streaming-output";
33
+ import {
34
+ lookupOwnedRegistration,
35
+ registerOwnedIfLineaged,
36
+ unregisterOwnedRegistration,
37
+ } from "../session/terminal-abort";
33
38
 
34
39
  import { renderStatusLine } from "../tui";
35
40
  import { CachedOutputBlock, getOutputBlockContentWidth } from "../tui/output-block";
@@ -42,6 +47,7 @@ import { type BashInteractiveResult, runInteractiveBashPty } from "./bash-intera
42
47
  import { checkBashInterception } from "./bash-interceptor";
43
48
  import { canUseInteractiveBashPty } from "./bash-pty-selection";
44
49
  import { expandInternalUrls, type InternalUrlExpansionOptions } from "./bash-skill-urls";
50
+ import { longSleepAdvisory } from "./bash-sleep-advisory";
45
51
  import { checkComposerBashPolicy } from "./composer-bash-policy";
46
52
  import {
47
53
  formatArtifactReference,
@@ -598,6 +604,23 @@ function formatTimeoutClampNotice(requestedTimeoutSec: number, effectiveTimeoutS
598
604
  *
599
605
  * Executes bash commands with optional timeout and working directory.
600
606
  */
607
+ /** Remove the owned registration of a FOREGROUND bash job whose delivery was
608
+ * synchronously acknowledged: the tuple is settled and must not occupy the
609
+ * registry, otherwise old retained policies are treated as occupied and the
610
+ * tombstone FIFO fallback can evict a genuinely live work's policy (review
611
+ * thread P2). */
612
+ function unregisterForegroundOwnedBash(
613
+ manager: { getJob?(id: string): { generation?: string } | undefined },
614
+ jobId: string,
615
+ endpointId?: string,
616
+ ): void {
617
+ const generation = manager.getJob?.(jobId)?.generation;
618
+ if (!generation) return;
619
+ // The endpoint disambiguates concurrent sessions' same job ids (review P1).
620
+ const registration = lookupOwnedRegistration(jobId, generation, endpointId);
621
+ if (registration) unregisterOwnedRegistration(registration);
622
+ }
623
+
601
624
  export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
602
625
  readonly name = "bash";
603
626
  readonly label = "Bash";
@@ -751,8 +774,10 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
751
774
  resolvedEnv?: Record<string, string>;
752
775
  onUpdate?: AgentToolUpdateCallback<BashToolDetails>;
753
776
  startBackgrounded: boolean;
777
+ /** Immutable attempt-scoped tool call id, when executed via a tool call. */
778
+ toolCallId?: string;
754
779
  }): ManagedBashJobHandle {
755
- const manager = AsyncJobManager.instance();
780
+ const manager = this.#resolveOwnedJobManager();
756
781
  if (!manager) {
757
782
  throw new ToolError("Background job manager unavailable for this session.");
758
783
  }
@@ -840,6 +865,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
840
865
  },
841
866
  },
842
867
  );
868
+ registerOwnedIfLineaged(manager, options.toolCallId, jobId, this.session.getSessionId?.() ?? undefined);
843
869
 
844
870
  return {
845
871
  jobId,
@@ -852,6 +878,24 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
852
878
  };
853
879
  }
854
880
 
881
+ /**
882
+ * The session's ENDPOINT-owned AsyncJobManager, falling back to the
883
+ * process-global instance. Concurrent top-level sessions each register
884
+ * their manager under their endpoint (sdk/session.ts), so a job created
885
+ * by THIS session must be stored in THIS session's manager — otherwise a
886
+ * Bash launched by session A lands in the last-created session B's
887
+ * manager while registering as A-owned, an A scope:"owned" abort then
888
+ * consults A's endpoint manager and cannot cancel the actual job, and a
889
+ * later missing-job settlement can retire the tuple while the job keeps
890
+ * running (review thread P1).
891
+ */
892
+ #resolveOwnedJobManager(): AsyncJobManager | undefined {
893
+ const endpointId = this.session.getSessionId?.() ?? undefined;
894
+ return (
895
+ this.session.getAsyncJobManager?.() ?? AsyncJobManager.forEndpoint(endpointId) ?? AsyncJobManager.instance()
896
+ );
897
+ }
898
+
855
899
  async #waitForManagedBashJob(
856
900
  job: ManagedBashJobHandle,
857
901
  thresholdMs: number,
@@ -1024,12 +1068,28 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1024
1068
  ),
1025
1069
  )
1026
1070
  : undefined;
1071
+ // Spawned workflow commands must resolve the SESSION's agent
1072
+ // profile: the child's getAgentDir() reads GJC_CODING_AGENT_DIR at
1073
+ // module load. Injected per-command (session-scoped), never
1074
+ // mutating the host process; an explicit tool-call env wins. The
1075
+ // session's REQUESTED directory (getSessionAgentDir) takes
1076
+ // precedence over the global Settings singleton, which may belong
1077
+ // to an earlier session.
1078
+ const sessionAgentDir = this.session.getSessionAgentDir?.() ?? this.session.settings?.getAgentDir?.();
1079
+ // An EXPLICIT tool-call env that supplies either supported spelling of
1080
+ // the agent-directory override wins over the session injection: the
1081
+ // child's getAgentDir() prefers GJC_CODING_AGENT_DIR, so injecting it
1082
+ // while the caller only set the legacy PI_CODING_AGENT_DIR alias would
1083
+ // silently ignore the caller's override.
1084
+ const explicitAgentDirOverride =
1085
+ expandedEnv?.GJC_CODING_AGENT_DIR !== undefined || expandedEnv?.PI_CODING_AGENT_DIR !== undefined;
1027
1086
  const resolvedEnv = {
1028
1087
  ...buildGjcRuntimeSessionEnv({
1029
1088
  sessionFile: null,
1030
1089
  sessionId: this.session.getSessionId?.(),
1031
1090
  cwd: this.session.cwd,
1032
1091
  }),
1092
+ ...(sessionAgentDir && !explicitAgentDirOverride ? { GJC_CODING_AGENT_DIR: sessionAgentDir } : {}),
1033
1093
  ...expandedEnv,
1034
1094
  ...(this.session.bashRestrictionProfile === "read-only" ? READ_ONLY_BASH_ENV : {}),
1035
1095
  ...(allowedPrefixes && allowedPrefixes.length > 0 ? { [GJC_RESTRICTED_ROLE_AGENT_BASH_ENV]: "1" } : {}),
@@ -1059,6 +1119,8 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1059
1119
  const notices: string[] = [];
1060
1120
  const timeoutClampNotice = formatTimeoutClampNotice(requestedTimeoutSec, timeoutSec);
1061
1121
  if (timeoutClampNotice) notices.push(timeoutClampNotice);
1122
+ const sleepAdvisory = longSleepAdvisory(command, timeoutSec);
1123
+ if (sleepAdvisory) notices.push(sleepAdvisory);
1062
1124
 
1063
1125
  return { command, commandCwd, resolvedEnv, requestedTimeoutSec, timeoutSec, timeoutMs, notices };
1064
1126
  }
@@ -1078,12 +1140,13 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1078
1140
  ownerId?: string;
1079
1141
  label?: string;
1080
1142
  ctx?: AgentToolContext;
1143
+ toolCallId?: string;
1081
1144
  onRawLine?: (line: string, jobId: string) => void;
1082
1145
  shouldAcceptRawLine?: (jobId: string) => boolean;
1083
1146
  lifecycle?: import("../async").AsyncJobLifecycleCleanup;
1084
1147
  } = {},
1085
1148
  ): Promise<{ jobId: string; label: string; commandCwd: string }> {
1086
- const manager = AsyncJobManager.instance();
1149
+ const manager = this.#resolveOwnedJobManager();
1087
1150
  if (!manager) {
1088
1151
  throw new ToolError("Async job manager unavailable for this session.");
1089
1152
  }
@@ -1181,12 +1244,16 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1181
1244
  },
1182
1245
  { ownerId, metadata: { monitor: true }, lifecycle: opts.lifecycle },
1183
1246
  );
1247
+ // Monitor jobs are exact owned background work of the turn that started
1248
+ // them: register the five-tuple so scope:"owned" terminal abort stops the
1249
+ // monitor too (review thread P2).
1250
+ registerOwnedIfLineaged(manager, opts.toolCallId, jobId, this.session.getSessionId?.() ?? undefined);
1184
1251
  currentJobId = jobId;
1185
1252
  return { jobId, label, commandCwd: prepared.commandCwd };
1186
1253
  }
1187
1254
 
1188
1255
  async execute(
1189
- _toolCallId: string,
1256
+ toolCallId: string,
1190
1257
  {
1191
1258
  command: rawCommand,
1192
1259
  env: rawEnv,
@@ -1222,7 +1289,11 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1222
1289
  } = prepared;
1223
1290
 
1224
1291
  if (asyncRequested) {
1225
- if (!AsyncJobManager.instance()) {
1292
+ // Availability is endpoint-first: a concurrent top-level session
1293
+ // that was the process-global instance may have been disposed,
1294
+ // clearing instance() while THIS session's manager stays
1295
+ // registered by endpoint (review thread P1).
1296
+ if (!this.#resolveOwnedJobManager()) {
1226
1297
  throw new ToolError("Async job manager unavailable for this session.");
1227
1298
  }
1228
1299
  const job = this.#startManagedBashJob({
@@ -1236,6 +1307,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1236
1307
  resolvedEnv,
1237
1308
  onUpdate,
1238
1309
  startBackgrounded: true,
1310
+ toolCallId,
1239
1311
  });
1240
1312
  return this.#buildBackgroundStartResult(job.jobId, job.label, "", timeoutSec, {
1241
1313
  requestedTimeoutSec,
@@ -1249,11 +1321,15 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1249
1321
  this.session.bashRestrictionProfile === "read-only" ? undefined : this.session.getClientBridge?.();
1250
1322
  const clientTerminalActive = Boolean(clientBridge?.capabilities.terminal && clientBridge.createTerminal && !pty);
1251
1323
 
1252
- const autoBgManager = AsyncJobManager.instance();
1253
1324
  // Run non-PTY bash through the managed job path so Ctrl+B-twice fold-on-demand works
1254
1325
  // even when auto-background is disabled. When a client terminal will handle the
1255
1326
  // command, keep the existing bridge path unless auto-background is enabled.
1256
- if (!pty && autoBgManager && (this.#autoBackgroundEnabled || !clientTerminalActive)) {
1327
+ // The manager is resolved ONCE from the session's endpoint (same instance the
1328
+ // job was created in) and reused for creation, acknowledgement, cancellation,
1329
+ // and unregistering — the process-global instance may belong to a different
1330
+ // concurrent top-level session (review thread P1).
1331
+ const ownedManager = this.#resolveOwnedJobManager();
1332
+ if (!pty && ownedManager && (this.#autoBackgroundEnabled || !clientTerminalActive)) {
1257
1333
  // With auto-background off, wait past the command's own timeout so the job only
1258
1334
  // leaves the foreground on an explicit Ctrl+B fold, never on an auto-background timer.
1259
1335
  const autoBackgroundWaitMs = this.#autoBackgroundEnabled
@@ -1271,6 +1347,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1271
1347
  resolvedEnv,
1272
1348
  onUpdate,
1273
1349
  startBackgrounded,
1350
+ toolCallId,
1274
1351
  });
1275
1352
  if (startBackgrounded) {
1276
1353
  return this.#buildBackgroundStartResult(job.jobId, job.label, "", timeoutSec, {
@@ -1295,17 +1372,20 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1295
1372
  unregisterBackgroundRequest?.();
1296
1373
  }
1297
1374
  if (waitResult.kind === "completed") {
1298
- autoBgManager.acknowledgeDeliveries([job.jobId]);
1375
+ ownedManager.acknowledgeDeliveries([job.jobId]);
1376
+ unregisterForegroundOwnedBash(ownedManager, job.jobId, this.session.getSessionId?.() ?? "local");
1299
1377
  return waitResult.result;
1300
1378
  }
1301
1379
  if (waitResult.kind === "failed") {
1302
- autoBgManager.acknowledgeDeliveries([job.jobId]);
1380
+ ownedManager.acknowledgeDeliveries([job.jobId]);
1381
+ unregisterForegroundOwnedBash(ownedManager, job.jobId, this.session.getSessionId?.() ?? "local");
1303
1382
  throw waitResult.error;
1304
1383
  }
1305
1384
  if (waitResult.kind === "aborted") {
1306
- autoBgManager.cancel(job.jobId);
1385
+ ownedManager.cancel(job.jobId);
1307
1386
  const terminal = await job.completion;
1308
- autoBgManager.acknowledgeDeliveries([job.jobId]);
1387
+ ownedManager.acknowledgeDeliveries([job.jobId]);
1388
+ unregisterForegroundOwnedBash(ownedManager, job.jobId, this.session.getSessionId?.() ?? "local");
1309
1389
  if (terminal.kind === "failed") {
1310
1390
  throw new ToolAbortError(
1311
1391
  formatManagedAbortFailure(terminal.error, terminal.result, job.getLatestText()),
@@ -1585,20 +1665,20 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
1585
1665
  disableShellSnapshot: this.session.bashRestrictionProfile === "read-only",
1586
1666
  });
1587
1667
  if (result.cancelled) {
1588
- const failureText = formatBashFailureMessage(
1589
- result,
1590
- normalizeResultOutput(result) || "Command aborted",
1591
- signal?.aborted ? "Command aborted" : undefined,
1592
- );
1668
+ const noticeSuffix = pendingNotices.length > 0 ? `\n\n${pendingNotices.join("\n")}` : "";
1669
+ const baseCancelledText = normalizeResultOutput(result) || "Command aborted";
1593
1670
  if (signal?.aborted) {
1594
- throw new ToolAbortError(failureText);
1671
+ throw new ToolAbortError(formatBashFailureMessage(result, baseCancelledText, "Command aborted"));
1595
1672
  }
1596
- throw new ToolError(failureText);
1673
+ const failureText = `${baseCancelledText}${noticeSuffix}`;
1674
+ throw new ToolError(formatBashFailureMessage(result, failureText));
1597
1675
  }
1598
1676
  if (isInteractiveResult(result) && result.timedOut) {
1599
1677
  const timeoutMessage = `Command timed out after ${timeoutSec} seconds`;
1600
1678
  const output = normalizeResultOutput(result);
1601
- const failureText = output ? `${output}\n\n${timeoutMessage}` : timeoutMessage;
1679
+ const noticeSuffix = pendingNotices.length > 0 ? `\n\n${pendingNotices.join("\n")}` : "";
1680
+ const baseText = output ? `${output}\n\n${timeoutMessage}` : timeoutMessage;
1681
+ const failureText = `${baseText}${noticeSuffix}`;
1602
1682
  throw new ToolError(formatBashFailureMessage(result, failureText, timeoutMessage));
1603
1683
  }
1604
1684
  return this.#buildCompletedResult(result, timeoutSec, {
@@ -1,8 +1,10 @@
1
+ import * as fs from "node:fs/promises";
1
2
  import * as net from "node:net";
2
3
  import * as path from "node:path";
3
4
  import { nativeProcessBindings } from "@gajae-code/utils/native-process";
4
5
  import type { Browser, Page } from "puppeteer-core";
5
6
  import { ToolError, throwIfAborted } from "../tool-errors";
7
+ import { isChromeProfileExecutable } from "./launch";
6
8
 
7
9
  const ATTACH_TARGET_SKIP_PATTERN =
8
10
  /request[\s_-]?handler|devtools|background[\s_-]?(?:page|host)|service[\s_-]?worker/i;
@@ -133,8 +135,10 @@ async function probeCdpAt(port: number, signal?: AbortSignal): Promise<boolean>
133
135
  try {
134
136
  const res = await fetch(`http://127.0.0.1:${port}/json/version`, { signal: probeSignal });
135
137
  await res.body?.cancel();
138
+ throwIfAborted(signal);
136
139
  return res.ok;
137
140
  } catch {
141
+ throwIfAborted(signal);
138
142
  return false;
139
143
  }
140
144
  }
@@ -181,6 +185,7 @@ export async function findReusableCdp(
181
185
  if (await probeCdpAt(port, signal)) {
182
186
  return { cdpUrl: `http://127.0.0.1:${port}`, pid: proc.pid };
183
187
  }
188
+ throwIfAborted(signal);
184
189
  }
185
190
  return null;
186
191
  }
@@ -196,10 +201,64 @@ export async function findRunningChromeProfile(
196
201
  profile: { userDataDir: string; profileDirectory: string },
197
202
  signal?: AbortSignal,
198
203
  ): Promise<RunningChromeProfile | null> {
199
- const candidates = nativeProcessBindings()
200
- .Process.fromPath(exe)
201
- .filter(p => p.status() === nativeProcessBindings().ProcessStatus.Running);
204
+ return findRunningChromeProfileWithOptions(exe, profile, signal, {});
205
+ }
206
+
207
+ interface ProfileProcessScanOptions {
208
+ platform?: NodeJS.Platform;
209
+ linuxPids?: readonly number[];
210
+ linuxExecutablePaths?: ReadonlyMap<number, string>;
211
+ signal?: AbortSignal;
212
+ }
213
+
214
+ async function liveLinuxPids(): Promise<number[]> {
215
+ try {
216
+ const entries = await fs.readdir("/proc", { withFileTypes: true });
217
+ return entries
218
+ .filter(entry => entry.isDirectory() && /^\d+$/.test(entry.name))
219
+ .map(entry => Number.parseInt(entry.name, 10));
220
+ } catch {
221
+ return [];
222
+ }
223
+ }
224
+
225
+ async function linuxExecutablePath(pid: number, options: ProfileProcessScanOptions): Promise<string | null> {
226
+ const injected = options.linuxExecutablePaths?.get(pid);
227
+ if (injected) return injected;
228
+ try {
229
+ return await fs.readlink(`/proc/${pid}/exe`);
230
+ } catch {
231
+ return null;
232
+ }
233
+ }
234
+
235
+ async function findRunningChromeProfileWithOptions(
236
+ exe: string,
237
+ profile: { userDataDir: string; profileDirectory: string },
238
+ signal: AbortSignal | undefined,
239
+ options: ProfileProcessScanOptions,
240
+ ): Promise<RunningChromeProfile | null> {
241
+ const bindings = nativeProcessBindings();
242
+ const candidates = bindings.Process.fromPath(exe).filter(p => p.status() === bindings.ProcessStatus.Running);
243
+ const seenPids = new Set(candidates.map(candidate => candidate.pid));
244
+ if ((options.platform ?? process.platform) === "linux" && candidates.length === 0) {
245
+ throwIfAborted(signal);
246
+ const linuxPids = options.linuxPids ?? (await liveLinuxPids());
247
+ throwIfAborted(signal);
248
+ for (const pid of linuxPids) {
249
+ throwIfAborted(signal);
250
+ if (seenPids.has(pid)) continue;
251
+ const candidate = bindings.Process.fromPid(pid);
252
+ if (!candidate || candidate.status() !== bindings.ProcessStatus.Running) continue;
253
+ const executablePath = await linuxExecutablePath(pid, options);
254
+ throwIfAborted(signal);
255
+ if (!executablePath || !isChromeProfileExecutable(executablePath)) continue;
256
+ seenPids.add(pid);
257
+ candidates.push(candidate);
258
+ }
259
+ }
202
260
  for (const proc of candidates) {
261
+ throwIfAborted(signal);
203
262
  let args: string[];
204
263
  try {
205
264
  args = proc.args();
@@ -216,12 +275,21 @@ export async function findRunningChromeProfile(
216
275
  if (await probeCdpAt(port, signal)) {
217
276
  return { pid: proc.pid, cdpUrl: `http://127.0.0.1:${port}` };
218
277
  }
278
+ throwIfAborted(signal);
219
279
  }
220
280
  return { pid: proc.pid, cdpUrl: null };
221
281
  }
222
282
  return null;
223
283
  }
224
284
 
285
+ export function findRunningChromeProfileForTest(
286
+ exe: string,
287
+ profile: { userDataDir: string; profileDirectory: string },
288
+ options: ProfileProcessScanOptions,
289
+ ): Promise<RunningChromeProfile | null> {
290
+ return findRunningChromeProfileWithOptions(exe, profile, options.signal, options);
291
+ }
292
+
225
293
  /**
226
294
  * Pick the best page target on an attached browser. Without a matcher, prefer
227
295
  * a page that doesn't look like a helper window (devtools, request handler,
@@ -108,12 +108,18 @@ export function resolveBrowserEnvOverridesForTest(): {
108
108
  proxy: string | undefined;
109
109
  proxyBypassLoopback: boolean;
110
110
  ignoreCertErrors: boolean;
111
+ programFiles: string | undefined;
112
+ programFilesX86: string | undefined;
113
+ localAppData: string | undefined;
111
114
  } {
112
115
  return {
113
116
  executablePath: trustedBrowserEnv("PUPPETEER_EXECUTABLE_PATH"),
114
117
  proxy: trustedBrowserEnv("PUPPETEER_PROXY"),
115
118
  proxyBypassLoopback: browserLaunchFlagEnabled("PUPPETEER_PROXY_BYPASS_LOOPBACK"),
116
119
  ignoreCertErrors: browserLaunchFlagEnabled("PUPPETEER_PROXY_IGNORE_CERT_ERRORS"),
120
+ programFiles: trustedBrowserEnv("ProgramFiles"),
121
+ programFilesX86: trustedBrowserEnv("ProgramFiles(x86)"),
122
+ localAppData: trustedBrowserEnv("LOCALAPPDATA"),
117
123
  };
118
124
  }
119
125
 
@@ -208,7 +214,16 @@ function systemChromiumCandidates(): string[] {
208
214
  break;
209
215
  }
210
216
  case "linux": {
211
- const names = ["google-chrome-stable", "google-chrome", "chromium", "chromium-browser", "chrome"];
217
+ const names = [
218
+ "google-chrome-stable",
219
+ "google-chrome",
220
+ "google-chrome-beta",
221
+ "google-chrome-unstable",
222
+ "google-chrome-canary",
223
+ "chromium",
224
+ "chromium-browser",
225
+ "chrome",
226
+ ];
212
227
  for (const name of names) {
213
228
  const found = $which(name);
214
229
  if (found) candidates.push(found);
@@ -216,6 +231,9 @@ function systemChromiumCandidates(): string[] {
216
231
  candidates.push(
217
232
  "/usr/bin/google-chrome-stable",
218
233
  "/usr/bin/google-chrome",
234
+ "/usr/bin/google-chrome-beta",
235
+ "/usr/bin/google-chrome-unstable",
236
+ "/usr/bin/google-chrome-canary",
219
237
  "/usr/bin/chromium",
220
238
  "/usr/bin/chromium-browser",
221
239
  "/snap/bin/chromium",
@@ -232,13 +250,20 @@ function systemChromiumCandidates(): string[] {
232
250
  break;
233
251
  }
234
252
  case "win32": {
235
- const programFiles = process.env.ProgramFiles ?? "C:\\Program Files";
236
- const programFilesX86 = process.env["ProgramFiles(x86)"] ?? "C:\\Program Files (x86)";
237
- const localAppData = process.env.LOCALAPPDATA ?? path.join(home, "AppData\\Local");
253
+ const programFiles = trustedBrowserEnv("ProgramFiles") ?? "C:\\Program Files";
254
+ const programFilesX86 = trustedBrowserEnv("ProgramFiles(x86)") ?? "C:\\Program Files (x86)";
255
+ const localAppData = trustedBrowserEnv("LOCALAPPDATA") ?? path.join(home, "AppData\\Local");
238
256
  candidates.push(
239
257
  path.join(programFiles, "Google\\Chrome\\Application\\chrome.exe"),
240
258
  path.join(programFilesX86, "Google\\Chrome\\Application\\chrome.exe"),
241
259
  path.join(localAppData, "Google\\Chrome\\Application\\chrome.exe"),
260
+ path.join(programFiles, "Google\\Chrome Beta\\Application\\chrome.exe"),
261
+ path.join(programFilesX86, "Google\\Chrome Beta\\Application\\chrome.exe"),
262
+ path.join(localAppData, "Google\\Chrome Beta\\Application\\chrome.exe"),
263
+ path.join(programFiles, "Google\\Chrome Dev\\Application\\chrome.exe"),
264
+ path.join(programFilesX86, "Google\\Chrome Dev\\Application\\chrome.exe"),
265
+ path.join(localAppData, "Google\\Chrome Dev\\Application\\chrome.exe"),
266
+ path.join(localAppData, "Google\\Chrome SxS\\Application\\chrome.exe"),
242
267
  path.join(programFiles, "Chromium\\Application\\chrome.exe"),
243
268
  path.join(localAppData, "Chromium\\Application\\chrome.exe"),
244
269
  path.join(programFiles, "Microsoft\\Edge\\Application\\msedge.exe"),
@@ -250,22 +275,70 @@ function systemChromiumCandidates(): string[] {
250
275
  return candidates;
251
276
  }
252
277
 
253
- function resolveSystemChromium(): string | undefined {
254
- if (resolvedChromium !== undefined) return resolvedChromium ?? undefined;
278
+ function firstExecutableCandidate(candidates: string[], accept: (candidate: string) => boolean): string | undefined {
255
279
  const seen = new Set<string>();
256
- for (const candidate of systemChromiumCandidates()) {
280
+ for (const candidate of candidates) {
257
281
  if (!candidate || seen.has(candidate)) continue;
258
282
  seen.add(candidate);
259
- if (isExecutableFile(candidate)) {
260
- resolvedChromium = candidate;
261
- logger.debug("Using system Chrome/Chromium", { path: candidate });
262
- return candidate;
263
- }
283
+ if (accept(candidate) && isExecutableFile(candidate)) return candidate;
264
284
  }
265
- resolvedChromium = null;
266
285
  return undefined;
267
286
  }
268
287
 
288
+ function resolveSystemChromium(): string | undefined {
289
+ if (resolvedChromium !== undefined) return resolvedChromium ?? undefined;
290
+ const found = firstExecutableCandidate(systemChromiumCandidates(), () => true);
291
+ resolvedChromium = found ?? null;
292
+ if (found) logger.debug("Using system Chrome/Chromium", { path: found });
293
+ return found;
294
+ }
295
+
296
+ /** Edge is Chromium-based but keeps its own profile format under its own user data root. */
297
+ const EDGE_EXECUTABLE_PATTERN =
298
+ /(?:^|[/\\])(?:msedge(?:\.exe)?|microsoft-edge(?:-(?:stable|beta|dev|canary))?|com\.microsoft\.Edge|Microsoft Edge(?: Beta| Dev| Canary)?)$/i;
299
+
300
+ /** True for a Microsoft Edge executable path (excluded from Chrome profile mode). */
301
+ export function isEdgeExecutable(candidate: string): boolean {
302
+ return EDGE_EXECUTABLE_PATTERN.test(candidate);
303
+ }
304
+
305
+ const CHROME_PROFILE_EXECUTABLE_PATTERN =
306
+ /(?:^|[/\\])(?:google-chrome(?:-(?:stable|beta|unstable|canary))?|chromium(?:-browser)?|chrome(?:\.exe)?|Google Chrome(?: Beta| Dev| Canary)?|Chromium|com\.google\.Chrome|org\.chromium\.Chromium)$/i;
307
+
308
+ /** True only for executable names owned by Google Chrome or Chromium. */
309
+ export function isChromeProfileExecutable(candidate: string): boolean {
310
+ return CHROME_PROFILE_EXECUTABLE_PATTERN.test(candidate);
311
+ }
312
+
313
+ /**
314
+ * Validate the executable identity used for profile mode. Most symlinks are
315
+ * judged by their resolved target so a renamed cross-brand browser cannot pass
316
+ * by alias. Snap's canonical `/snap/bin/chromium` launcher is the exception:
317
+ * it resolves to the generic `/usr/bin/snap` dispatcher by design.
318
+ */
319
+ export function isChromeProfileExecutableForLaunch(candidate: string, resolvedCandidate: string): boolean {
320
+ return (
321
+ (path.posix.normalize(candidate) === "/snap/bin/chromium" &&
322
+ path.posix.normalize(resolvedCandidate) === "/usr/bin/snap") ||
323
+ isChromeProfileExecutable(resolvedCandidate)
324
+ );
325
+ }
326
+
327
+ let resolvedProfileChrome: string | null | undefined; // undefined = unchecked; null = not found
328
+
329
+ /**
330
+ * Installed Chrome/Chromium executable for saved-profile mode, or undefined when
331
+ * none is present. Edge is excluded on purpose: a discovered Chrome user data
332
+ * directory must never be opened by a different browser brand.
333
+ */
334
+ export function resolveSystemChromeForProfile(): string | undefined {
335
+ if (resolvedProfileChrome !== undefined) return resolvedProfileChrome ?? undefined;
336
+ const found = firstExecutableCandidate(systemChromiumCandidates(), isChromeProfileExecutable);
337
+ resolvedProfileChrome = found ?? null;
338
+ if (found) logger.debug("Using system Chrome/Chromium for profile mode", { path: found });
339
+ return found;
340
+ }
341
+
269
342
  export interface LaunchHeadlessOptions {
270
343
  headless: boolean;
271
344
  viewport?: { width: number; height: number; deviceScaleFactor?: number };
@@ -10,6 +10,7 @@
10
10
 
11
11
  import * as os from "node:os";
12
12
  import * as path from "node:path";
13
+ import { $credentialEnv } from "@gajae-code/utils/env";
13
14
 
14
15
  export interface DiscoveryEnv {
15
16
  platform: NodeJS.Platform;
@@ -18,19 +19,55 @@ export interface DiscoveryEnv {
18
19
  exists: (p: string) => boolean;
19
20
  /** Windows LOCALAPPDATA override (tests / non-default installs). */
20
21
  localAppData?: string;
22
+ /** Linux Chrome-specific default user-data override. */
23
+ chromeUserDataDir?: string;
24
+ /** Linux Chrome config-home override (takes precedence over XDG_CONFIG_HOME). */
25
+ chromeConfigHome?: string;
26
+ /** Linux XDG config-home override. */
27
+ xdgConfigHome?: string;
28
+ }
29
+
30
+ function discoveryPath(env: DiscoveryEnv): typeof path.posix {
31
+ return env.platform === "win32" ? path.win32 : path.posix;
21
32
  }
22
33
 
23
34
  /** Candidate Chrome user-data roots for the platform (most common first). */
24
35
  export function chromeUserDataRoots(env: DiscoveryEnv): string[] {
36
+ const platformPath = discoveryPath(env);
25
37
  switch (env.platform) {
26
38
  case "darwin":
27
- return [path.join(env.home, "Library", "Application Support", "Google", "Chrome")];
39
+ return [
40
+ platformPath.join(env.home, "Library", "Application Support", "Google", "Chrome"),
41
+ platformPath.join(env.home, "Library", "Application Support", "Google", "Chrome Beta"),
42
+ platformPath.join(env.home, "Library", "Application Support", "Google", "Chrome Dev"),
43
+ platformPath.join(env.home, "Library", "Application Support", "Google", "Chrome Canary"),
44
+ platformPath.join(env.home, "Library", "Application Support", "Chromium"),
45
+ ];
28
46
  case "win32": {
29
- const localAppData = env.localAppData ?? path.join(env.home, "AppData", "Local");
30
- return [path.join(localAppData, "Google", "Chrome", "User Data")];
47
+ const localAppData = env.localAppData ?? platformPath.join(env.home, "AppData", "Local");
48
+ return [
49
+ platformPath.join(localAppData, "Google", "Chrome", "User Data"),
50
+ platformPath.join(localAppData, "Google", "Chrome Beta", "User Data"),
51
+ platformPath.join(localAppData, "Google", "Chrome Dev", "User Data"),
52
+ platformPath.join(localAppData, "Google", "Chrome SxS", "User Data"),
53
+ platformPath.join(localAppData, "Chromium", "User Data"),
54
+ ];
55
+ }
56
+ default: {
57
+ const configHome = env.chromeConfigHome ?? env.xdgConfigHome ?? platformPath.join(env.home, ".config");
58
+ return [
59
+ ...(env.chromeUserDataDir ? [env.chromeUserDataDir] : []),
60
+ platformPath.join(configHome, "google-chrome"),
61
+ platformPath.join(configHome, "google-chrome-beta"),
62
+ platformPath.join(configHome, "google-chrome-unstable"),
63
+ platformPath.join(configHome, "google-chrome-canary"),
64
+ platformPath.join(configHome, "chromium"),
65
+ platformPath.join(env.home, ".var", "app", "com.google.Chrome", "config", "google-chrome"),
66
+ platformPath.join(env.home, ".var", "app", "org.chromium.Chromium", "config", "chromium"),
67
+ platformPath.join(env.home, "snap", "chromium", "common", "chromium"),
68
+ platformPath.join(env.home, "snap", "chromium", "current", ".config", "chromium"),
69
+ ];
31
70
  }
32
- default:
33
- return [path.join(env.home, ".config", "google-chrome"), path.join(env.home, ".config", "chromium")];
34
71
  }
35
72
  }
36
73
 
@@ -48,8 +85,9 @@ export function discoverDefaultChromeProfile(
48
85
  env: DiscoveryEnv,
49
86
  profileDirectory = "Default",
50
87
  ): DiscoveredProfile | null {
88
+ const platformPath = discoveryPath(env);
51
89
  for (const userDataDir of chromeUserDataRoots(env)) {
52
- const profileDir = path.join(userDataDir, profileDirectory);
90
+ const profileDir = platformPath.join(userDataDir, profileDirectory);
53
91
  if (env.exists(profileDir)) {
54
92
  return { userDataDir, profileDirectory, profileDir };
55
93
  }
@@ -59,5 +97,17 @@ export function discoverDefaultChromeProfile(
59
97
 
60
98
  /** Convenience wrapper using the live OS environment + fs. */
61
99
  export function defaultDiscoveryEnv(exists: (p: string) => boolean): DiscoveryEnv {
62
- return { platform: process.platform, home: os.homedir(), exists };
100
+ const localAppData = $credentialEnv("LOCALAPPDATA");
101
+ const chromeUserDataDir = $credentialEnv("CHROME_USER_DATA_DIR");
102
+ const chromeConfigHome = $credentialEnv("CHROME_CONFIG_HOME");
103
+ const xdgConfigHome = $credentialEnv("XDG_CONFIG_HOME");
104
+ return {
105
+ platform: process.platform,
106
+ home: os.homedir(),
107
+ exists,
108
+ ...(localAppData ? { localAppData } : {}),
109
+ ...(chromeUserDataDir ? { chromeUserDataDir } : {}),
110
+ ...(chromeConfigHome ? { chromeConfigHome } : {}),
111
+ ...(xdgConfigHome ? { xdgConfigHome } : {}),
112
+ };
63
113
  }
@@ -42,7 +42,7 @@ interface BrowserRenderContext {
42
42
 
43
43
  function describeBrowser(args: BrowserRenderArgs, details: BrowserToolDetails | undefined): string | undefined {
44
44
  if (args.app?.cdp_url) return `connected ${args.app.cdp_url}`;
45
- if (args.app?.browser === "chrome") return `Chrome profile ${args.app.profile_directory ?? "<profile>"}`;
45
+ if (args.app?.browser === "chrome") return `Chrome profile ${args.app.profile_directory ?? "Default"}`;
46
46
  if (args.app?.path) return `spawned ${shortenPath(args.app.path)}`;
47
47
  switch (details?.browser) {
48
48
  case "headless":
@@ -56,6 +56,13 @@ function describeBrowser(args: BrowserRenderArgs, details: BrowserToolDetails |
56
56
  }
57
57
  }
58
58
 
59
+ export function describeBrowserForTest(
60
+ args: BrowserRenderArgs,
61
+ details: BrowserToolDetails | undefined,
62
+ ): string | undefined {
63
+ return describeBrowser(args, details);
64
+ }
65
+
59
66
  function tabLabel(args: BrowserRenderArgs, details: BrowserToolDetails | undefined): string {
60
67
  const name = details?.name ?? args.name ?? "main";
61
68
  return `tab ${JSON.stringify(name)}`;