mixdog 1.2.5 → 1.3.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 (493) hide show
  1. package/LICENSES/simple-icons-CC0-1.0.txt +30 -0
  2. package/NOTICE.md +19 -0
  3. package/package.json +4 -1
  4. package/scripts/check-model-recommendations.mjs +89 -0
  5. package/scripts/gate-local.mjs +7 -0
  6. package/scripts/lib/gate-scheduler.mjs +2 -2
  7. package/scripts/lib/isolated-test-env.mjs +16 -0
  8. package/scripts/lib/run-node-tests.mjs +5 -14
  9. package/scripts/provider-pingpong-live.mjs +9 -9
  10. package/src/agents/advisor/AGENT.md +4 -4
  11. package/src/agents/advisor/agent.json +1 -1
  12. package/src/agents/reviewer/AGENT.md +5 -4
  13. package/src/agents/reviewer/agent.json +1 -1
  14. package/src/defaults/shipped-history.json +17 -0
  15. package/src/defaults/skills/browser-use/SKILL.md +7 -1
  16. package/src/defaults/skills/computer-use/SKILL.md +3 -1
  17. package/src/defaults/skills/memory-management/SKILL.md +4 -1
  18. package/src/defaults/skills/setup/references/actions.md +11 -4
  19. package/src/defaults/skills/setup-guide/SKILL.md +175 -0
  20. package/src/defaults/skills/setup-guide/model-recommendations.json +333 -0
  21. package/src/defaults/skills/visualize/SKILL.md +3 -2
  22. package/src/lib/rules-builder.cjs +56 -7
  23. package/src/output-styles/common.md +22 -6
  24. package/src/output-styles/detailed.md +7 -5
  25. package/src/output-styles/minimal.md +7 -3
  26. package/src/output-styles/simple.md +2 -3
  27. package/src/rules/agent/AGENT.md +7 -1
  28. package/src/rules/agent-mode/AGENT_MODE.md +24 -0
  29. package/src/rules/agent-mode/MIXY.md +21 -0
  30. package/src/rules/agent-mode/ROUTINE.md +6 -0
  31. package/src/rules/lead/LEAD.md +9 -4
  32. package/src/rules/shared/10-tool-workflow.md +2 -1
  33. package/src/rules/shared/60-verification.md +4 -5
  34. package/src/rules/shared/70-delivery.md +3 -0
  35. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +2 -1
  36. package/src/runtime/agent/orchestrator/agent-runtime/room-supervisor-completion.mjs +86 -0
  37. package/src/runtime/agent/orchestrator/config.mjs +6 -0
  38. package/src/runtime/agent/orchestrator/context/deferred-tools.mjs +77 -14
  39. package/src/runtime/agent/orchestrator/context/role-instructions.mjs +182 -13
  40. package/src/runtime/agent/orchestrator/context/skill-catalog.mjs +5 -3
  41. package/src/runtime/agent/orchestrator/internal-agents.mjs +10 -0
  42. package/src/runtime/agent/orchestrator/mcp/agent-connectors.mjs +215 -0
  43. package/src/runtime/agent/orchestrator/mcp/child-tree.mjs +58 -64
  44. package/src/runtime/agent/orchestrator/mcp/client-transport.mjs +10 -1
  45. package/src/runtime/agent/orchestrator/mcp/client.mjs +122 -15
  46. package/src/runtime/agent/orchestrator/mcp/oauth-account.mjs +97 -0
  47. package/src/runtime/agent/orchestrator/mcp/oauth-callback.mjs +2 -3
  48. package/src/runtime/agent/orchestrator/mcp/oauth-client.mjs +49 -0
  49. package/src/runtime/agent/orchestrator/mcp/oauth-credentials.mjs +59 -9
  50. package/src/runtime/agent/orchestrator/mcp/oauth-login.mjs +32 -7
  51. package/src/runtime/agent/orchestrator/mcp/oauth-provider.mjs +45 -6
  52. package/src/runtime/agent/orchestrator/mcp/oauth.mjs +195 -6
  53. package/src/runtime/agent/orchestrator/mcp/server-connectors.mjs +17 -0
  54. package/src/runtime/agent/orchestrator/providers/account-pool.mjs +9 -2
  55. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  56. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +41 -19
  57. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +3 -2
  58. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events/content-block-start.mjs +4 -1
  59. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn/turn-events.mjs +2 -0
  60. package/src/runtime/agent/orchestrator/providers/anthropic-sse-turn.mjs +3 -0
  61. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +2 -1
  62. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +3 -1
  63. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-login.mjs +11 -5
  64. package/src/runtime/agent/orchestrator/providers/antigravity-oauth-tokens.mjs +4 -0
  65. package/src/runtime/agent/orchestrator/providers/catalog-deadline.mjs +163 -0
  66. package/src/runtime/agent/orchestrator/providers/catalog-failures.mjs +34 -0
  67. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth-login.mjs +38 -14
  69. package/src/runtime/agent/orchestrator/providers/lib/oauth-page.mjs +100 -26
  70. package/src/runtime/agent/orchestrator/providers/lib/send-callbacks.mjs +24 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-credential-probes.mjs +13 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +2 -1
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-send.mjs +1 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/chunk-events.mjs +4 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream/stream-state.mjs +3 -1
  76. package/src/runtime/agent/orchestrator/providers/openai-compat-chat-stream.mjs +2 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-compat-models.mjs +49 -4
  78. package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +0 -7
  79. package/src/runtime/agent/orchestrator/providers/openai-compat-responses-events.mjs +7 -1
  80. package/src/runtime/agent/orchestrator/providers/openai-compat-responses.mjs +1 -0
  81. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +2 -0
  82. package/src/runtime/agent/orchestrator/providers/openai-compat-xai-send.mjs +1 -0
  83. package/src/runtime/agent/orchestrator/providers/openai-error-contract.mjs +17 -12
  84. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state/response-events.mjs +5 -1
  85. package/src/runtime/agent/orchestrator/providers/openai-http-sse-response-state.mjs +11 -2
  86. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +1 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +45 -16
  88. package/src/runtime/agent/orchestrator/providers/openai-oauth-tokens.mjs +10 -0
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +1 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-ws-connect.mjs +196 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +74 -9
  92. package/src/runtime/agent/orchestrator/providers/openai-ws-stream/event-switch.mjs +14 -1
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +2 -0
  94. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-login.mjs +194 -0
  95. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth-tokens.mjs +353 -0
  96. package/src/runtime/agent/orchestrator/providers/opencode-go-oauth.mjs +293 -0
  97. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +33 -100
  98. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +23 -14
  99. package/src/runtime/agent/orchestrator/providers/registry.mjs +41 -27
  100. package/src/runtime/agent/orchestrator/runtime-core/ask-user-tool-defs.mjs +98 -4
  101. package/src/runtime/agent/orchestrator/runtime-core/context-status-shape.mjs +4 -0
  102. package/src/runtime/agent/orchestrator/runtime-core/extension-scopes.mjs +6 -4
  103. package/src/runtime/agent/orchestrator/runtime-core/orchestration.mjs +15 -8
  104. package/src/runtime/agent/orchestrator/runtime-core/plugin-mcp.mjs +1 -0
  105. package/src/runtime/agent/orchestrator/runtime-core/tool-bridge.mjs +12 -6
  106. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +32 -5
  107. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +10 -4
  108. package/src/runtime/agent/orchestrator/runtime-core/workflow/agents.mjs +4 -1
  109. package/src/runtime/agent/orchestrator/runtime-core/workflow/context.mjs +50 -20
  110. package/src/runtime/agent/orchestrator/runtime-core/workflow-ids.mjs +2 -0
  111. package/src/runtime/agent/orchestrator/session/agent-home.d.mts +4 -0
  112. package/src/runtime/agent/orchestrator/session/agent-home.mjs +33 -0
  113. package/src/runtime/agent/orchestrator/session/agent-mode.mjs +62 -0
  114. package/src/runtime/agent/orchestrator/session/agent-pool-progress.mjs +15 -3
  115. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.d.mts +31 -0
  116. package/src/runtime/agent/orchestrator/session/agent-room-supervisor.mjs +241 -0
  117. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +162 -0
  118. package/src/runtime/agent/orchestrator/session/agent-room.mjs +641 -0
  119. package/src/runtime/agent/orchestrator/session/catalog-db/schema.mjs +7 -1
  120. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +74 -13
  121. package/src/runtime/agent/orchestrator/session/compact/forked-summary.mjs +102 -0
  122. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +8 -2
  123. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +16 -0
  124. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +2 -0
  125. package/src/runtime/agent/orchestrator/session/compaction-archive-capture.mjs +6 -2
  126. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +165 -0
  127. package/src/runtime/agent/orchestrator/session/human-gate/held-message.mjs +95 -0
  128. package/src/runtime/agent/orchestrator/session/human-gate/outbound-policy.mjs +221 -0
  129. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +195 -0
  130. package/src/runtime/agent/orchestrator/session/human-gate/store.mjs +167 -0
  131. package/src/runtime/agent/orchestrator/session/lifecycle-scan.mjs +9 -0
  132. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +3 -1
  133. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +39 -2
  134. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +10 -0
  135. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +16 -1
  136. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +82 -33
  137. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +11 -4
  138. package/src/runtime/agent/orchestrator/session/loop/tool-exposure-migration.mjs +5 -4
  139. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +13 -3
  140. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +7 -0
  141. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +1 -0
  142. package/src/runtime/agent/orchestrator/session/manager/ask-turn-loop-options.mjs +6 -1
  143. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +6 -0
  144. package/src/runtime/agent/orchestrator/session/manager/ask-turn-settle.mjs +2 -0
  145. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +13 -5
  146. package/src/runtime/agent/orchestrator/session/manager/pending-lifecycle-epoch.mjs +0 -8
  147. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +10 -7
  148. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +62 -22
  149. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +44 -16
  150. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +22 -5
  151. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +23 -1
  152. package/src/runtime/agent/orchestrator/session/manager/session-close.mjs +81 -34
  153. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +39 -4
  154. package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +27 -5
  155. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +55 -8
  156. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +16 -0
  157. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +3 -2
  158. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +6 -0
  159. package/src/runtime/agent/orchestrator/session/manager/workflow-switch-notice.mjs +58 -0
  160. package/src/runtime/agent/orchestrator/session/manager.mjs +2 -2
  161. package/src/runtime/agent/orchestrator/session/mixy-name.mjs +24 -0
  162. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +32 -5
  163. package/src/runtime/agent/orchestrator/session/request-fork.mjs +47 -0
  164. package/src/runtime/agent/orchestrator/session/routine-result.d.mts +70 -0
  165. package/src/runtime/agent/orchestrator/session/routine-result.mjs +277 -0
  166. package/src/runtime/agent/orchestrator/session/side-question-store.mjs +16 -1
  167. package/src/runtime/agent/orchestrator/session/side-question.mjs +5 -43
  168. package/src/runtime/agent/orchestrator/session/store/fs-probe.mjs +10 -0
  169. package/src/runtime/agent/orchestrator/session/store/lifecycle-barriers.mjs +73 -6
  170. package/src/runtime/agent/orchestrator/session/store/load-session.mjs +40 -0
  171. package/src/runtime/agent/orchestrator/session/store/save-fault.mjs +15 -0
  172. package/src/runtime/agent/orchestrator/session/store/session-paths.mjs +12 -0
  173. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +8 -0
  174. package/src/runtime/agent/orchestrator/session/store-agent-worker-header.mjs +36 -0
  175. package/src/runtime/agent/orchestrator/session/store-agent-worker-rows.mjs +258 -43
  176. package/src/runtime/agent/orchestrator/session/store-record-strict-scan.mjs +325 -0
  177. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +84 -21
  178. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +44 -12
  179. package/src/runtime/agent/orchestrator/session/store-summary-last-message.mjs +46 -0
  180. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +46 -30
  181. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +0 -4
  182. package/src/runtime/agent/orchestrator/session/store-transcript-cache.mjs +144 -45
  183. package/src/runtime/agent/orchestrator/session/store-transcript-projection.mjs +32 -13
  184. package/src/runtime/agent/orchestrator/session/store-transcript-worker.mjs +364 -38
  185. package/src/runtime/agent/orchestrator/session/store.mjs +9 -2
  186. package/src/runtime/agent/orchestrator/session/task-wait-control.mjs +43 -12
  187. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +23 -6
  188. package/src/runtime/agent/orchestrator/session/transcript-restore/restore.mjs +44 -1
  189. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +12 -6
  190. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +13 -7
  191. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/bashism-rewrite.mjs +1 -1
  192. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/benign-exit.mjs +7 -1
  193. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/completed-result.mjs +40 -7
  194. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/deadline-plan.mjs +37 -34
  195. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/inline-hoist.mjs +1 -1
  196. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/spawn-env.mjs +0 -4
  197. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +6 -0
  198. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +29 -27
  199. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +1 -1
  200. package/src/runtime/agent/orchestrator/tools/builtin/find-files-tool.mjs +28 -11
  201. package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +12 -3
  202. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +203 -101
  203. package/src/runtime/agent/orchestrator/tools/builtin/git-repo-rw-lock.mjs +90 -41
  204. package/src/runtime/agent/orchestrator/tools/builtin/lib/list-helpers.mjs +17 -1
  205. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-delivery.mjs +199 -0
  206. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +12 -0
  207. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-task-output.mjs +165 -39
  208. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +25 -13
  209. package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +113 -5
  210. package/src/runtime/agent/orchestrator/tools/builtin/read-batch.mjs +7 -6
  211. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +19 -4
  212. package/src/runtime/agent/orchestrator/tools/builtin/read-line-collector.mjs +5 -3
  213. package/src/runtime/agent/orchestrator/tools/builtin/read-single-render.mjs +25 -7
  214. package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +2 -1
  215. package/src/runtime/agent/orchestrator/tools/builtin/read-tool/batch-render.mjs +3 -1
  216. package/src/runtime/agent/orchestrator/tools/builtin/search-glob-tool.mjs +12 -5
  217. package/src/runtime/agent/orchestrator/tools/builtin/search-grep-tool.mjs +61 -22
  218. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +32 -8
  219. package/src/runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs +193 -19
  220. package/src/runtime/agent/orchestrator/tools/builtin/shell-direct-exe.mjs +57 -7
  221. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +123 -32
  222. package/src/runtime/agent/orchestrator/tools/builtin/shell-lossless-compact.mjs +26 -1
  223. package/src/runtime/agent/orchestrator/tools/builtin/shell-output.mjs +13 -28
  224. package/src/runtime/agent/orchestrator/tools/builtin/task-tool.mjs +90 -11
  225. package/src/runtime/agent/orchestrator/tools/builtin/wait-budgets.mjs +23 -0
  226. package/src/runtime/agent/orchestrator/tools/builtin.mjs +54 -10
  227. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +22 -28
  228. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +11 -7
  229. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +126 -9
  230. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +13 -13
  231. package/src/runtime/agent/orchestrator/tools/lib/owned-shell-trees.mjs +15 -6
  232. package/src/runtime/agent/orchestrator/tools/lib/shell-descendants.mjs +64 -2
  233. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promote-job.mjs +10 -2
  234. package/src/runtime/agent/orchestrator/tools/lib/shell-run-background/promotion-results.mjs +13 -3
  235. package/src/runtime/agent/orchestrator/tools/lib/shell-run-settle.mjs +8 -0
  236. package/src/runtime/agent/orchestrator/tools/lib/shell-run-state.mjs +6 -1
  237. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +1 -1
  238. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +104 -55
  239. package/src/runtime/agent/orchestrator/tools/shell-policy.mjs +7 -2
  240. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +39 -23
  241. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +6 -2
  242. package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +13 -13
  243. package/src/runtime/attachments/office-extract.mjs +11 -9
  244. package/src/runtime/browser-bridge/client.mjs +24 -0
  245. package/src/runtime/channels/lib/scheduler.mjs +40 -12
  246. package/src/runtime/channels/lib/schedules-db.mjs +71 -12
  247. package/src/runtime/channels/lib/webhook/session-dispatch.mjs +36 -16
  248. package/src/runtime/channels/lib/webhook.mjs +0 -1
  249. package/src/runtime/channels/lib/webhooks-db.mjs +100 -10
  250. package/src/runtime/channels/lib/worker-main.mjs +17 -20
  251. package/src/runtime/computer-bridge/client.mjs +28 -1
  252. package/src/runtime/connectors/gmail-app-password.mjs +690 -0
  253. package/src/runtime/connectors/google-mcp.mjs +446 -0
  254. package/src/runtime/memory/lib/core-memory-access.mjs +69 -0
  255. package/src/runtime/memory/lib/core-memory-file.mjs +16 -8
  256. package/src/runtime/memory/lib/core-memory-index.mjs +15 -9
  257. package/src/runtime/memory/lib/core-memory-management.mjs +10 -4
  258. package/src/runtime/memory/lib/core-memory-store.mjs +53 -30
  259. package/src/runtime/memory/lib/core-memory-uniqueness.mjs +10 -6
  260. package/src/runtime/memory/lib/embedding-tokenizer.mjs +32 -18
  261. package/src/runtime/memory/lib/http-router/session-routes.mjs +3 -2
  262. package/src/runtime/memory/lib/memory-action-handlers/core-actions.mjs +44 -14
  263. package/src/runtime/memory/lib/memory-schema/core-and-meta.mjs +11 -0
  264. package/src/runtime/memory/lib/memory.mjs +7 -1
  265. package/src/runtime/memory/lib/query-core-recall.mjs +9 -1
  266. package/src/runtime/memory/lib/query-hybrid-search.mjs +2 -0
  267. package/src/runtime/memory/lib/runtime-fetcher.mjs +1 -1
  268. package/src/runtime/memory/lib/tool-call-handler.mjs +9 -5
  269. package/src/runtime/memory/tool-defs.mjs +5 -0
  270. package/src/runtime/office/authoring/pptx-script-normalize.mjs +11 -8
  271. package/src/runtime/office/core/tabular.mjs +1 -1
  272. package/src/runtime/office/design/library/design-template-inspect.mjs +7 -4
  273. package/src/runtime/office/portable/docx-formatting.mjs +1 -1
  274. package/src/runtime/office/portable/docx-runs.mjs +1 -1
  275. package/src/runtime/office/portable/docx-tracked-edits.mjs +2 -2
  276. package/src/runtime/office/portable/portable-docx-edits.mjs +11 -10
  277. package/src/runtime/office/portable/portable-docx-operations.mjs +21 -17
  278. package/src/runtime/office/portable/portable-docx-parts.mjs +15 -9
  279. package/src/runtime/office/portable/portable-docx-styles.mjs +4 -1
  280. package/src/runtime/office/portable/portable-docx-xml.mjs +9 -9
  281. package/src/runtime/office/portable/portable-opc.mjs +27 -13
  282. package/src/runtime/office/portable/portable-pivot.mjs +3 -3
  283. package/src/runtime/office/portable/portable-pptx-chart.mjs +3 -3
  284. package/src/runtime/office/portable/portable-pptx-charts.mjs +24 -18
  285. package/src/runtime/office/portable/portable-pptx-core.mjs +5 -5
  286. package/src/runtime/office/portable/portable-pptx-deck.mjs +8 -4
  287. package/src/runtime/office/portable/portable-pptx-package.mjs +7 -4
  288. package/src/runtime/office/portable/portable-pptx-shapes.mjs +18 -9
  289. package/src/runtime/office/portable/portable-sheet-parts.mjs +9 -3
  290. package/src/runtime/office/portable/portable-sheet-xml.mjs +5 -5
  291. package/src/runtime/office/portable/portable-xlsx-charts.mjs +4 -1
  292. package/src/runtime/office/portable/portable-xlsx-drawings.mjs +10 -6
  293. package/src/runtime/office/portable/portable-xlsx-operations.mjs +8 -5
  294. package/src/runtime/office/portable/portable-xlsx-pivot-ops.mjs +1 -1
  295. package/src/runtime/office/portable/portable-xlsx-reference-shift.mjs +11 -7
  296. package/src/runtime/office/portable/portable-xlsx-sheet-edits.mjs +6 -3
  297. package/src/runtime/office/portable/portable-xml.mjs +1 -1
  298. package/src/runtime/shared/agent-avatar-sprites.mjs +445 -0
  299. package/src/runtime/shared/agent-avatar.d.mts +64 -0
  300. package/src/runtime/shared/agent-avatar.mjs +320 -0
  301. package/src/runtime/shared/agent-route-config.d.mts +3 -0
  302. package/src/runtime/shared/agent-route-config.mjs +16 -0
  303. package/src/runtime/shared/atomic-file.mjs +36 -14
  304. package/src/runtime/shared/background-tasks.mjs +60 -20
  305. package/src/runtime/shared/child-spawn-gate.mjs +26 -16
  306. package/src/runtime/shared/config.mjs +8 -11
  307. package/src/runtime/shared/connector-accounts.mjs +15 -0
  308. package/src/runtime/shared/connector-catalog.d.mts +52 -0
  309. package/src/runtime/shared/connector-catalog.mjs +230 -0
  310. package/src/runtime/shared/connector-triggers.d.mts +3 -0
  311. package/src/runtime/shared/connector-triggers.mjs +43 -0
  312. package/src/runtime/shared/file-lock.mjs +7 -1
  313. package/src/runtime/shared/file-permissions-worker.mjs +38 -0
  314. package/src/runtime/shared/file-permissions.d.mts +19 -4
  315. package/src/runtime/shared/file-permissions.mjs +310 -4
  316. package/src/runtime/shared/git-runner-worker.mjs +6 -78
  317. package/src/runtime/shared/google-oauth-client.mjs +24 -0
  318. package/src/runtime/shared/held-request-host.d.mts +12 -0
  319. package/src/runtime/shared/held-request-host.mjs +71 -0
  320. package/src/runtime/shared/llm/http-agent.mjs +7 -3
  321. package/src/runtime/shared/llm/provider-catalog-registry.mjs +10 -0
  322. package/src/runtime/shared/llm/usage-accounting.mjs +2 -0
  323. package/src/runtime/shared/llm/usage-ledger-import.mjs +32 -3
  324. package/src/runtime/shared/llm/usage-ledger-rollup.mjs +12 -5
  325. package/src/runtime/shared/llm/usage-ledger-worker.mjs +1 -1
  326. package/src/runtime/shared/llm/usage-ledger.mjs +20 -5
  327. package/src/runtime/shared/memory-snapshot.mjs +5 -1
  328. package/src/runtime/shared/notify-trace.mjs +8 -1
  329. package/src/runtime/shared/plain-preview.d.mts +1 -0
  330. package/src/runtime/shared/plain-preview.mjs +28 -0
  331. package/src/runtime/shared/pristine-execution-contract.json +5 -1
  332. package/src/runtime/shared/process-runner-worker.mjs +7 -0
  333. package/src/runtime/shared/process-runner.mjs +38 -0
  334. package/src/runtime/shared/provider-accounts.mjs +2 -1
  335. package/src/runtime/shared/provider-api-key.mjs +0 -1
  336. package/src/runtime/shared/read-row-numbers.mjs +1 -1
  337. package/src/runtime/shared/resource-admission.mjs +60 -18
  338. package/src/runtime/shared/routine-limits.d.mts +11 -0
  339. package/src/runtime/shared/routine-limits.mjs +21 -0
  340. package/src/runtime/shared/routine-trigger.d.mts +10 -0
  341. package/src/runtime/shared/routine-trigger.mjs +44 -0
  342. package/src/runtime/shared/run-child.mjs +84 -0
  343. package/src/runtime/shared/schedule-model-ref.mjs +9 -10
  344. package/src/runtime/shared/session-activity-signal.mjs +23 -0
  345. package/src/runtime/shared/shell-output-summary.mjs +23 -0
  346. package/src/runtime/shared/singleton-owner.mjs +126 -42
  347. package/src/runtime/shared/slow-span.mjs +4 -12
  348. package/src/runtime/shared/statusline/statusline-segments.mjs +13 -1
  349. package/src/runtime/shared/tool-output-limit.mjs +4 -2
  350. package/src/runtime/shared/tool-output-marker.mjs +58 -0
  351. package/src/runtime/shared/transcript-metadata.mjs +10 -0
  352. package/src/runtime/shared/turn-changes.mjs +0 -8
  353. package/src/runtime/shared/usage-readout-totals.mjs +56 -0
  354. package/src/runtime/shared/user-data-guard.mjs +131 -34
  355. package/src/runtime/shared/worktrees/activity-gate.mjs +33 -8
  356. package/src/runtime/shared/worktrees/git-head.mjs +20 -2
  357. package/src/runtime/shared/worktrees/lock.mjs +3 -2
  358. package/src/runtime/terminal-bridge/tool-defs.mjs +1 -1
  359. package/src/runtime/tidy/runners/biome.mjs +3 -1
  360. package/src/runtime/tidy/shadow.mjs +2 -1
  361. package/src/runtime/web-search/index.mjs +5 -7
  362. package/src/runtime/web-search/lib/formatter.mjs +42 -6
  363. package/src/runtime/web-search/tool-defs.mjs +6 -1
  364. package/src/session-runtime/agent-home-delivery.mjs +459 -0
  365. package/src/session-runtime/agent-profile-changes.mjs +21 -0
  366. package/src/session-runtime/agent-room-delivery.mjs +92 -0
  367. package/src/session-runtime/agent-task-sessions.mjs +200 -0
  368. package/src/session-runtime/boot/apis.mjs +50 -18
  369. package/src/session-runtime/boot/facade.mjs +5 -8
  370. package/src/session-runtime/boot/infrastructure.mjs +28 -17
  371. package/src/session-runtime/boot/tools.mjs +3 -0
  372. package/src/session-runtime/channel-config-api.mjs +53 -5
  373. package/src/session-runtime/cwd-plugins/core-memory-context.mjs +36 -20
  374. package/src/session-runtime/cwd-plugins/plugin-status.mjs +6 -1
  375. package/src/session-runtime/held-requests.mjs +228 -0
  376. package/src/session-runtime/internal-tool-executor/ask-user-tool.mjs +121 -0
  377. package/src/session-runtime/internal-tool-executor/feature-tools.mjs +5 -1
  378. package/src/session-runtime/internal-tool-executor/knowledge-tools.mjs +31 -2
  379. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +31 -2
  380. package/src/session-runtime/internal-tool-executor.mjs +2 -0
  381. package/src/session-runtime/lifecycle/session-catalog.mjs +9 -0
  382. package/src/session-runtime/lifecycle/session-switch/context-switch.mjs +4 -3
  383. package/src/session-runtime/lifecycle/session-switch/resume.mjs +11 -4
  384. package/src/session-runtime/lifecycle/session-switch/session-delete.mjs +3 -3
  385. package/src/session-runtime/lifecycle/shared.mjs +25 -2
  386. package/src/session-runtime/lifecycle/teardown/session-close.mjs +2 -0
  387. package/src/session-runtime/lifecycle/teardown.mjs +5 -2
  388. package/src/session-runtime/lifecycle-api.mjs +3 -1
  389. package/src/session-runtime/mcp-glue/server-catalog.mjs +8 -0
  390. package/src/session-runtime/mcp-glue/server-input.mjs +3 -0
  391. package/src/session-runtime/mcp-oauth-login.mjs +112 -15
  392. package/src/session-runtime/model-route/set-route.mjs +14 -3
  393. package/src/session-runtime/owned-automation-run.mjs +229 -0
  394. package/src/session-runtime/provider-auth/login.mjs +10 -6
  395. package/src/session-runtime/provider-auth/setup.mjs +19 -2
  396. package/src/session-runtime/provider-catalog-cache.mjs +101 -25
  397. package/src/session-runtime/provider-models/catalog-load.mjs +14 -3
  398. package/src/session-runtime/provider-models/row-hydration.mjs +4 -0
  399. package/src/session-runtime/provider-models.mjs +76 -10
  400. package/src/session-runtime/provider-readiness.mjs +4 -0
  401. package/src/session-runtime/resource-api.mjs +5 -0
  402. package/src/session-runtime/resource-mcp-api.mjs +107 -13
  403. package/src/session-runtime/resource-skills-api.mjs +12 -0
  404. package/src/session-runtime/room-member-gate.mjs +48 -0
  405. package/src/session-runtime/routine-home-turn.mjs +156 -0
  406. package/src/session-runtime/routine-owner.mjs +48 -0
  407. package/src/session-runtime/schedule-session-run.mjs +30 -64
  408. package/src/session-runtime/services/agent-tool/close-flow.mjs +2 -1
  409. package/src/session-runtime/services/agent-tool/helpers.mjs +10 -0
  410. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +10 -2
  411. package/src/session-runtime/services/agent-tool/job-views/session-progress.mjs +13 -4
  412. package/src/session-runtime/services/agent-tool/notify.mjs +15 -4
  413. package/src/session-runtime/services/agent-tool/restart-notify.mjs +134 -0
  414. package/src/session-runtime/services/agent-tool/send-flow.mjs +24 -1
  415. package/src/session-runtime/services/agent-tool/spawn-flow/deferred-spawn.mjs +2 -1
  416. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +4 -3
  417. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-plan.mjs +19 -4
  418. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-prep.mjs +2 -0
  419. package/src/session-runtime/services/agent-tool/spawn-flow/spawn-run.mjs +5 -1
  420. package/src/session-runtime/services/agent-tool/tag-registry/tag-lookup.mjs +8 -3
  421. package/src/session-runtime/services/agent-tool/tag-registry.mjs +3 -0
  422. package/src/session-runtime/services/agent-tool/worker-index/row-shape.mjs +4 -0
  423. package/src/session-runtime/services/agent-tool/worker-index.mjs +44 -10
  424. package/src/session-runtime/services/agent-tool.mjs +20 -0
  425. package/src/session-runtime/services/channel-admin.mjs +93 -24
  426. package/src/session-runtime/services/memory-access.mjs +37 -0
  427. package/src/session-runtime/services/provider-admin.mjs +166 -59
  428. package/src/session-runtime/services/schedule-access.mjs +91 -0
  429. package/src/session-runtime/services/usage-dashboard-model.mjs +2 -2
  430. package/src/session-runtime/services/usage-dashboard.mjs +27 -69
  431. package/src/session-runtime/session-create/session-options.mjs +34 -7
  432. package/src/session-runtime/session-hooks.mjs +16 -8
  433. package/src/session-runtime/setup-tool/executor.mjs +68 -6
  434. package/src/session-runtime/setup-tool/extended-actions.mjs +72 -14
  435. package/src/session-runtime/setup-tool/settings-contract.mjs +8 -6
  436. package/src/session-runtime/setup-tool/tool-defs.mjs +8 -0
  437. package/src/session-runtime/skills-api.mjs +16 -1
  438. package/src/session-runtime/tool-policy-refresh.mjs +238 -29
  439. package/src/session-runtime/turn/session-ops.mjs +10 -3
  440. package/src/session-runtime/turn/turn-run/ask-callbacks.mjs +11 -2
  441. package/src/session-runtime/turn/turn-run/turn-prepare.mjs +3 -0
  442. package/src/session-runtime/usage-stats-api.mjs +6 -1
  443. package/src/session-runtime/webhook-session-run.mjs +49 -67
  444. package/src/session-runtime/workflow-agents-api/agent-connectors.mjs +239 -0
  445. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +556 -22
  446. package/src/session-runtime/workflow-agents-api/workflow-packs.mjs +11 -1
  447. package/src/session-runtime/workflow-agents-api.mjs +4 -1
  448. package/src/standalone/channel-transport/http-routes.mjs +10 -9
  449. package/src/standalone/daemon-agent-control.mjs +1 -8
  450. package/src/standalone/daemon-desktop-runtime.mjs +20 -7
  451. package/src/standalone/daemon-owner.mjs +117 -25
  452. package/src/standalone/daemon-session-control.mjs +11 -2
  453. package/src/standalone/daemon.mjs +61 -17
  454. package/src/standalone/session-call-cache.mjs +6 -0
  455. package/src/standalone/session-protocol.mjs +28 -1
  456. package/src/standalone/session-service/retention/busy.mjs +7 -2
  457. package/src/standalone/session-service/session-calls/session-turns.mjs +9 -0
  458. package/src/standalone/session-service.mjs +19 -0
  459. package/src/standalone/session-transport/routes.mjs +7 -6
  460. package/src/tui/app/model-options.mjs +39 -2
  461. package/src/tui/app/model-picker.mjs +16 -2
  462. package/src/tui/app/provider-setup-picker.mjs +1 -2
  463. package/src/tui/app/slash-commands.mjs +20 -0
  464. package/src/tui/dist/index.mjs +487 -128
  465. package/src/tui/session/context-state.mjs +6 -1
  466. package/src/tui/session/notice-surface.mjs +35 -4
  467. package/src/tui/session/notice-text.mjs +0 -1
  468. package/src/tui/session/queue-helpers.mjs +2 -1
  469. package/src/tui/session/session-api/extensions.mjs +4 -0
  470. package/src/tui/session/session-api/intake/submission.mjs +12 -13
  471. package/src/tui/session/session-api/integrations.mjs +9 -5
  472. package/src/tui/session/session-api/lifecycle/session-reset.mjs +13 -3
  473. package/src/tui/session/session-api/lifecycle.mjs +17 -1
  474. package/src/tui/session/session-api/routes.mjs +48 -3
  475. package/src/tui/session/session-flow/drain.mjs +20 -3
  476. package/src/tui/session/session-flow/queue/entry-shape.mjs +2 -1
  477. package/src/tui/session/session-flow/queue/take-entries.mjs +3 -2
  478. package/src/tui/session/session-flow/steering.mjs +104 -24
  479. package/src/tui/session/session-flow.mjs +2 -0
  480. package/src/tui/session/tool-approval.mjs +26 -5
  481. package/src/tui/session/transcript-intake.mjs +6 -2
  482. package/src/tui/session/transcript-spill.mjs +5 -1
  483. package/src/tui/session/tui-steering-persist.mjs +65 -42
  484. package/src/tui/session/turn-live-call.mjs +56 -0
  485. package/src/tui/session/turn-stream.mjs +33 -0
  486. package/src/tui/session/turn.mjs +50 -7
  487. package/src/ui/statusline.mjs +1 -6
  488. package/src/ui/streaming-markdown-heal.mjs +24 -7
  489. package/src/vendor/statusline/bin/statusline-route.mjs +0 -1
  490. package/src/vendor/statusline/src/gateway/route-meta.mjs +0 -1
  491. package/src/workflows/default/WORKFLOW.md +9 -13
  492. package/src/session-runtime/automation-agents.mjs +0 -94
  493. package/src/session-runtime/automation-workflow.mjs +0 -59
@@ -11,7 +11,7 @@
11
11
  import { createServer } from 'node:http';
12
12
  import { randomBytes } from 'node:crypto';
13
13
  import { createOAuthPkce, parseOAuthCodeInput } from './lib/oauth-pkce.mjs';
14
- import { OAUTH_PAGE_CONTENT_TYPE, oauthSuccessHtml } from './lib/oauth-page.mjs';
14
+ import { OAUTH_PAGE_CONTENT_TYPE, oauthErrorHtml, oauthSuccessHtml } from './lib/oauth-page.mjs';
15
15
  import { openLoginUrl } from './lib/open-login-url.mjs';
16
16
 
17
17
  const TOKEN_URL = 'https://auth.openai.com/oauth/token';
@@ -44,7 +44,8 @@ function _scrubOAuthLoginBody(text) {
44
44
  export function createOpenAIOAuthLogin(deps) {
45
45
  const { clientId, originator, extractAccountId, identityFromTokens, expiryFromAccessToken, saveTokens } = deps;
46
46
 
47
- async function exchangeAuthorizationCode({ pkce, code }) {
47
+ async function exchangeAuthorizationCode({ pkce, code, signal = null }) {
48
+ signal?.throwIfAborted();
48
49
  const cleanCode = String(code || '').trim();
49
50
  if (!cleanCode) throw new Error('[openai-oauth] authorization code is required');
50
51
  const tokenRes = await fetch(TOKEN_URL, {
@@ -58,7 +59,9 @@ export function createOpenAIOAuthLogin(deps) {
58
59
  code_verifier: pkce.verifier,
59
60
  }),
60
61
  redirect: 'error',
61
- signal: AbortSignal.timeout(TOKEN_TIMEOUT_MS),
62
+ signal: signal
63
+ ? AbortSignal.any([signal, AbortSignal.timeout(TOKEN_TIMEOUT_MS)])
64
+ : AbortSignal.timeout(TOKEN_TIMEOUT_MS),
62
65
  });
63
66
  if (!tokenRes.ok) {
64
67
  const text = await tokenRes.text().catch(() => '');
@@ -78,6 +81,8 @@ export function createOpenAIOAuthLogin(deps) {
78
81
  account_id: extractAccountId(json.access_token),
79
82
  identity: identityFromTokens(json.id_token, json.access_token),
80
83
  };
84
+ // A cancelled login never stores the account it was exchanging.
85
+ signal?.throwIfAborted();
81
86
  saveTokens(tokens);
82
87
  return tokens;
83
88
  }
@@ -100,11 +105,30 @@ export function createOpenAIOAuthLogin(deps) {
100
105
  let server = null;
101
106
  let timeout = null;
102
107
  let finish = null;
108
+ let exchangePromise = null;
109
+ const controller = new AbortController();
110
+ // Browser and manual callbacks share one exchange: an authorization code is
111
+ // single-use, and a duplicate must not settle the login before the first.
112
+ const acceptCode = (code) => {
113
+ if (exchangePromise) return exchangePromise;
114
+ controller.signal.throwIfAborted();
115
+ // The browser deadline ends when a code arrives; the exchange has its own.
116
+ if (timeout) clearTimeout(timeout);
117
+ timeout = null;
118
+ exchangePromise = exchangeAuthorizationCode({ pkce, code, signal: controller.signal });
119
+ exchangePromise.then(
120
+ (tokens) => finish(tokens),
121
+ (err) => finish(null, err instanceof Error ? err : new Error(String(err)))
122
+ );
123
+ return exchangePromise;
124
+ };
103
125
  const waitForCallback = new Promise((resolve, reject) => {
104
126
  let settled = false;
105
127
  finish = (value, error = null) => {
106
128
  if (settled) return;
107
129
  settled = true;
130
+ // Work arriving after the login settled (or was cancelled) is rejected.
131
+ controller.abort();
108
132
  if (timeout) clearTimeout(timeout);
109
133
  try {
110
134
  server?.close();
@@ -122,19 +146,25 @@ export function createOpenAIOAuthLogin(deps) {
122
146
  return;
123
147
  }
124
148
  const code = u.searchParams.get('code');
125
- if (!code || u.searchParams.get('state') !== state) {
126
- res.writeHead(400);
127
- res.end('Invalid');
128
- finish(null);
149
+ const stateMatches = u.searchParams.get('state') === state;
150
+ if (!code || !stateMatches) {
151
+ res.writeHead(400, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
152
+ res.end(oauthErrorHtml('The sign-in callback was invalid or did not match this login.'));
153
+ // A request for another login is rejected alone; this login's
154
+ // legitimate callback may still arrive.
155
+ if (stateMatches && !exchangePromise) finish(null);
129
156
  return;
130
157
  }
131
- res.writeHead(200, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE });
132
- res.end(oauthSuccessHtml('OpenAI'));
133
158
  try {
134
- const tokens = await exchangeAuthorizationCode({ pkce, code });
135
- finish(tokens);
136
- } catch (err) {
137
- finish(null, err instanceof Error ? err : new Error(String(err)));
159
+ await acceptCode(code);
160
+ // The login settles (closing the server) before this response is
161
+ // written; do not leave a keep-alive connection bound to it.
162
+ res.writeHead(200, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE, Connection: 'close' });
163
+ res.end(oauthSuccessHtml('OpenAI'));
164
+ } catch {
165
+ // The shared exchange reports its error through waitForCallback.
166
+ res.writeHead(500, { 'Content-Type': OAUTH_PAGE_CONTENT_TYPE, Connection: 'close' });
167
+ res.end(oauthErrorHtml('OpenAI could not complete the token exchange.'));
138
168
  }
139
169
  });
140
170
  timeout = setTimeout(() => finish(null), LOGIN_TIMEOUT_MS);
@@ -161,9 +191,8 @@ export function createOpenAIOAuthLogin(deps) {
161
191
  completeCode: async (input) => {
162
192
  const parsed = parseOAuthCodeInput(input, { allowHashState: true });
163
193
  if (parsed.state && parsed.state !== state) throw new Error('[openai-oauth] OAuth state mismatch');
164
- const tokens = await exchangeAuthorizationCode({ pkce, code: parsed.code });
165
- finish?.(tokens);
166
- return tokens;
194
+ if (!parsed.code) throw new Error('[openai-oauth] authorization code is required');
195
+ return await acceptCode(parsed.code);
167
196
  },
168
197
  cancel: () => {
169
198
  finish?.(null);
@@ -92,6 +92,15 @@ export function identityFromTokens(...tokens) {
92
92
  return normalizeAccountIdentity({ id: [sub, accountId].filter(Boolean).join(':'), email });
93
93
  }
94
94
 
95
+ /** ChatGPT plan (e.g. plus, pro) from the first token carrying the claim, else null. */
96
+ export function planFromTokens(...tokens) {
97
+ for (const token of tokens) {
98
+ const plan = decodeJwtPayload(token)?.['https://api.openai.com/auth']?.chatgpt_plan_type;
99
+ if (typeof plan === 'string' && plan) return plan;
100
+ }
101
+ return null;
102
+ }
103
+
95
104
  /** mtime of the token file, 0 when it is missing or unreadable. */
96
105
  export function tokensFileMtimeMs() {
97
106
  try {
@@ -165,6 +174,7 @@ export function describeOpenAIOAuthCredentials() {
165
174
  ...oauthCredentialStatus({ hasRefresh, expiresAt, detail: source, refreshSkewMs: TOKEN_REFRESH_SKEW_MS }),
166
175
  ...accountIdentityFields(tokens.identity),
167
176
  ...(accountId ? { accountId } : {}),
177
+ plan: planFromTokens(tokens.id_token, tokens.access_token),
168
178
  };
169
179
  } catch (err) {
170
180
  return {
@@ -297,6 +297,7 @@ export async function sendViaWebSocket({
297
297
  onStreamDelta,
298
298
  onToolCall,
299
299
  onTextDelta,
300
+ onStreamItemStart: typeof sendOpts?.onStreamItemStart === 'function' ? sendOpts.onStreamItemStart : null,
300
301
  state: midState,
301
302
  logSuppressedReasoningDeltas,
302
303
  traceProvider,
@@ -0,0 +1,196 @@
1
+ /**
2
+ * openai-ws-connect.mjs — how a Responses WebSocket reaches the server.
3
+ *
4
+ * Every pool handshake is a brand-new TCP+TLS connection (the upgrade detaches
5
+ * it from any HTTP keep-alive pool), so a burst of agents starting together
6
+ * pays one DNS resolution and one full TLS handshake per socket. This module
7
+ * removes the repeated work and the long stall:
8
+ *
9
+ * - lookup: one resolution per host, shared by concurrent handshakes and
10
+ * reused for a short TTL (libuv's small thread pool otherwise queues one
11
+ * getaddrinfo per socket behind unrelated file I/O);
12
+ * - TLS resumption: the latest session ticket per host rides the next
13
+ * connect, so later sockets skip the full key exchange;
14
+ * - hedged open: an upgrade that has not opened within the hedge window
15
+ * gets a parallel replacement attempt instead of waiting out the whole
16
+ * acquire timeout. The first leg to open wins; the rest are cancelled.
17
+ * Server decisions (any HTTP status on the upgrade, e.g. 429/401) end
18
+ * the race at once so backoff stays driven by real server signals.
19
+ */
20
+ import { lookup as dnsLookup } from 'node:dns';
21
+ import net from 'node:net';
22
+ import tls from 'node:tls';
23
+ import { resolveTimeoutMs } from '../stall-policy.mjs';
24
+
25
+ const DNS_TTL_MS = resolveTimeoutMs('MIXDOG_PROVIDER_WS_DNS_TTL_MS', 30_000, { minMs: 1_000, maxMs: 300_000 });
26
+ // Observed production upgrades: p95 ≈ 0.55s, max ≈ 3.4s over 6k handshakes,
27
+ // so a leg still unopened after 3s is almost certainly stuck.
28
+ const WS_HEDGE_MS = resolveTimeoutMs('MIXDOG_PROVIDER_WS_HEDGE_MS', 3_000, { minMs: 500, maxMs: 60_000 });
29
+
30
+ const _dnsCache = new Map();
31
+
32
+ function _lookupKey(hostname, options) {
33
+ return `${hostname}\0${options?.family || 0}\0${options?.hints || 0}`;
34
+ }
35
+
36
+ function _answer(addresses, options, callback) {
37
+ if (options?.all) {
38
+ callback(null, addresses);
39
+ return;
40
+ }
41
+ const first = addresses[0];
42
+ callback(null, first.address, first.family);
43
+ }
44
+
45
+ /** dns.lookup-compatible resolver with in-flight coalescing and a short TTL. */
46
+ export function cachedLookup(hostname, options, callback) {
47
+ const opts = typeof options === 'function' ? {} : typeof options === 'number' ? { family: options } : options || {};
48
+ const cb = typeof options === 'function' ? options : callback;
49
+ const key = _lookupKey(hostname, opts);
50
+ const cached = _dnsCache.get(key);
51
+ if (cached?.addresses && cached.expiresAt > Date.now()) {
52
+ _answer(cached.addresses, opts, cb);
53
+ return;
54
+ }
55
+ if (cached?.waiters) {
56
+ cached.waiters.push({ opts, cb });
57
+ return;
58
+ }
59
+ const record = { waiters: [{ opts, cb }] };
60
+ _dnsCache.set(key, record);
61
+ dnsLookup(hostname, { family: opts.family || 0, hints: opts.hints || 0, all: true }, (err, addresses) => {
62
+ const waiters = record.waiters;
63
+ if (err || !addresses?.length) {
64
+ if (_dnsCache.get(key) === record) _dnsCache.delete(key);
65
+ const failure = err || Object.assign(new Error(`lookup ${hostname} returned no address`), { code: 'ENOTFOUND' });
66
+ for (const waiter of waiters) waiter.cb(failure);
67
+ return;
68
+ }
69
+ _dnsCache.set(key, { addresses, expiresAt: Date.now() + DNS_TTL_MS });
70
+ for (const waiter of waiters) _answer(addresses, waiter.opts, waiter.cb);
71
+ });
72
+ }
73
+
74
+ const _tlsSessions = new Map();
75
+
76
+ /**
77
+ * `ws` createConnection: the shared lookup for every socket, plus TLS
78
+ * resumption for secure ones. Mirrors ws's own servername defaulting.
79
+ */
80
+ export function createWsConnection(options) {
81
+ if (options.protocol === 'ws:' || options.protocol === 'http:') {
82
+ return net.connect({ ...options, path: options.socketPath, lookup: cachedLookup });
83
+ }
84
+ const sessionKey = `${options.host}:${options.port}`;
85
+ const servername =
86
+ options.servername || options.servername === '' ? options.servername : net.isIP(options.host) ? '' : options.host;
87
+ const socket = tls.connect({
88
+ ...options,
89
+ path: undefined,
90
+ servername,
91
+ lookup: cachedLookup,
92
+ session: _tlsSessions.get(sessionKey),
93
+ });
94
+ socket.on('session', (session) => _tlsSessions.set(sessionKey, session));
95
+ return socket;
96
+ }
97
+
98
+ /** Test-only reset of the resolver and TLS session caches. */
99
+ export function _clearConnectCachesForTest() {
100
+ _dnsCache.clear();
101
+ _tlsSessions.clear();
102
+ }
103
+
104
+ function _abortReason(signal, fallback) {
105
+ return signal?.reason instanceof Error ? signal.reason : new Error(fallback);
106
+ }
107
+
108
+ /**
109
+ * Race handshake legs until one opens. `openLeg({ externalSignal })` opens one
110
+ * socket and resolves `{ socket }`. A new leg starts every `hedgeMs` while
111
+ * none has opened and the acquire deadline leaves room; a leg's transport
112
+ * failure only ends the race when nothing else is still connecting.
113
+ */
114
+ export function openHedged({ openLeg, externalSignal, hedgeMs = WS_HEDGE_MS, deadlineMs, deadlineError }) {
115
+ return new Promise((resolve, reject) => {
116
+ const startedAt = Date.now();
117
+ const legs = new Set();
118
+ let settled = false;
119
+ let hedgeTimer = null;
120
+ let deadlineTimer = null;
121
+ let lastError = null;
122
+
123
+ const cleanup = () => {
124
+ if (hedgeTimer) clearTimeout(hedgeTimer);
125
+ if (deadlineTimer) clearTimeout(deadlineTimer);
126
+ externalSignal?.removeEventListener?.('abort', onExternalAbort);
127
+ };
128
+ const cancelLegs = (reason) => {
129
+ for (const leg of legs) leg.abort(reason);
130
+ legs.clear();
131
+ };
132
+ const finish = (ok, value) => {
133
+ if (settled) return;
134
+ settled = true;
135
+ cleanup();
136
+ (ok ? resolve : reject)(value);
137
+ };
138
+ const fail = (err) => {
139
+ cancelLegs(err);
140
+ finish(false, err);
141
+ };
142
+ function onExternalAbort() {
143
+ fail(_abortReason(externalSignal, 'OpenAI WS handshake aborted'));
144
+ }
145
+
146
+ const scheduleHedge = () => {
147
+ if (settled || !(hedgeMs > 0)) return;
148
+ if (Date.now() - startedAt + hedgeMs >= deadlineMs) return;
149
+ hedgeTimer = setTimeout(() => {
150
+ hedgeTimer = null;
151
+ startLeg();
152
+ }, hedgeMs);
153
+ hedgeTimer.unref?.();
154
+ };
155
+
156
+ function startLeg() {
157
+ if (settled) return;
158
+ const controller = new AbortController();
159
+ legs.add(controller);
160
+ Promise.resolve()
161
+ .then(() => openLeg({ externalSignal: controller.signal }))
162
+ .then(
163
+ (opened) => {
164
+ legs.delete(controller);
165
+ if (settled) {
166
+ try {
167
+ opened?.socket?.terminate?.();
168
+ } catch {}
169
+ return;
170
+ }
171
+ cancelLegs(new Error('OpenAI WS handshake superseded by a faster attempt'));
172
+ finish(true, opened);
173
+ },
174
+ (err) => {
175
+ legs.delete(controller);
176
+ if (settled || controller.signal.aborted) return;
177
+ lastError = err;
178
+ // An HTTP status is the server's decision for this request
179
+ // (rate limit, auth, upgrade refusal): surface it unchanged.
180
+ if (err?.httpStatus != null || legs.size === 0) fail(err);
181
+ }
182
+ );
183
+ if (hedgeTimer) clearTimeout(hedgeTimer);
184
+ scheduleHedge();
185
+ }
186
+
187
+ if (externalSignal?.aborted) {
188
+ onExternalAbort();
189
+ return;
190
+ }
191
+ externalSignal?.addEventListener?.('abort', onExternalAbort, { once: true });
192
+ deadlineTimer = setTimeout(() => fail(lastError?.httpStatus != null ? lastError : deadlineError()), deadlineMs);
193
+ deadlineTimer.unref?.();
194
+ startLeg();
195
+ });
196
+ }
@@ -9,6 +9,7 @@
9
9
  import { createHash, randomBytes } from 'node:crypto';
10
10
  import { performance } from 'node:perf_hooks';
11
11
  import { attachHandshakeFailureHandlers, captureHandshakeUpgrade } from './openai-ws-handshake.mjs';
12
+ import { createWsConnection, openHedged } from './openai-ws-connect.mjs';
12
13
  import { codexOriginator, codexUserAgent, codexVersionHeader } from './codex-client-meta.mjs';
13
14
  import {
14
15
  PROVIDER_WS_ACQUIRE_TIMEOUT_MS,
@@ -539,7 +540,26 @@ const WS_URL_BY_AUTH = { xai: XAI_WS_URL, 'openai-direct': OPENAI_WS_URL };
539
540
  /** The auth kind an error label names; anything but xAI/direct is the OAuth (Codex) path. */
540
541
  const _wsAuthKind = (auth) => (auth?.type === 'xai' || auth?.type === 'openai-direct' ? auth.type : 'openai-oauth');
541
542
 
542
- async function _openSocket({ auth, sessionToken, externalSignal, cacheKey, codexHeaders }) {
543
+ function _acquireTimeoutError(auth) {
544
+ return Object.assign(
545
+ new Error(`${_wsErrLabel(_wsAuthKind(auth))} acquire timed out before open (${WS_ACQUIRE_TIMEOUT_MS}ms)`),
546
+ { code: 'EWSACQUIRETIMEOUT', acquireTimeoutMs: WS_ACQUIRE_TIMEOUT_MS }
547
+ );
548
+ }
549
+
550
+ // One acquire = a hedged race of handshake legs under the acquire deadline
551
+ // (openai-ws-connect.mjs): a stuck upgrade is replaced after the hedge window
552
+ // instead of costing the whole timeout plus a retry.
553
+ function _openSocket(args) {
554
+ return openHedged({
555
+ openLeg: ({ externalSignal }) => _openSocketLeg({ ...args, externalSignal }),
556
+ externalSignal: args.externalSignal,
557
+ deadlineMs: WS_ACQUIRE_TIMEOUT_MS,
558
+ deadlineError: () => _acquireTimeoutError(args.auth),
559
+ });
560
+ }
561
+
562
+ async function _openSocketLeg({ auth, sessionToken, externalSignal, cacheKey, codexHeaders }) {
543
563
  // `ws` loads on the first socket, not at runtime boot via provider-admin.
544
564
  const { default: WebSocket } = await import('ws');
545
565
  const headers = _buildHandshakeHeaders({ auth, sessionToken, cacheKey, codexHeaders });
@@ -586,6 +606,7 @@ async function _openSocket({ auth, sessionToken, externalSignal, cacheKey, codex
586
606
  headers,
587
607
  handshakeTimeout: WS_HANDSHAKE_TIMEOUT_MS,
588
608
  maxPayload: WS_MAX_INCOMING_FRAME_BYTES,
609
+ createConnection: createWsConnection,
589
610
  });
590
611
  acquireTimer = setTimeout(() => {
591
612
  if (settled) return;
@@ -597,13 +618,7 @@ async function _openSocket({ auth, sessionToken, externalSignal, cacheKey, codex
597
618
  try {
598
619
  socket.terminate();
599
620
  } catch {}
600
- settle(
601
- false,
602
- Object.assign(
603
- new Error(`${_wsErrLabel(_wsAuthKind(auth))} acquire timed out before open (${WS_ACQUIRE_TIMEOUT_MS}ms)`),
604
- { code: 'EWSACQUIRETIMEOUT', acquireTimeoutMs: WS_ACQUIRE_TIMEOUT_MS }
605
- )
606
- );
621
+ settle(false, _acquireTimeoutError(auth));
607
622
  }, WS_ACQUIRE_TIMEOUT_MS);
608
623
  try {
609
624
  acquireTimer.unref?.();
@@ -764,6 +779,52 @@ function _onEntryClosed(poolKey, entry) {
764
779
  if (!entry.ephemeral) _removeFromPool(poolKey, entry);
765
780
  }
766
781
 
782
+ // Sessionless sends (no poolKey) carry no turn state or response chain of
783
+ // their own, so their connections are shared: one idle bucket per
784
+ // credential + cache key, no owner claim (concurrent sessionless callers
785
+ // each take a different idle socket or open one), and a reused socket starts
786
+ // with an empty chain so no request ever deltas against another caller's
787
+ // response. Without this every sessionless send paid a fresh handshake and
788
+ // closed the socket on release.
789
+ const SHARED_POOL_PREFIX = '\0shared:';
790
+
791
+ function _resetChain(entry) {
792
+ entry.lastResponseId = null;
793
+ entry.lastRequestSansInput = null;
794
+ entry.lastRequestInput = null;
795
+ entry.lastResponseItems = null;
796
+ entry.lastInputLen = 0;
797
+ entry.lastInputPrefixHash = null;
798
+ entry.turnState = null;
799
+ entry.turnStateScope = null;
800
+ entry.turnStateTurnId = null;
801
+ }
802
+
803
+ async function _acquireShared({ auth, cacheKey, codexHeaders, externalSignal, acqStart }) {
804
+ const compatibility = _poolCompatibility(auth, cacheKey);
805
+ const sharedKey = `${SHARED_POOL_PREFIX}${compatibility.authIdentity}:${compatibility.cacheKeyIdentity}`;
806
+ const arr = _wsPool.get(sharedKey) || [];
807
+ _pruneStaleEntries(sharedKey, arr, compatibility);
808
+ const idle = await _takeIdleEntry(sharedKey, arr, compatibility, acqStart);
809
+ if (idle) {
810
+ _resetChain(idle);
811
+ return { entry: idle, reused: true, ownerWaitMs: 0 };
812
+ }
813
+ const entry = await _openPoolEntry({
814
+ auth,
815
+ cacheKey,
816
+ codexHeaders,
817
+ externalSignal,
818
+ compatibility,
819
+ ephemeral: false,
820
+ acqStart,
821
+ });
822
+ entry.sharedPoolKey = sharedKey;
823
+ _getPoolArr(sharedKey).push(entry);
824
+ entry.socket.on('close', () => _onEntryClosed(sharedKey, entry));
825
+ return { entry, reused: false, ownerWaitMs: 0 };
826
+ }
827
+
767
828
  export async function acquireWebSocket({ auth, poolKey, cacheKey, codexHeaders, forceFresh, externalSignal }) {
768
829
  const _acqStart = Date.now();
769
830
  _acquireTrace(
@@ -772,6 +833,9 @@ export async function acquireWebSocket({ auth, poolKey, cacheKey, codexHeaders,
772
833
  if (externalSignal?.aborted) {
773
834
  throw _acquireAbortError(externalSignal);
774
835
  }
836
+ if (!poolKey && !forceFresh) {
837
+ return _acquireShared({ auth, cacheKey, codexHeaders, externalSignal, acqStart: _acqStart });
838
+ }
775
839
  const ownerClaim = await _claimPoolOwner(poolKey, externalSignal);
776
840
  const acquired = (entry, reused) => {
777
841
  _bindPoolOwner(poolKey, ownerClaim, entry);
@@ -825,8 +889,9 @@ export async function acquireWebSocket({ auth, poolKey, cacheKey, codexHeaders,
825
889
  }
826
890
  }
827
891
 
828
- export function releaseWebSocket({ entry, poolKey, keep }) {
892
+ export function releaseWebSocket({ entry, poolKey: callerPoolKey, keep }) {
829
893
  if (!entry) return;
894
+ const poolKey = callerPoolKey || entry.sharedPoolKey || null;
830
895
  entry.busy = false;
831
896
  if (!keep || !_isOpen(entry) || !poolKey || entry.ephemeral) {
832
897
  try {
@@ -1,9 +1,19 @@
1
1
  import { performance } from 'node:perf_hooks';
2
+ import { reportStreamItemStart, responsesItemStart } from '../lib/send-callbacks.mjs';
2
3
 
3
4
  // The per-event fold: text/reasoning/tool deltas and item lifecycle feed the
4
5
  // response state, the text relay and the semantic watchdog; terminal frames
5
6
  // route to the terminal-frame handlers.
6
- export function createWsEventSwitch({ response, textRelay, watchdogs, midState, progress, terminal, streamingStart }) {
7
+ export function createWsEventSwitch({
8
+ response,
9
+ textRelay,
10
+ watchdogs,
11
+ midState,
12
+ progress,
13
+ terminal,
14
+ streamingStart,
15
+ onStreamItemStart = null,
16
+ }) {
7
17
  let firstDeltaEmitted = false;
8
18
 
9
19
  function onResponseCreated(event) {
@@ -73,6 +83,7 @@ export function createWsEventSwitch({ response, textRelay, watchdogs, midState,
73
83
  break;
74
84
  case 'response.output_item.added':
75
85
  response.noteItemAdded(event.item);
86
+ reportStreamItemStart(onStreamItemStart, responsesItemStart(event.item));
76
87
  // Item lifecycle is genuine progress: reset the semantic-idle timer so
77
88
  // long server-side tool latency after item-added (before any arg
78
89
  // delta) is not mistaken for a silent stall.
@@ -102,6 +113,8 @@ export function createWsEventSwitch({ response, textRelay, watchdogs, midState,
102
113
  break;
103
114
  case 'response.output_item.done': {
104
115
  const kind = response.completeOutputItem(event.item);
116
+ // A stream that names the phase only on the finished message.
117
+ if (event.item?.type === 'message') reportStreamItemStart(onStreamItemStart, responsesItemStart(event.item));
105
118
  // Item-done is genuine lifecycle progress — reset semantic idle so
106
119
  // latency before the next item/args does not stall.
107
120
  watchdogs.resetSemantic();
@@ -96,6 +96,7 @@ export async function _streamResponse({
96
96
  onStreamDelta,
97
97
  onToolCall,
98
98
  onTextDelta,
99
+ onStreamItemStart = null,
99
100
  state,
100
101
  logSuppressedReasoningDeltas = true,
101
102
  traceProvider = 'openai-oauth',
@@ -236,6 +237,7 @@ export async function _streamResponse({
236
237
  progress,
237
238
  terminal,
238
239
  streamingStart,
240
+ onStreamItemStart,
239
241
  });
240
242
  handlers = createSocketHandlers({
241
243
  socket,