@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
@@ -57,7 +57,7 @@ import {
57
57
  invalidateSessionTitleGeneration,
58
58
  isSessionTitleGenerationCurrent,
59
59
  } from "../utils/session-title-generation";
60
- import { buildConversationTitleInput, generateSessionTitle } from "../utils/title-generator";
60
+ import { buildConversationTitleInput, generateSessionTitle, titleInputObfuscator } from "../utils/title-generator";
61
61
  import { handleAsideAcp } from "./helpers/aside";
62
62
  import { buildAutoroutingStatusReport } from "./helpers/autorouting-status";
63
63
  import { buildContextReportText } from "./helpers/context-report";
@@ -66,6 +66,7 @@ import { buildFastStatusReport } from "./helpers/fast-status-report";
66
66
  import { formatDuration } from "./helpers/format";
67
67
  import { commandConsumed, errorMessage, parseSlashCommand, parseSubcommand, usage } from "./helpers/parse";
68
68
  import { renderProgressReportLines, renderProgressReportText } from "./helpers/progress-report";
69
+ import { buildProviderAuthStatusText } from "./helpers/provider-auth-status";
69
70
  import { handleSshAcp } from "./helpers/ssh";
70
71
  import { buildUsageReportText, collectCachedUsageReports } from "./helpers/usage-report";
71
72
  import type {
@@ -157,7 +158,9 @@ function toSlashCommandRuntime(runtime: TuiSlashCommandRuntime): SlashCommandRun
157
158
  async function regenerateSessionTitle(runtime: SlashCommandRuntime): Promise<SlashCommandResult> {
158
159
  try {
159
160
  const generation = beginSessionTitleGeneration(runtime.sessionManager);
160
- const input = buildConversationTitleInput(runtime.session.messages);
161
+ const activeCwd = runtime.sessionManager.getCwd();
162
+ const obfuscateText = await titleInputObfuscator(runtime.settings, activeCwd);
163
+ const input = buildConversationTitleInput(runtime.session.messages, obfuscateText);
161
164
  if (!input) {
162
165
  return usage("Nothing to summarize yet — pass a title: /rename <title>", runtime);
163
166
  }
@@ -169,10 +172,11 @@ async function regenerateSessionTitle(runtime: SlashCommandRuntime): Promise<Sla
169
172
  runtime.session.credentialSessionId,
170
173
  runtime.session.model,
171
174
  provider => runtime.session.agent.metadataForProvider(provider),
175
+ activeCwd,
172
176
  );
173
177
  if (
174
178
  !isSessionTitleGenerationCurrent(runtime.sessionManager, generation) ||
175
- buildConversationTitleInput(runtime.session.messages) !== input
179
+ buildConversationTitleInput(runtime.session.messages, obfuscateText) !== input
176
180
  )
177
181
  return commandConsumed();
178
182
  if (!generated) {
@@ -292,6 +296,7 @@ function providerSetupUsage(): string {
292
296
  "Aliases include minimax, zai, alibaba, cline, command-code, goat, and ionet.",
293
297
  `API providers: ${MODEL_ONBOARDING_API_PROVIDER_COMMAND} [--force]`,
294
298
  `Available presets:\n${formatProviderPresetList()}`,
299
+ "Credential status: /provider status",
295
300
  "OAuth/subscription providers: /provider login [provider-id] or /login [provider-id]",
296
301
  "Headless OAuth callbacks can be pasted with /login <redirect URL or code>.",
297
302
  ].join("\n");
@@ -1151,6 +1156,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1151
1156
  if (!materializedProfile) {
1152
1157
  for (const [targetId, selector] of assignments) {
1153
1158
  const target = GJC_MODEL_ASSIGNMENT_TARGETS[targetId];
1159
+ runtime.session.markProfileRoleOverrideManual?.(target.settingsPath, targetId);
1154
1160
  if (target.settingsPath === "modelRoles") {
1155
1161
  runtime.settings.setModelRole(targetId, selector);
1156
1162
  } else {
@@ -1653,7 +1659,7 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1653
1659
  aliases: ["account"],
1654
1660
  description: "Switch this session's active stored account, or list accounts",
1655
1661
  acpDescription: "Switch or list stored credentials for this session",
1656
- inlineHint: "[email:<addr>|id:<n>|account:<id>|project:<id>|provider/<selector>]",
1662
+ inlineHint: "[email:<addr>|id:<n>|account:<id>|project:<id>|org:<id|name>|provider/<selector>]",
1657
1663
  acpInputHint: "[selector]",
1658
1664
  allowArgs: true,
1659
1665
  handle: async (command, runtime) => {
@@ -1899,8 +1905,8 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1899
1905
 
1900
1906
  {
1901
1907
  name: "provider",
1902
- description: "Set up API-compatible providers or login providers",
1903
- inlineHint: "add|login",
1908
+ description: "Show provider credential status or set up providers",
1909
+ inlineHint: "status|add|login",
1904
1910
  allowArgs: true,
1905
1911
  handle: async (command, runtime) => {
1906
1912
  const args = command.args.trim();
@@ -1908,6 +1914,10 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1908
1914
  await runtime.output(providerSetupUsage());
1909
1915
  return commandConsumed();
1910
1916
  }
1917
+ if (args === "status") {
1918
+ await runtime.output(await buildProviderAuthStatusText(runtime.session));
1919
+ return commandConsumed();
1920
+ }
1911
1921
  if (args === "login" || args.startsWith("login ")) {
1912
1922
  const providerId = args.slice("login".length).trim();
1913
1923
  const loginCommand = providerId ? `/login ${providerId}` : "/login [provider-id]";
@@ -1976,6 +1986,11 @@ const BUILTIN_SLASH_COMMAND_REGISTRY: ReadonlyArray<SlashCommandSpec> = [
1976
1986
  runtime.ctx.editor.setText("");
1977
1987
  return;
1978
1988
  }
1989
+ if (args === "status") {
1990
+ runtime.ctx.showStatus(await buildProviderAuthStatusText(runtime.ctx.session));
1991
+ runtime.ctx.editor.setText("");
1992
+ return;
1993
+ }
1979
1994
  if (args === "help") {
1980
1995
  runtime.ctx.showStatus(providerSetupUsage());
1981
1996
  runtime.ctx.editor.setText("");
@@ -1,13 +1,16 @@
1
- import type { AuthCredentialSelector, AuthCredentialSnapshotEntry } from "@gajae-code/ai/core";
1
+ import {
2
+ type AuthCredentialSelector,
3
+ type AuthCredentialSnapshotEntry,
4
+ formatOAuthIdentityLabel,
5
+ oauthCredentialMatchesOrganization,
6
+ } from "@gajae-code/ai/core";
2
7
  import { parseCliCredentialSelector } from "../../runtime-credential-selector";
3
8
  import type { SlashCommandRuntime } from "../types";
4
9
 
5
10
  /** Human-readable label for one stored OAuth credential row. */
6
11
  function describeCredentialRow(entry: AuthCredentialSnapshotEntry): string {
7
12
  if (entry.credential.type !== "oauth") return `id:${entry.id} (api key)`;
8
- const email = entry.credential.email;
9
- const accountId = entry.credential.accountId;
10
- const label = email ?? accountId ?? `row ${entry.id}`;
13
+ const label = formatOAuthIdentityLabel(entry.credential) ?? `row ${entry.id}`;
11
14
  return `id:${entry.id} — ${label}`;
12
15
  }
13
16
 
@@ -33,6 +36,8 @@ function selectorMatchesRow(selector: AuthCredentialSelector, entry: AuthCredent
33
36
  return entry.credential.accountId === selector.value;
34
37
  case "project":
35
38
  return entry.credential.projectId === selector.value;
39
+ case "org":
40
+ return oauthCredentialMatchesOrganization(entry.credential, selector.value);
36
41
  }
37
42
  }
38
43
 
@@ -116,7 +121,7 @@ export async function switchSessionCredentialCommand(runtime: SlashCommandRuntim
116
121
  try {
117
122
  parsed = parseCliCredentialSelector(trimmed);
118
123
  } catch {
119
- return `Invalid selector "${trimmed}". Use email:name@example.com, id:15, account:<id>, project:<id>, or provider/<selector>.`;
124
+ return `Invalid selector "${trimmed}". Use email:name@example.com, id:15, account:<id>, project:<id>, org:<organization id or name>, or provider/<selector>.`;
120
125
  }
121
126
 
122
127
  const authStorage = runtime.session.modelRegistry.authStorage;
@@ -1,4 +1,4 @@
1
- import { getMCPConfigPath } from "@gajae-code/utils";
1
+ import { getMCPConfigPath, sanitizeDisplayLine } from "@gajae-code/utils";
2
2
  import { listPrompts, listResources, listTools } from "../../runtime-mcp/client";
3
3
  import {
4
4
  addMCPServer,
@@ -19,6 +19,14 @@ import { commandConsumed, errorMessage, parseNamedScopeArgs, parseSubcommand, us
19
19
 
20
20
  type AcpMcpScope = "user" | "project";
21
21
 
22
+ /**
23
+ * One terminal row for an untrusted MCP server or tool name.
24
+ * Ordinary names are unchanged. Controls, OSC, and line breaks are not.
25
+ */
26
+ export function mcpTerminalLabel(value: string): string {
27
+ return sanitizeDisplayLine(value);
28
+ }
29
+
22
30
  interface ParsedMcpAddArgs {
23
31
  name?: string;
24
32
  scope: AcpMcpScope;
@@ -272,7 +280,7 @@ async function handleTestCommand(rest: string, runtime: SlashCommandRuntime): Pr
272
280
  return await withPreparedMcpConnection(runtime, name, server.config, server.scope, async connection => {
273
281
  const tools = await listTools(connection);
274
282
  const lines = [`Server "${name}" connected (${tools.length} tools).`];
275
- for (const tool of tools) lines.push(` - ${tool.name}`);
283
+ for (const tool of tools) lines.push(` - ${mcpTerminalLabel(tool.name)}`);
276
284
  await runtime.output(lines.join("\n"));
277
285
  return commandConsumed();
278
286
  });
@@ -398,7 +406,7 @@ async function handleListCommand(runtime: SlashCommandRuntime): Promise<SlashCom
398
406
  } else {
399
407
  location = (config as { command: string }).command;
400
408
  }
401
- return `${name} | ${type} | ${status} | ${location ?? "(unknown)"} [${scope}]`;
409
+ return `${mcpTerminalLabel(name)} | ${type} | ${status} | ${location ?? "(unknown)"} [${scope}]`;
402
410
  })
403
411
  .join("\n"),
404
412
  );
@@ -0,0 +1,456 @@
1
+ import {
2
+ type AuthCredentialSnapshotEntry,
3
+ type EnvApiKeyCredentialSource,
4
+ getEnvApiKeyCredentialSources,
5
+ listProvidersWithEnvKey,
6
+ resolveOAuthStorageProvider,
7
+ } from "@gajae-code/ai/core";
8
+ import { replaceTabs, truncateToWidth, wrapTextWithAnsi } from "@gajae-code/tui";
9
+ import { $credentialEnv, sanitizeDisplayLine } from "@gajae-code/utils";
10
+ import type { ModelRegistry } from "../../config/model-registry";
11
+ import type { AgentSession } from "../../session/agent-session";
12
+
13
+ type ProviderAuthStatusSession = Pick<AgentSession, "credentialSessionId"> & {
14
+ modelRegistry: Pick<
15
+ ModelRegistry,
16
+ | "authStorage"
17
+ | "getAll"
18
+ | "getAvailable"
19
+ | "getConfiguredProviderIds"
20
+ | "getAuthStorageOwner"
21
+ | "getProviderConfigApiKeySources"
22
+ | "getProviderRuntimeApiKeyEnvName"
23
+ | "hasRuntimeProviderApiKey"
24
+ >;
25
+ };
26
+
27
+ interface CredentialSource {
28
+ kind: "api_key" | "oauth";
29
+ layer: "runtime-override" | "runtime-provider" | "config" | "stored" | "environment" | "fallback" | "pending";
30
+ label: string;
31
+ }
32
+
33
+ type ConfigApiKeySource =
34
+ | { kind: "environment"; name: string; provider: string }
35
+ | { kind: "models-yml"; provider: string };
36
+
37
+ const MAX_STATUS_VALUE_WIDTH = 120;
38
+
39
+ function displayStatusValue(value: string): string {
40
+ const safe = replaceTabs(sanitizeDisplayLine(value))
41
+ .replaceAll(/[\u2028\u2029]/gu, " ")
42
+ .trim();
43
+ return truncateToWidth(safe, MAX_STATUS_VALUE_WIDTH).trim() || "unknown";
44
+ }
45
+
46
+ function displayAccountLabel(value: string): string {
47
+ return displayStatusValue(value);
48
+ }
49
+
50
+ function displayEnvironmentName(value: string): string {
51
+ return displayStatusValue(value);
52
+ }
53
+
54
+ function oauthLabel(entry: AuthCredentialSnapshotEntry): string {
55
+ if (entry.credential.type !== "oauth") return `OAuth (stored credential id:${entry.id})`;
56
+ const account = entry.credential.accountId ?? entry.credential.email;
57
+ return account ? `OAuth (account ${displayAccountLabel(account)})` : `OAuth (stored credential id:${entry.id})`;
58
+ }
59
+
60
+ function environmentCredentialLabel(name: string): string {
61
+ const safeName = displayEnvironmentName(name);
62
+ if (name.endsWith("_API_KEY")) return `API key (env ${safeName})`;
63
+ if (name.includes("OAUTH") || name.includes("ACCESS_TOKEN")) return `OAuth token (env ${safeName})`;
64
+ return `environment credential (env ${safeName})`;
65
+ }
66
+
67
+ function environmentSourceLabel(source: EnvApiKeyCredentialSource): string {
68
+ switch (source.kind) {
69
+ case "environment":
70
+ return environmentCredentialLabel(source.name);
71
+ case "google-adc":
72
+ return source.source === "explicit-file"
73
+ ? "Google ADC (env GOOGLE_APPLICATION_CREDENTIALS)"
74
+ : source.source === "default-file"
75
+ ? "Google ADC (default credentials file)"
76
+ : "Google ADC (metadata server)";
77
+ case "aws":
78
+ return source.source === "bearer-token"
79
+ ? "AWS bearer token (env AWS_BEARER_TOKEN_BEDROCK)"
80
+ : source.source === "environment-credentials"
81
+ ? "AWS environment credentials"
82
+ : source.source === "profile"
83
+ ? "AWS profile credentials"
84
+ : "AWS instance profile credentials";
85
+ case "unknown":
86
+ return "environment credentials";
87
+ }
88
+ }
89
+
90
+ function configSourceLabel(source: ConfigApiKeySource, includeProvider = false): string {
91
+ return source.kind === "environment"
92
+ ? `API key (env ${displayEnvironmentName(source.name)})`
93
+ : includeProvider
94
+ ? `API key (models.yml ${displayStatusValue(source.provider)})`
95
+ : "API key (models.yml)";
96
+ }
97
+
98
+ function configSourcesVaryByAlias(sources: ConfigApiKeySource[]): boolean {
99
+ const byProvider = new Map<string, Set<string>>();
100
+ for (const source of sources) {
101
+ const identities = byProvider.get(source.provider) ?? new Set<string>();
102
+ identities.add(source.kind === "environment" ? `environment:${source.name}` : `models-yml:${source.provider}`);
103
+ byProvider.set(source.provider, identities);
104
+ }
105
+ const signatures = new Set([...byProvider.values()].map(identities => [...identities].sort().join("\u0000")));
106
+ return signatures.size > 1;
107
+ }
108
+
109
+ function addSource(sources: CredentialSource[], source: CredentialSource): void {
110
+ if (
111
+ !sources.some(
112
+ existing =>
113
+ existing.kind === source.kind && existing.layer === source.layer && existing.label === source.label,
114
+ )
115
+ ) {
116
+ sources.push(source);
117
+ }
118
+ }
119
+
120
+ function hasRuntimeProviderCredential(registry: ProviderAuthStatusSession["modelRegistry"], provider: string): boolean {
121
+ const envName = registry.getProviderRuntimeApiKeyEnvName(provider);
122
+ return registry.hasRuntimeProviderApiKey(provider) && (envName === undefined || Boolean($credentialEnv(envName)));
123
+ }
124
+
125
+ function storedApiKeySource(
126
+ authStorage: ProviderAuthStatusSession["modelRegistry"]["authStorage"],
127
+ provider: string,
128
+ entries: AuthCredentialSnapshotEntry[],
129
+ rowId: number | undefined,
130
+ ): Omit<CredentialSource, "kind"> | undefined {
131
+ const apiKeys = entries.filter(entry => entry.credential.type === "api_key");
132
+ const selected = rowId === undefined ? undefined : apiKeys.find(entry => entry.id === rowId);
133
+ if (selected?.credential.type === "api_key") {
134
+ const usability = authStorage.getStoredApiKeyUsability(provider, selected.id);
135
+ if (selected.credential.key.startsWith("!") && usability !== true) {
136
+ return {
137
+ layer: "pending",
138
+ label:
139
+ usability === false
140
+ ? "API key (stored credential; retry pending)"
141
+ : "API key (stored credential; usability pending)",
142
+ };
143
+ }
144
+ return { layer: "stored", label: `API key (stored credential id:${selected.id})` };
145
+ }
146
+ const unknownCommandKey = apiKeys.some(
147
+ entry =>
148
+ entry.credential.type === "api_key" &&
149
+ entry.credential.key.startsWith("!") &&
150
+ authStorage.getStoredApiKeyUsability(provider, entry.id) === undefined,
151
+ );
152
+ if (unknownCommandKey) {
153
+ return { layer: "pending", label: "API key (stored credential; usability pending)" };
154
+ }
155
+ const retryableCommandKey = apiKeys.some(
156
+ entry =>
157
+ entry.credential.type === "api_key" &&
158
+ entry.credential.key.startsWith("!") &&
159
+ authStorage.getStoredApiKeyUsability(provider, entry.id) === false,
160
+ );
161
+ if (retryableCommandKey) {
162
+ return { layer: "pending", label: "API key (stored credential; retry pending)" };
163
+ }
164
+ const usableApiKeys = apiKeys.filter(entry => authStorage.getStoredApiKeyUsability(provider, entry.id) !== false);
165
+ if (usableApiKeys.length === 1) {
166
+ return { layer: "stored", label: `API key (stored credential id:${usableApiKeys[0]!.id})` };
167
+ }
168
+ if (usableApiKeys.length > 1) return { layer: "pending", label: "API key (stored credential; selection pending)" };
169
+ return undefined;
170
+ }
171
+
172
+ function collectSources(
173
+ provider: string,
174
+ entries: AuthCredentialSnapshotEntry[],
175
+ registry: ProviderAuthStatusSession["modelRegistry"],
176
+ environmentSources: EnvApiKeyCredentialSource[],
177
+ usesBedrockResolver: boolean,
178
+ ): CredentialSource[] {
179
+ const sources: CredentialSource[] = [];
180
+ if (usesBedrockResolver) {
181
+ for (const source of environmentSources) {
182
+ addSource(sources, { kind: "api_key", layer: "environment", label: environmentSourceLabel(source) });
183
+ }
184
+ return sources;
185
+ }
186
+ const authStorage = registry.authStorage;
187
+ for (const entry of entries) {
188
+ if (entry.credential.type === "oauth") {
189
+ addSource(sources, { kind: "oauth", layer: "stored", label: oauthLabel(entry) });
190
+ } else {
191
+ if (authStorage.getStoredApiKeyUsability(provider, entry.id) === false) continue;
192
+ addSource(sources, {
193
+ kind: "api_key",
194
+ layer: "stored",
195
+ label: `API key (stored credential id:${entry.id})`,
196
+ });
197
+ }
198
+ }
199
+
200
+ if (authStorage.hasRuntimeApiKey(provider)) {
201
+ addSource(sources, {
202
+ kind: "api_key",
203
+ layer: "runtime-override",
204
+ label: "API key (runtime override)",
205
+ });
206
+ }
207
+ const runtimeEnvName = registry.getProviderRuntimeApiKeyEnvName(provider);
208
+ if (
209
+ registry.hasRuntimeProviderApiKey(provider) &&
210
+ (runtimeEnvName === undefined || $credentialEnv(runtimeEnvName) !== undefined)
211
+ ) {
212
+ addSource(sources, {
213
+ kind: "api_key",
214
+ layer: "runtime-provider",
215
+ label: runtimeEnvName
216
+ ? `API key (env ${displayEnvironmentName(runtimeEnvName)})`
217
+ : "API key (runtime provider)",
218
+ });
219
+ }
220
+ for (const configSource of registry.getProviderConfigApiKeySources(provider)) {
221
+ addSource(sources, {
222
+ kind: "api_key",
223
+ layer: "config",
224
+ label: configSourceLabel(configSource),
225
+ });
226
+ }
227
+ for (const source of environmentSources) {
228
+ addSource(sources, { kind: "api_key", layer: "environment", label: environmentSourceLabel(source) });
229
+ }
230
+ return sources;
231
+ }
232
+
233
+ function activeSource(
234
+ provider: string,
235
+ entries: AuthCredentialSnapshotEntry[],
236
+ session: ProviderAuthStatusSession,
237
+ owner: object,
238
+ activeType: "api_key" | "oauth",
239
+ environmentSources: EnvApiKeyCredentialSource[],
240
+ usesBedrockResolver: boolean,
241
+ ): CredentialSource {
242
+ if (usesBedrockResolver) {
243
+ const source = environmentSources[0];
244
+ return source
245
+ ? { kind: "api_key", layer: "environment", label: environmentSourceLabel(source) }
246
+ : { kind: "api_key", layer: "pending", label: "AWS credentials unavailable" };
247
+ }
248
+ const { authStorage } = session.modelRegistry;
249
+ const sessionId = session.credentialSessionId;
250
+ if (activeType === "oauth") {
251
+ const pinnedRowId = authStorage.getSelectedOAuthCredentialRowId(provider, sessionId, { owner });
252
+ const preferredRowId = authStorage.getPreferredOAuthCredentialRowId(provider);
253
+ const sessionRowId = authStorage.getSessionCredentialRowId(provider, sessionId);
254
+ const availableSessionRowId =
255
+ sessionRowId !== undefined && authStorage.isCredentialAvailable(provider, sessionRowId)
256
+ ? sessionRowId
257
+ : undefined;
258
+ const rowId = pinnedRowId ?? availableSessionRowId ?? preferredRowId;
259
+ const selected = rowId === undefined ? undefined : entries.find(entry => entry.id === rowId);
260
+ if (
261
+ selected?.credential.type === "oauth" &&
262
+ (pinnedRowId === rowId || authStorage.isCredentialAvailable(provider, selected.id))
263
+ ) {
264
+ return { kind: "oauth", layer: "stored", label: oauthLabel(selected) };
265
+ }
266
+ const oauthEntries = entries.filter(
267
+ entry => entry.credential.type === "oauth" && authStorage.isCredentialAvailable(provider, entry.id),
268
+ );
269
+ if (oauthEntries.length === 1) return { kind: "oauth", layer: "stored", label: oauthLabel(oauthEntries[0]!) };
270
+ return {
271
+ kind: "oauth",
272
+ layer: "pending",
273
+ label: oauthEntries.length > 1 ? "OAuth (account selection pending)" : "OAuth (account unavailable)",
274
+ };
275
+ }
276
+
277
+ if (authStorage.hasRuntimeApiKey(provider)) {
278
+ return { kind: "api_key", layer: "runtime-override", label: "API key (runtime override)" };
279
+ }
280
+ const runtimeEnvName = session.modelRegistry.getProviderRuntimeApiKeyEnvName(provider);
281
+ if (
282
+ session.modelRegistry.hasRuntimeProviderApiKey(provider) &&
283
+ (runtimeEnvName === undefined || $credentialEnv(runtimeEnvName) !== undefined)
284
+ ) {
285
+ return {
286
+ kind: "api_key",
287
+ layer: "runtime-provider",
288
+ label: runtimeEnvName
289
+ ? `API key (env ${displayEnvironmentName(runtimeEnvName)})`
290
+ : "API key (runtime provider)",
291
+ };
292
+ }
293
+ const configSources = session.modelRegistry.getProviderConfigApiKeySources(provider);
294
+ if (authStorage.hasConfigApiKey(provider, owner) && configSources.length > 0) {
295
+ const configSource = configSources[0]!;
296
+ if (!authStorage.hasLiteralConfigApiKey(provider, owner)) {
297
+ const rowId = authStorage.getProspectiveApiKeyCredentialRowId(provider, sessionId, { owner });
298
+ const storedSource = storedApiKeySource(authStorage, provider, entries, rowId);
299
+ if (storedSource) return { kind: "api_key", ...storedSource };
300
+ }
301
+ return {
302
+ kind: "api_key",
303
+ layer: "config",
304
+ label: configSourcesVaryByAlias(configSources)
305
+ ? "API key (models.yml; source varies by provider alias)"
306
+ : configSourceLabel(configSource),
307
+ };
308
+ }
309
+ const selectedRowId = authStorage.getSelectedApiKeyCredentialRowId(provider, sessionId, { owner });
310
+ if (selectedRowId !== undefined && authStorage.getStoredApiKeyUsability(provider, selectedRowId) === false) {
311
+ return { kind: "api_key", layer: "pending", label: "API key (selected credential unavailable)" };
312
+ }
313
+ const rowId = authStorage.getProspectiveApiKeyCredentialRowId(provider, sessionId, { owner });
314
+ const storedSource = storedApiKeySource(authStorage, provider, entries, rowId);
315
+ if (storedSource) return { kind: "api_key", ...storedSource };
316
+
317
+ const envSource = environmentSources[0];
318
+ if (envSource) return { kind: "api_key", layer: "environment", label: environmentSourceLabel(envSource) };
319
+ return { kind: "api_key", layer: "fallback", label: "API key (configured)" };
320
+ }
321
+
322
+ /** Format credential provenance for `/provider status` without returning credential values. */
323
+ export async function buildProviderAuthStatusText(session: ProviderAuthStatusSession): Promise<string> {
324
+ const { modelRegistry } = session;
325
+ // Status must reflect rotating env-backed keys even before another model selection runs.
326
+ modelRegistry.getAvailable();
327
+ const googleVertexSources = await getEnvApiKeyCredentialSources("google-vertex");
328
+ const bedrockCredentialSources = await getEnvApiKeyCredentialSources("amazon-bedrock");
329
+ const authStorage = modelRegistry.authStorage;
330
+ const owner = modelRegistry.getAuthStorageOwner();
331
+ const snapshot = authStorage.exportSnapshot();
332
+ const storedProviders = new Set(snapshot.credentials.map(entry => resolveOAuthStorageProvider(entry.provider)));
333
+ const models = modelRegistry.getAll();
334
+ const providerApis = new Map<string, Set<string>>();
335
+ for (const model of models) {
336
+ const provider = resolveOAuthStorageProvider(model.provider);
337
+ const apis = providerApis.get(provider) ?? new Set<string>();
338
+ apis.add(model.api);
339
+ providerApis.set(provider, apis);
340
+ }
341
+ const bedrockRouteProviders = new Set<string>();
342
+ const bedrockOnlyProviders = new Set<string>();
343
+ const googleVertexRouteProviders = new Set<string>();
344
+ for (const [provider, apis] of providerApis) {
345
+ if (apis.has("google-vertex")) googleVertexRouteProviders.add(provider);
346
+ if (!apis.has("bedrock-converse-stream")) continue;
347
+ bedrockRouteProviders.add(provider);
348
+ if (apis.size === 1) bedrockOnlyProviders.add(provider);
349
+ }
350
+ if (!providerApis.has("google-vertex")) googleVertexRouteProviders.add("google-vertex");
351
+ if (!providerApis.has("amazon-bedrock")) {
352
+ bedrockRouteProviders.add("amazon-bedrock");
353
+ bedrockOnlyProviders.add("amazon-bedrock");
354
+ }
355
+ const providerIds = new Set([
356
+ ...models.map(model => resolveOAuthStorageProvider(model.provider)),
357
+ ...modelRegistry.getConfiguredProviderIds().map(provider => resolveOAuthStorageProvider(provider)),
358
+ ...snapshot.credentials.map(entry => resolveOAuthStorageProvider(entry.provider)),
359
+ ...listProvidersWithEnvKey().map(provider => resolveOAuthStorageProvider(provider)),
360
+ ]);
361
+ const providers = [...providerIds]
362
+ .filter(
363
+ provider =>
364
+ authStorage.hasSessionCredentialUnavailable(provider, session.credentialSessionId) ||
365
+ storedProviders.has(provider) ||
366
+ (googleVertexRouteProviders.has(provider)
367
+ ? googleVertexSources.length > 0 ||
368
+ modelRegistry.getProviderConfigApiKeySources(provider).length > 0 ||
369
+ hasRuntimeProviderCredential(modelRegistry, provider) ||
370
+ authStorage.hasRuntimeApiKey(provider)
371
+ : bedrockRouteProviders.has(provider)
372
+ ? bedrockCredentialSources.length > 0 ||
373
+ authStorage.hasAuth(provider, session.credentialSessionId, { owner })
374
+ : authStorage.hasAuth(provider, session.credentialSessionId, { owner })),
375
+ )
376
+ .sort((left, right) => left.localeCompare(right));
377
+ if (providers.length === 0) return "No configured provider credentials.";
378
+
379
+ const lines = ["Provider credentials (active source per provider):"];
380
+ for (const provider of providers) {
381
+ const entries = snapshot.credentials.filter(entry => resolveOAuthStorageProvider(entry.provider) === provider);
382
+ const configSources = modelRegistry.getProviderConfigApiKeySources(provider);
383
+ const usesBedrockResolver = bedrockOnlyProviders.has(provider);
384
+ const hasBedrockRoute = bedrockRouteProviders.has(provider);
385
+ const environmentSources = googleVertexRouteProviders.has(provider)
386
+ ? googleVertexSources
387
+ : usesBedrockResolver
388
+ ? bedrockCredentialSources
389
+ : await getEnvApiKeyCredentialSources(provider);
390
+ const activeType = authStorage.getEffectiveCredentialType(provider, session.credentialSessionId, { owner });
391
+ const sources = collectSources(provider, entries, modelRegistry, environmentSources, usesBedrockResolver);
392
+ const sessionCredentialUnavailable = authStorage.hasSessionCredentialUnavailable(
393
+ provider,
394
+ session.credentialSessionId,
395
+ );
396
+ let active: { kind: "api_key" | "oauth"; layer: string; label: string } | undefined;
397
+ if (usesBedrockResolver) {
398
+ active = activeSource(provider, entries, session, owner, "api_key", environmentSources, usesBedrockResolver);
399
+ } else if (activeType === "oauth" || activeType === "api_key") {
400
+ active = activeSource(provider, entries, session, owner, activeType, environmentSources, usesBedrockResolver);
401
+ } else if (environmentSources[0]) {
402
+ active = {
403
+ kind: "api_key" as const,
404
+ layer: "environment",
405
+ label: environmentSourceLabel(environmentSources[0]),
406
+ };
407
+ } else {
408
+ active = undefined;
409
+ }
410
+ const configOverridePrecedesUnavailablePin =
411
+ authStorage.hasConfigApiKey(provider, owner) &&
412
+ modelRegistry.getProviderConfigApiKeySources(provider).length > 0;
413
+ const overridePrecedesUnavailablePin =
414
+ active?.layer === "runtime-override" ||
415
+ active?.layer === "runtime-provider" ||
416
+ configOverridePrecedesUnavailablePin;
417
+ if (!usesBedrockResolver && sessionCredentialUnavailable && !overridePrecedesUnavailablePin) {
418
+ active = { kind: "api_key", layer: "pending", label: "selected credential unavailable" };
419
+ }
420
+ lines.push(
421
+ ...wrapTextWithAnsi(
422
+ `${displayStatusValue(provider)}: ${active?.label ?? "credential source unavailable"}`,
423
+ MAX_STATUS_VALUE_WIDTH,
424
+ ),
425
+ );
426
+ const configSourceVariesByAlias = active?.layer === "config" && configSourcesVaryByAlias(configSources);
427
+ if (configSourceVariesByAlias) {
428
+ const configuredSources = [...new Set(configSources.map(source => configSourceLabel(source, true)))];
429
+ lines.push(
430
+ ...wrapTextWithAnsi(` configured sources: ${configuredSources.join(", ")}`, MAX_STATUS_VALUE_WIDTH),
431
+ );
432
+ }
433
+ if (hasBedrockRoute && !usesBedrockResolver) {
434
+ const bedrockRouteSource = bedrockCredentialSources[0];
435
+ const bedrockRouteLabel = bedrockRouteSource
436
+ ? environmentSourceLabel(bedrockRouteSource)
437
+ : "AWS credentials unavailable";
438
+ lines.push(...wrapTextWithAnsi(` Bedrock route: ${bedrockRouteLabel}`, MAX_STATUS_VALUE_WIDTH));
439
+ }
440
+ const shadowed =
441
+ active && active.layer !== "pending"
442
+ ? sources
443
+ .filter(
444
+ source =>
445
+ !(configSourceVariesByAlias && source.layer === "config") &&
446
+ source.label !== active.label &&
447
+ !(active.layer === "stored" && source.layer === "stored" && source.kind === active.kind),
448
+ )
449
+ .map(source => source.label)
450
+ : [];
451
+ if (shadowed.length > 0) {
452
+ lines.push(...wrapTextWithAnsi(` shadowed: ${[...new Set(shadowed)].join(", ")}`, MAX_STATUS_VALUE_WIDTH));
453
+ }
454
+ }
455
+ return lines.join("\n");
456
+ }
@@ -1,6 +1,6 @@
1
1
  import { logger, ptree } from "@gajae-code/utils";
2
2
  import { Settings } from "../config/settings";
3
- import { OutputSink } from "../session/streaming-output";
3
+ import { OutputSink, type TerminalArtifactPublisher } from "../session/streaming-output";
4
4
  import { resolveOutputMaxColumns, resolveOutputSinkHeadBytes } from "../tools/output-meta";
5
5
  import { buildRemoteCommand, ensureConnection, ensureHostInfo, type SSHConnectionTarget } from "./connection-manager";
6
6
  import { hasSshfs, mountRemote } from "./sshfs-mount";
@@ -21,6 +21,8 @@ export interface SSHExecutorOptions {
21
21
  /** Artifact path/id for full output storage */
22
22
  artifactPath?: string;
23
23
  artifactId?: string;
24
+ /** Session-owned publisher for managed sessions without a writable artifact path. */
25
+ artifactPublisher?: TerminalArtifactPublisher;
24
26
  }
25
27
 
26
28
  export interface SSHResult {
@@ -40,8 +42,12 @@ export interface SSHResult {
40
42
  outputLines: number;
41
43
  /** Number of bytes included in the output text */
42
44
  outputBytes: number;
43
- /** Artifact ID if full output was saved to artifact storage */
45
+ /** Artifact ID if output was saved to artifact storage. */
44
46
  artifactId?: string;
47
+ /** Bytes omitted from artifact storage after its hard cap was reached. */
48
+ artifactTruncatedBytes?: number;
49
+ /** Bounded diagnostic when artifact storage failed. */
50
+ artifactFailureDiagnostic?: string;
45
51
  }
46
52
 
47
53
  function quoteForCompatShell(command: string): string {
@@ -92,6 +98,7 @@ export async function executeSSH(
92
98
  onChunk: options?.onChunk,
93
99
  artifactPath: options?.artifactPath,
94
100
  artifactId: options?.artifactId,
101
+ artifactPublisher: options?.artifactPublisher,
95
102
  headBytes: resolveOutputSinkHeadBytes(settings),
96
103
  maxColumns: resolveOutputMaxColumns(settings),
97
104
  });