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
@@ -0,0 +1,194 @@
1
+ // OpenCode Go login: OAuth device authorization against the OpenCode Console
2
+ // (JSON bodies, client `opencode-cli`), then the account and the organization
3
+ // the token acts for.
4
+ import { openLoginUrl } from './lib/open-login-url.mjs';
5
+ import { scrubOAuthSecrets } from './lib/oauth-token-utils.mjs';
6
+ import {
7
+ CLIENT_ID,
8
+ DEVICE_CODE_URL,
9
+ DEVICE_TOKEN_URL,
10
+ ORGS_URL,
11
+ PROVIDER_ID,
12
+ SERVER,
13
+ USER_URL,
14
+ consoleGetJson,
15
+ consoleRequest,
16
+ openCodeGoError,
17
+ saveTokens,
18
+ tokenFieldsFromGrant,
19
+ } from './opencode-go-oauth-tokens.mjs';
20
+
21
+ const DEVICE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';
22
+ const DEFAULT_INTERVAL_S = 5;
23
+ const SLOW_DOWN_STEP_S = 5;
24
+ const MAX_TRANSIENT_FAILURES = 3;
25
+
26
+ const cancelled = () => openCodeGoError(`[${PROVIDER_ID}] login cancelled`, { kind: 'cancelled', cancelled: true });
27
+
28
+ export const defaultSleep = (ms, signal) =>
29
+ new Promise((resolve, reject) => {
30
+ if (signal?.aborted) return reject(cancelled());
31
+ const onAbort = () => {
32
+ clearTimeout(timer);
33
+ reject(cancelled());
34
+ };
35
+ const timer = setTimeout(() => {
36
+ signal?.removeEventListener('abort', onAbort);
37
+ resolve();
38
+ }, ms);
39
+ signal?.addEventListener('abort', onAbort, { once: true });
40
+ });
41
+
42
+ /** The device code request; the verification URL is resolved against the Console. */
43
+ export async function requestDeviceCode({ fetchFn = fetch, signal } = {}) {
44
+ const { res, json, text } = await consoleRequest(DEVICE_CODE_URL, {
45
+ method: 'POST',
46
+ body: { client_id: CLIENT_ID },
47
+ fetchFn,
48
+ signal,
49
+ });
50
+ if (!res.ok) {
51
+ throw openCodeGoError(
52
+ `[${PROVIDER_ID}] device authorization ${res.status}: ${scrubOAuthSecrets(text).slice(0, 300)}`,
53
+ {
54
+ kind: 'device-auth',
55
+ status: res.status,
56
+ }
57
+ );
58
+ }
59
+ const deviceCode = typeof json?.device_code === 'string' ? json.device_code : '';
60
+ const userCode = typeof json?.user_code === 'string' ? json.user_code : '';
61
+ const verification = typeof json?.verification_uri_complete === 'string' ? json.verification_uri_complete : '';
62
+ if (!deviceCode || !userCode || !verification) {
63
+ throw openCodeGoError(`[${PROVIDER_ID}] device authorization response is missing required fields`, {
64
+ kind: 'validation',
65
+ });
66
+ }
67
+ const url = new URL(verification, `${SERVER}/`);
68
+ if (url.protocol !== 'https:' && url.protocol !== 'http:') {
69
+ throw openCodeGoError(`[${PROVIDER_ID}] device verification URL is not HTTP(S)`, { kind: 'validation' });
70
+ }
71
+ const interval = Number(json.interval);
72
+ const expiresIn = Number(json.expires_in);
73
+ return {
74
+ deviceCode,
75
+ userCode,
76
+ verificationUrl: url.href,
77
+ intervalS: Number.isFinite(interval) && interval > 0 ? interval : DEFAULT_INTERVAL_S,
78
+ expiresInS: Number.isFinite(expiresIn) && expiresIn > 0 ? expiresIn : null,
79
+ };
80
+ }
81
+
82
+ /** Poll until approval, denial or expiry; resolves the token fields of the grant. */
83
+ export async function pollDeviceToken(device, { fetchFn = fetch, signal, sleep = defaultSleep, now = Date.now } = {}) {
84
+ const expired = () =>
85
+ openCodeGoError(`[${PROVIDER_ID}] device code expired — start the login again`, {
86
+ kind: 'device-token',
87
+ code: 'expired_token',
88
+ });
89
+ const deadline = device.expiresInS ? now() + device.expiresInS * 1000 : Number.POSITIVE_INFINITY;
90
+ let intervalMs = device.intervalS * 1000;
91
+ let failures = 0;
92
+ while (now() < deadline) {
93
+ if (signal?.aborted) throw cancelled();
94
+ let reply;
95
+ try {
96
+ reply = await consoleRequest(DEVICE_TOKEN_URL, {
97
+ method: 'POST',
98
+ body: { grant_type: DEVICE_GRANT_TYPE, device_code: device.deviceCode, client_id: CLIENT_ID },
99
+ fetchFn,
100
+ signal,
101
+ });
102
+ } catch (err) {
103
+ if (signal?.aborted) throw cancelled();
104
+ if (++failures > MAX_TRANSIENT_FAILURES) throw err;
105
+ await sleep(Math.min(intervalMs, Math.max(0, deadline - now())), signal);
106
+ continue;
107
+ }
108
+ const { res, json, text } = reply;
109
+ const error = typeof json?.error === 'string' ? json.error : '';
110
+ if (res.ok && !error && json?.access_token) return tokenFieldsFromGrant(json, now());
111
+ if (error === 'authorization_pending') {
112
+ failures = 0;
113
+ } else if (error === 'slow_down') {
114
+ failures = 0;
115
+ intervalMs += SLOW_DOWN_STEP_S * 1000;
116
+ } else if (error === 'expired_token') {
117
+ throw expired();
118
+ } else if (error === 'access_denied') {
119
+ throw openCodeGoError(`[${PROVIDER_ID}] sign-in was denied`, { kind: 'device-token', code: 'access_denied' });
120
+ } else if (!error && res.status >= 500 && ++failures <= MAX_TRANSIENT_FAILURES) {
121
+ /* transient gateway failure: poll again */
122
+ } else {
123
+ const detail = error || scrubOAuthSecrets(text, [device.deviceCode]).slice(0, 300);
124
+ throw openCodeGoError(`[${PROVIDER_ID}] device token ${res.status}: ${detail}`, {
125
+ kind: 'device-token',
126
+ status: res.status,
127
+ ...(error ? { code: error } : {}),
128
+ });
129
+ }
130
+ const left = deadline - now();
131
+ if (left <= 0) break;
132
+ await sleep(Math.min(intervalMs, left), signal);
133
+ }
134
+ throw expired();
135
+ }
136
+
137
+ /** The organization the login acts for: the grant's own, else the first by name (as opencode picks). */
138
+ export function pickOrganization(orgs, orgId = '') {
139
+ const list = (Array.isArray(orgs) ? orgs : []).filter((org) => typeof org?.id === 'string' && org.id);
140
+ if (orgId) {
141
+ const match = list.find((org) => org.id === orgId);
142
+ if (!match)
143
+ throw openCodeGoError(`[${PROVIDER_ID}] OpenCode organization not found: ${orgId}`, { kind: 'validation' });
144
+ return match;
145
+ }
146
+ return (
147
+ [...list].sort((a, b) => String(a.name || '').localeCompare(String(b.name || '')) || a.id.localeCompare(b.id))[0] ||
148
+ null
149
+ );
150
+ }
151
+
152
+ /** Read the account and organization for a fresh grant and persist the credential. */
153
+ export async function completeLogin(granted, { fetchFn = fetch, signal } = {}) {
154
+ const [user, orgs] = await Promise.all([
155
+ consoleGetJson(USER_URL, granted, { fetchFn, signal }),
156
+ consoleGetJson(ORGS_URL, granted, { fetchFn, signal }),
157
+ ]);
158
+ const org = pickOrganization(orgs, granted.org_id);
159
+ if (!org) throw openCodeGoError(`[${PROVIDER_ID}] the OpenCode account has no organization`, { kind: 'validation' });
160
+ return saveTokens({
161
+ ...granted,
162
+ account_id: typeof user?.id === 'string' ? user.id : '',
163
+ email: typeof user?.email === 'string' ? user.email.trim().toLowerCase() : '',
164
+ org_id: org.id,
165
+ org_name: typeof org.name === 'string' ? org.name : '',
166
+ });
167
+ }
168
+
169
+ export async function beginOAuthLogin({ openBrowser = true, fetchFn = fetch, sleep, now } = {}) {
170
+ const controller = new AbortController();
171
+ const device = await requestDeviceCode({ fetchFn, signal: controller.signal });
172
+ process.stderr.write(
173
+ `\n[${PROVIDER_ID}] Enter code: ${device.userCode}\n[${PROVIDER_ID}] Open: ${device.verificationUrl}\n\n`
174
+ );
175
+ if (openBrowser) await openLoginUrl(PROVIDER_ID, device.verificationUrl);
176
+ const waitForCallback = pollDeviceToken(device, { fetchFn, signal: controller.signal, sleep, now }).then((granted) =>
177
+ completeLogin(granted, { fetchFn, signal: controller.signal })
178
+ );
179
+ // A cancelled flow rejects before some hosts attach a listener.
180
+ waitForCallback.catch(() => {});
181
+ return {
182
+ provider: PROVIDER_ID,
183
+ url: device.verificationUrl,
184
+ manualUrl: null,
185
+ userCode: device.userCode,
186
+ waitForCallback,
187
+ cancel: () => controller.abort(new Error('OpenCode Go login cancelled')),
188
+ };
189
+ }
190
+
191
+ export async function loginOAuth() {
192
+ const login = await beginOAuthLogin();
193
+ return await login.waitForCallback;
194
+ }
@@ -0,0 +1,353 @@
1
+ // OpenCode Go OAuth credentials: an OpenCode Console device-flow login
2
+ // (client `opencode-cli`) yields a refreshable access token bound to one
3
+ // Console organization. The token reads the organization's remote config
4
+ // (`/api/v2/config`), whose `opencode-go` provider names the inference base
5
+ // URL, the request headers and the model catalog, and the Go usage meters
6
+ // (`/api/go/status`). Stored in Mixdog's own opencode-go-oauth.json, one file
7
+ // per connected account.
8
+ import { readFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
9
+ import { join, resolve } from 'node:path';
10
+ import { getPluginData } from '../config.mjs';
11
+ import {
12
+ updateJsonAtomicSync,
13
+ withFileLock,
14
+ withFileLockSync,
15
+ writeJsonAtomicSync,
16
+ } from '../../../shared/atomic-file.mjs';
17
+ import { boundProviderAuthPath } from '../../../shared/provider-auth-binding.mjs';
18
+ import { getLlmDispatcher } from '../../../shared/llm/http-agent.mjs';
19
+ import { modelProxyClientMode, serverModelCredentialsDisabledError } from '../../../shared/model-proxy-mode.mjs';
20
+ import {
21
+ accountIdentityFields,
22
+ fileMtimeMs,
23
+ oauthCredentialStatus,
24
+ scrubOAuthSecrets,
25
+ } from './lib/oauth-token-utils.mjs';
26
+
27
+ export const PROVIDER_ID = 'opencode-go-oauth';
28
+ export const SERVER = 'https://opencode.ai/console';
29
+ export const CLIENT_ID = 'opencode-cli';
30
+ export const DEVICE_CODE_URL = `${SERVER}/auth/device/code`;
31
+ export const DEVICE_TOKEN_URL = `${SERVER}/auth/device/token`;
32
+ export const USER_URL = `${SERVER}/api/user`;
33
+ export const ORGS_URL = `${SERVER}/api/orgs`;
34
+ export const CONFIG_URL = `${SERVER}/api/v2/config`;
35
+ export const STATUS_URL = `${SERVER}/api/go/status`;
36
+ // The remote config's provider entry this login serves (`opencode` is Zen).
37
+ export const CONFIG_PROVIDER_KEY = 'opencode-go';
38
+ // Used only when the remote config names no base URL.
39
+ export const FALLBACK_BASE_URL = 'https://opencode.ai/inference/go/openai/v1';
40
+ export const TOKEN_REFRESH_SKEW_MS = 5 * 60_000;
41
+ export const REQUEST_TIMEOUT_MS = 20_000;
42
+ const USER_AGENT = 'mixdog';
43
+
44
+ export function getOwnTokenPath() {
45
+ const bound = boundProviderAuthPath(PROVIDER_ID);
46
+ if (bound) return resolve(bound);
47
+ const explicit = process.env.OPENCODE_GO_OAUTH_CREDENTIALS_PATH;
48
+ if (explicit) return resolve(explicit);
49
+ const dir = getPluginData();
50
+ if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
51
+ return join(dir, 'opencode-go-oauth.json');
52
+ }
53
+
54
+ const text = (value) => (typeof value === 'string' ? value.trim() : '');
55
+
56
+ export const isValidOpenCodeGoCredentialDocument = (doc) =>
57
+ Boolean(text(doc?.access_token) && text(doc?.refresh_token));
58
+
59
+ export function openCodeGoError(message, meta = {}) {
60
+ return Object.assign(new Error(message), meta);
61
+ }
62
+
63
+ export function openCodeGoReauthError(detail, status = 401) {
64
+ return openCodeGoError(
65
+ `[${PROVIDER_ID}] invalid_grant: OpenCode sign-in expired${detail ? ` (${detail})` : ''} — open /providers in mixdog to sign in again`,
66
+ { status, reauthRequired: true, kind: 'reauth' }
67
+ );
68
+ }
69
+
70
+ export function loadTokens() {
71
+ if (modelProxyClientMode()) return null;
72
+ const path = getOwnTokenPath();
73
+ if (!existsSync(path)) return null;
74
+ try {
75
+ const raw = JSON.parse(readFileSync(path, 'utf-8'));
76
+ if (!isValidOpenCodeGoCredentialDocument(raw)) return null;
77
+ return {
78
+ access_token: raw.access_token,
79
+ refresh_token: raw.refresh_token,
80
+ expires_at: Number(raw.expires_at) || 0,
81
+ account_id: text(raw.account_id),
82
+ email: text(raw.email),
83
+ org_id: text(raw.org_id),
84
+ org_name: text(raw.org_name),
85
+ mtimeMs: fileMtimeMs(path),
86
+ };
87
+ } catch {
88
+ return null;
89
+ }
90
+ }
91
+
92
+ const tokenDocument = (tokens) => ({
93
+ access_token: tokens.access_token,
94
+ refresh_token: tokens.refresh_token,
95
+ expires_at: Number(tokens.expires_at) || 0,
96
+ ...(text(tokens.account_id) ? { account_id: text(tokens.account_id) } : {}),
97
+ ...(text(tokens.email) ? { email: text(tokens.email) } : {}),
98
+ ...(text(tokens.org_id) ? { org_id: text(tokens.org_id) } : {}),
99
+ ...(text(tokens.org_name) ? { org_name: text(tokens.org_name) } : {}),
100
+ });
101
+
102
+ export function saveTokens(tokens) {
103
+ const doc = tokenDocument(tokens);
104
+ writeJsonAtomicSync(getOwnTokenPath(), doc, { lock: true, fsyncDir: true, mode: 0o600, secret: true });
105
+ return { ...doc, mtimeMs: fileMtimeMs(getOwnTokenPath()) };
106
+ }
107
+
108
+ // Stores `tokens` only over the very credential `previous` was read from,
109
+ // compared under the store's write lock: a sign-in that replaced it, or a
110
+ // sign-out that removed it, meanwhile is kept and the stored state returned.
111
+ function replaceTokens(previous, tokens) {
112
+ const path = getOwnTokenPath();
113
+ const doc = tokenDocument(tokens);
114
+ let replaced = false;
115
+ updateJsonAtomicSync(
116
+ path,
117
+ (current) => {
118
+ if (current?.access_token !== previous.access_token || current?.refresh_token !== previous.refresh_token) {
119
+ return undefined;
120
+ }
121
+ replaced = true;
122
+ return doc;
123
+ },
124
+ { fsyncDir: true, mode: 0o600, secret: true }
125
+ );
126
+ if (replaced) return { ...doc, mtimeMs: fileMtimeMs(path) };
127
+ const current = loadTokens();
128
+ if (!current) throw openCodeGoReauthError('credentials removed');
129
+ return current;
130
+ }
131
+
132
+ export function hasOpenCodeGoOAuthCredentials() {
133
+ try {
134
+ return Boolean(loadTokens());
135
+ } catch {
136
+ return false;
137
+ }
138
+ }
139
+
140
+ export function describeOpenCodeGoOAuthCredentials() {
141
+ try {
142
+ const tokens = loadTokens();
143
+ if (!tokens) {
144
+ return {
145
+ authenticated: false,
146
+ usable: false,
147
+ refreshable: false,
148
+ reauthRequired: false,
149
+ status: 'Not Set',
150
+ detail: 'Mixdog token store',
151
+ };
152
+ }
153
+ return {
154
+ ...oauthCredentialStatus({
155
+ hasRefresh: true,
156
+ expiresAt: tokens.expires_at,
157
+ detail: tokens.org_name ? `OpenCode Console · ${tokens.org_name}` : 'OpenCode Console',
158
+ refreshSkewMs: TOKEN_REFRESH_SKEW_MS,
159
+ }),
160
+ ...accountIdentityFields({ id: tokens.account_id, email: tokens.email }),
161
+ ...(tokens.org_id ? { orgId: tokens.org_id } : {}),
162
+ ...(tokens.org_name ? { orgName: tokens.org_name } : {}),
163
+ };
164
+ } catch (err) {
165
+ return {
166
+ authenticated: false,
167
+ usable: false,
168
+ refreshable: false,
169
+ reauthRequired: false,
170
+ status: 'Error',
171
+ detail: String(err?.message || err).slice(0, 200),
172
+ };
173
+ }
174
+ }
175
+
176
+ export function forgetOpenCodeGoOAuthCredentials() {
177
+ const path = getOwnTokenPath();
178
+ // Under the store's write lock, so a refresh finishing now cannot restore it.
179
+ return withFileLockSync(
180
+ `${path}.lock`,
181
+ () => {
182
+ if (!existsSync(path)) return { removed: false };
183
+ unlinkSync(path);
184
+ return { removed: true };
185
+ },
186
+ { secret: true }
187
+ );
188
+ }
189
+
190
+ /** Console bearer headers: the access token plus the organization it acts for. */
191
+ export function consoleHeaders(tokens) {
192
+ return {
193
+ Authorization: `Bearer ${tokens.access_token}`,
194
+ ...(tokens.org_id ? { 'x-org-id': tokens.org_id } : {}),
195
+ };
196
+ }
197
+
198
+ /**
199
+ * One JSON request to the Console. Never follows a redirect (the request
200
+ * carries a token); resolves `{ res, json, text }` whatever the status.
201
+ */
202
+ export async function consoleRequest(url, { method = 'GET', headers = {}, body, fetchFn = fetch, signal } = {}) {
203
+ const timeout = AbortSignal.timeout(REQUEST_TIMEOUT_MS);
204
+ const res = await fetchFn(url, {
205
+ method,
206
+ headers: {
207
+ Accept: 'application/json',
208
+ 'User-Agent': USER_AGENT,
209
+ ...(body !== undefined ? { 'Content-Type': 'application/json' } : {}),
210
+ ...headers,
211
+ },
212
+ ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
213
+ redirect: 'error',
214
+ signal: signal ? AbortSignal.any([signal, timeout]) : timeout,
215
+ dispatcher: getLlmDispatcher(),
216
+ });
217
+ const textBody = await res.text();
218
+ let json = null;
219
+ try {
220
+ json = textBody ? JSON.parse(textBody) : null;
221
+ } catch {
222
+ /* non-JSON body: callers report the status */
223
+ }
224
+ return { res, json, text: textBody };
225
+ }
226
+
227
+ /**
228
+ * Authenticated Console GET; a 401 is a reauth error, any other failure
229
+ * carries its status. `refresh` (a stored credential's read) first refreshes
230
+ * once and retries (withConsoleTokenRetry); a login's fresh grant, not yet
231
+ * stored, has nothing to refresh.
232
+ */
233
+ export async function consoleGetJson(url, tokens, { fetchFn, signal, refresh = false } = {}) {
234
+ if (refresh) {
235
+ return await withConsoleTokenRetry(tokens, (current) => consoleGetJson(url, current, { fetchFn, signal }), {
236
+ fetchFn,
237
+ });
238
+ }
239
+ const { res, json, text: body } = await consoleRequest(url, { headers: consoleHeaders(tokens), fetchFn, signal });
240
+ if (res.status === 401) throw openCodeGoReauthError(`${new URL(url).pathname} 401`);
241
+ if (!res.ok || json === null) {
242
+ const detail = scrubOAuthSecrets(body, [tokens.access_token, tokens.refresh_token]).trim().slice(0, 300);
243
+ throw openCodeGoError(`[${PROVIDER_ID}] ${new URL(url).pathname} ${res.status}${detail ? `: ${detail}` : ''}`, {
244
+ status: res.status,
245
+ });
246
+ }
247
+ return json;
248
+ }
249
+
250
+ /** Token fields from a device/refresh grant response (`expires_in` seconds). */
251
+ export function tokenFieldsFromGrant(json, now = Date.now()) {
252
+ const access = text(json?.access_token);
253
+ const refresh = text(json?.refresh_token);
254
+ if (!access || !refresh) {
255
+ throw openCodeGoError(`[${PROVIDER_ID}] token response is missing access_token or refresh_token`, {
256
+ kind: 'validation',
257
+ });
258
+ }
259
+ const expiresIn = Number(json?.expires_in);
260
+ return {
261
+ access_token: access,
262
+ refresh_token: refresh,
263
+ expires_at: Number.isFinite(expiresIn) && expiresIn > 0 ? now + expiresIn * 1000 : 0,
264
+ ...(text(json?.org_id) ? { org_id: text(json.org_id) } : {}),
265
+ };
266
+ }
267
+
268
+ async function postRefresh(tokens, { fetchFn } = {}) {
269
+ const {
270
+ res,
271
+ json,
272
+ text: body,
273
+ } = await consoleRequest(DEVICE_TOKEN_URL, {
274
+ method: 'POST',
275
+ body: { grant_type: 'refresh_token', refresh_token: tokens.refresh_token, client_id: CLIENT_ID },
276
+ fetchFn,
277
+ });
278
+ if (!res.ok) {
279
+ const oauthError = text(json?.error).toLowerCase();
280
+ if (oauthError === 'invalid_grant' || res.status === 401)
281
+ throw openCodeGoReauthError('refresh rejected', res.status);
282
+ const detail = scrubOAuthSecrets(body, [tokens.access_token, tokens.refresh_token]).trim().slice(0, 200);
283
+ throw openCodeGoError(`[${PROVIDER_ID}] token refresh ${res.status}${detail ? `: ${detail}` : ''}`, {
284
+ status: res.status,
285
+ });
286
+ }
287
+ const granted = tokenFieldsFromGrant(json);
288
+ // A grant naming another organization moves the account to it; its name is
289
+ // then unknown until the next sign-in.
290
+ const orgChanged = granted.org_id && granted.org_id !== tokens.org_id;
291
+ return replaceTokens(tokens, {
292
+ ...tokens,
293
+ ...granted,
294
+ org_id: granted.org_id || tokens.org_id,
295
+ org_name: orgChanged ? granted.org_id : tokens.org_name,
296
+ });
297
+ }
298
+
299
+ /**
300
+ * Refresh under a cross-process lease: a waiter that finds a newer generation
301
+ * on disk adopts it instead of spending the refresh token again.
302
+ */
303
+ export async function refreshTokens(tokens, { force = false, fetchFn } = {}) {
304
+ if (modelProxyClientMode()) throw serverModelCredentialsDisabledError('OpenCode Go OAuth credentials');
305
+ return withFileLock(
306
+ `${getOwnTokenPath()}.refresh.lock`,
307
+ async () => {
308
+ const disk = loadTokens();
309
+ if (!disk) throw openCodeGoReauthError('credentials removed');
310
+ const validAfter = Date.now() + (force ? 0 : TOKEN_REFRESH_SKEW_MS);
311
+ const rotated = disk.access_token !== tokens.access_token || disk.refresh_token !== tokens.refresh_token;
312
+ if (rotated && (!disk.expires_at || disk.expires_at >= validAfter)) return disk;
313
+ return await postRefresh(disk, { fetchFn });
314
+ },
315
+ { timeoutMs: 60_000, staleMs: 60_000, secret: true }
316
+ );
317
+ }
318
+
319
+ /**
320
+ * An authenticated Console read of the stored credential that outlives one
321
+ * stale access token: a 401 refreshes once (a newer stored generation is
322
+ * adopted instead of spending the refresh token again) and reads again. Only
323
+ * a second 401, or a refresh the server rejects, asks for a new sign-in.
324
+ */
325
+ export async function withConsoleTokenRetry(tokens, read, { fetchFn } = {}) {
326
+ try {
327
+ return await read(tokens);
328
+ } catch (err) {
329
+ if (Number(err?.status) !== 401) throw err;
330
+ }
331
+ const next = await refreshTokens(tokens, { force: true, fetchFn });
332
+ if (next.account_id !== tokens.account_id || next.org_id !== tokens.org_id) {
333
+ throw openCodeGoError(`[${PROVIDER_ID}] the OpenCode sign-in changed during the request`, { kind: 'superseded' });
334
+ }
335
+ try {
336
+ return await read(next);
337
+ } catch (err) {
338
+ if (Number(err?.status) === 401 && !err.reauthRequired) throw openCodeGoReauthError('console 401');
339
+ throw err;
340
+ }
341
+ }
342
+
343
+ /** The stored credential, refreshed when it is about to expire (or `force`). */
344
+ export async function ensureFreshTokens({ force = false, fetchFn } = {}) {
345
+ const tokens = loadTokens();
346
+ if (!tokens) {
347
+ throw openCodeGoError(`[${PROVIDER_ID}] credentials not found — open /providers in mixdog to sign in first`, {
348
+ status: 401,
349
+ });
350
+ }
351
+ const expiring = tokens.expires_at > 0 && tokens.expires_at < Date.now() + TOKEN_REFRESH_SKEW_MS;
352
+ return force || expiring ? await refreshTokens(tokens, { force, fetchFn }) : tokens;
353
+ }