mixdog 0.9.2 → 0.9.4

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 (417) hide show
  1. package/package.json +8 -3
  2. package/scripts/anthropic-maxtokens-test.mjs +119 -0
  3. package/scripts/bench/lead-review-tasks-r3.json +20 -0
  4. package/scripts/bench/lead-review-tasks.json +20 -0
  5. package/scripts/bench/r4-mixed-tasks.json +20 -0
  6. package/scripts/bench/review-tasks.json +20 -0
  7. package/scripts/bench/round-codex.json +114 -0
  8. package/scripts/bench/round-mixdog-lead-r3.json +269 -0
  9. package/scripts/bench/round-mixdog-lead.json +269 -0
  10. package/scripts/bench/round-mixdog.json +126 -0
  11. package/scripts/bench/round-r10-bigsample.json +679 -0
  12. package/scripts/bench/round-r11-codexalign.json +257 -0
  13. package/scripts/bench/round-r4-codex.json +114 -0
  14. package/scripts/bench/round-r4-mixed.json +225 -0
  15. package/scripts/bench/round-r5-gpt-lead.json +259 -0
  16. package/scripts/bench/round-r6-codex.json +114 -0
  17. package/scripts/bench/round-r6-solo.json +257 -0
  18. package/scripts/bench/round-r7-full.json +254 -0
  19. package/scripts/bench/round-r8-fulldefault.json +255 -0
  20. package/scripts/bench-run.mjs +215 -29
  21. package/scripts/build-tui.mjs +13 -1
  22. package/scripts/explore-bench.mjs +124 -0
  23. package/scripts/freevar-smoke.mjs +95 -0
  24. package/scripts/hook-bus-test.mjs +191 -0
  25. package/scripts/internal-comms-bench.mjs +1 -0
  26. package/scripts/internal-comms-smoke.mjs +10 -9
  27. package/scripts/mouse-probe.mjs +45 -0
  28. package/scripts/output-style-bench.mjs +13 -6
  29. package/scripts/output-style-smoke.mjs +4 -4
  30. package/scripts/path-suffix-test.mjs +57 -0
  31. package/scripts/provider-toolcall-test.mjs +7 -3
  32. package/scripts/recall-bench.mjs +207 -0
  33. package/scripts/recall-usecase-cases.json +18 -0
  34. package/scripts/recall-usecase-probe.json +6 -0
  35. package/scripts/session-bench.mjs +152 -6
  36. package/scripts/tool-smoke.mjs +30 -67
  37. package/scripts/tui-render-smoke.mjs +90 -0
  38. package/scripts/webhook-smoke.mjs +208 -0
  39. package/src/agents/debugger/AGENT.md +5 -2
  40. package/src/agents/heavy-worker/AGENT.md +21 -11
  41. package/src/agents/maintainer/AGENT.md +4 -0
  42. package/src/agents/reviewer/AGENT.md +3 -2
  43. package/src/agents/worker/AGENT.md +21 -11
  44. package/src/lib/rules-builder.cjs +4 -0
  45. package/src/mixdog-session-runtime.mjs +933 -3731
  46. package/src/output-styles/default.md +34 -9
  47. package/src/output-styles/{oneline.md → extreme-minimal.md} +5 -4
  48. package/src/output-styles/minimal.md +4 -1
  49. package/src/output-styles/simple.md +22 -7
  50. package/src/repl.mjs +5 -5
  51. package/src/rules/agent/00-common.md +2 -0
  52. package/src/rules/agent/30-explorer.md +8 -11
  53. package/src/rules/lead/lead-brief.md +12 -0
  54. package/src/rules/lead/lead-tool.md +2 -9
  55. package/src/rules/shared/01-tool.md +11 -5
  56. package/src/runtime/agent/orchestrator/agent-runtime/agent-loop-policy.mjs +25 -0
  57. package/src/runtime/agent/orchestrator/agent-runtime/cache-strategy.mjs +100 -23
  58. package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +6 -15
  59. package/src/runtime/agent/orchestrator/agent-trace-format.mjs +362 -0
  60. package/src/runtime/agent/orchestrator/agent-trace-io.mjs +410 -0
  61. package/src/runtime/agent/orchestrator/agent-trace.mjs +16 -735
  62. package/src/runtime/agent/orchestrator/config.mjs +69 -2
  63. package/src/runtime/agent/orchestrator/context/collect.mjs +51 -0
  64. package/src/runtime/agent/orchestrator/mcp/client.mjs +6 -2
  65. package/src/runtime/agent/orchestrator/providers/anthropic-effort.mjs +63 -21
  66. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +93 -0
  67. package/src/runtime/agent/orchestrator/providers/anthropic-model-resolve.mjs +209 -0
  68. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-credentials.mjs +489 -0
  69. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +97 -1343
  70. package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +607 -0
  71. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +78 -10
  72. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +1 -13
  73. package/src/runtime/agent/orchestrator/providers/codex-client-meta.mjs +81 -0
  74. package/src/runtime/agent/orchestrator/providers/gemini-cache.mjs +248 -0
  75. package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +303 -0
  76. package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +505 -0
  77. package/src/runtime/agent/orchestrator/providers/gemini.mjs +44 -1014
  78. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +18 -4
  79. package/src/runtime/agent/orchestrator/providers/lib/usage-primitives.mjs +32 -0
  80. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +86 -11
  81. package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +348 -0
  82. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +54 -20
  83. package/src/runtime/agent/orchestrator/providers/openai-codex-model.mjs +108 -0
  84. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +19 -12
  85. package/src/runtime/agent/orchestrator/providers/openai-compat-trace.mjs +58 -0
  86. package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +368 -0
  87. package/src/runtime/agent/orchestrator/providers/openai-compat-xai.mjs +760 -0
  88. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +41 -1142
  89. package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +732 -0
  90. package/src/runtime/agent/orchestrator/providers/openai-oauth-login.mjs +193 -0
  91. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +303 -2119
  92. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +140 -995
  93. package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +227 -0
  94. package/src/runtime/agent/orchestrator/providers/openai-ws-events.mjs +67 -0
  95. package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +436 -0
  96. package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +1105 -0
  97. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +2 -1
  98. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +38 -12
  99. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +7 -8
  100. package/src/runtime/agent/orchestrator/session/compact/budget.mjs +288 -0
  101. package/src/runtime/agent/orchestrator/session/compact/constants.mjs +85 -0
  102. package/src/runtime/agent/orchestrator/session/compact/engine.mjs +749 -0
  103. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +82 -0
  104. package/src/runtime/agent/orchestrator/session/compact/summary-schema.mjs +315 -0
  105. package/src/runtime/agent/orchestrator/session/compact/summary.mjs +643 -0
  106. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +326 -0
  107. package/src/runtime/agent/orchestrator/session/compact.mjs +40 -2282
  108. package/src/runtime/agent/orchestrator/session/loop/compact-debug.mjs +28 -0
  109. package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +274 -0
  110. package/src/runtime/agent/orchestrator/session/loop/completion-guards.mjs +61 -0
  111. package/src/runtime/agent/orchestrator/session/loop/context-overflow.mjs +38 -0
  112. package/src/runtime/agent/orchestrator/session/loop/env.mjs +14 -0
  113. package/src/runtime/agent/orchestrator/session/loop/hidden-agents.mjs +21 -0
  114. package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +47 -0
  115. package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +182 -0
  116. package/src/runtime/agent/orchestrator/session/loop/steering-ladder.mjs +173 -0
  117. package/src/runtime/agent/orchestrator/session/loop/steering.mjs +63 -0
  118. package/src/runtime/agent/orchestrator/session/loop/stored-tool-args.mjs +100 -0
  119. package/src/runtime/agent/orchestrator/session/loop/termination.mjs +58 -0
  120. package/src/runtime/agent/orchestrator/session/loop/tool-classify.mjs +52 -0
  121. package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +239 -0
  122. package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +218 -0
  123. package/src/runtime/agent/orchestrator/session/loop/transcript-repair.mjs +101 -0
  124. package/src/runtime/agent/orchestrator/session/loop/usage.mjs +35 -0
  125. package/src/runtime/agent/orchestrator/session/loop.mjs +409 -1304
  126. package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +471 -0
  127. package/src/runtime/agent/orchestrator/session/manager/context-meta.mjs +230 -0
  128. package/src/runtime/agent/orchestrator/session/manager/pending-messages.mjs +235 -0
  129. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +149 -0
  130. package/src/runtime/agent/orchestrator/session/manager/rules-cache.mjs +155 -0
  131. package/src/runtime/agent/orchestrator/session/manager/runtime-liveness.mjs +406 -0
  132. package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +80 -0
  133. package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +303 -0
  134. package/src/runtime/agent/orchestrator/session/manager/usage-metrics.mjs +210 -0
  135. package/src/runtime/agent/orchestrator/session/manager.mjs +226 -2114
  136. package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +189 -0
  137. package/src/runtime/agent/orchestrator/session/store.mjs +74 -179
  138. package/src/runtime/agent/orchestrator/stall-policy.mjs +3 -3
  139. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +70 -20
  140. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +22 -2
  141. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +33 -42
  142. package/src/runtime/agent/orchestrator/tools/builtin/external-tool-adapters.mjs +241 -0
  143. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +1 -1
  144. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +40 -0
  145. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +42 -2
  146. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +1 -1
  147. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +11 -4
  148. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +29 -0
  149. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +8 -0
  150. package/src/runtime/agent/orchestrator/tools/builtin/search-path-diagnostics.mjs +126 -0
  151. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +81 -87
  152. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-paths.mjs +161 -0
  153. package/src/runtime/agent/orchestrator/tools/builtin/shell-job-process.mjs +108 -0
  154. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +78 -304
  155. package/src/runtime/agent/orchestrator/tools/builtin.mjs +11 -6
  156. package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +303 -0
  157. package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +43 -0
  158. package/src/runtime/agent/orchestrator/tools/code-graph/disk-cache.mjs +382 -0
  159. package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +551 -0
  160. package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +295 -0
  161. package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +158 -0
  162. package/src/runtime/agent/orchestrator/tools/code-graph/keyword-match.mjs +82 -0
  163. package/src/runtime/agent/orchestrator/tools/code-graph/lang-predicates.mjs +128 -0
  164. package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +66 -0
  165. package/src/runtime/agent/orchestrator/tools/code-graph/project-root.mjs +44 -0
  166. package/src/runtime/agent/orchestrator/tools/code-graph/search.mjs +1080 -0
  167. package/src/runtime/agent/orchestrator/tools/code-graph/source-access.mjs +81 -0
  168. package/src/runtime/agent/orchestrator/tools/code-graph/span.mjs +19 -0
  169. package/src/runtime/agent/orchestrator/tools/code-graph/symbol-index.mjs +280 -0
  170. package/src/runtime/agent/orchestrator/tools/code-graph/text-columns.mjs +45 -0
  171. package/src/runtime/agent/orchestrator/tools/code-graph/text-mask.mjs +347 -0
  172. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +6 -6
  173. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +36 -4277
  174. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +6 -3
  175. package/src/runtime/agent/orchestrator/tools/patch/constants.mjs +9 -0
  176. package/src/runtime/agent/orchestrator/tools/patch/dispatch.mjs +171 -0
  177. package/src/runtime/agent/orchestrator/tools/patch/matcher.mjs +471 -0
  178. package/src/runtime/agent/orchestrator/tools/patch/native-server.mjs +436 -0
  179. package/src/runtime/agent/orchestrator/tools/patch/orchestrator.mjs +342 -0
  180. package/src/runtime/agent/orchestrator/tools/patch/parsing.mjs +359 -0
  181. package/src/runtime/agent/orchestrator/tools/patch/paths.mjs +340 -0
  182. package/src/runtime/agent/orchestrator/tools/patch/v4a-convert.mjs +643 -0
  183. package/src/runtime/agent/orchestrator/tools/patch.mjs +36 -2959
  184. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +1 -23
  185. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +10 -74
  186. package/src/runtime/agent/orchestrator/tools/shell-powershell.mjs +77 -0
  187. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +2 -4
  188. package/src/runtime/agent/orchestrator/tools/shell-state.mjs +154 -0
  189. package/src/runtime/channels/backends/discord-access.mjs +32 -0
  190. package/src/runtime/channels/backends/discord-attachments.mjs +65 -0
  191. package/src/runtime/channels/backends/discord-gateway.mjs +233 -0
  192. package/src/runtime/channels/backends/discord.mjs +12 -292
  193. package/src/runtime/channels/index.mjs +241 -894
  194. package/src/runtime/channels/lib/backend-dispatch.mjs +44 -0
  195. package/src/runtime/channels/lib/boot-profile.mjs +23 -0
  196. package/src/runtime/channels/lib/crash-log.mjs +106 -0
  197. package/src/runtime/channels/lib/event-pipeline.mjs +18 -1
  198. package/src/runtime/channels/lib/event-queue.mjs +63 -4
  199. package/src/runtime/channels/lib/inbound-routing.mjs +111 -0
  200. package/src/runtime/channels/lib/index-drop-trace.mjs +72 -0
  201. package/src/runtime/channels/lib/output-forwarder.mjs +9 -1
  202. package/src/runtime/channels/lib/owner-heartbeat.mjs +75 -0
  203. package/src/runtime/channels/lib/parent-bridge.mjs +88 -0
  204. package/src/runtime/channels/lib/runtime-paths.mjs +14 -4
  205. package/src/runtime/channels/lib/session-discovery.mjs +56 -4
  206. package/src/runtime/channels/lib/telegram-format.mjs +19 -22
  207. package/src/runtime/channels/lib/tool-dispatch.mjs +158 -0
  208. package/src/runtime/channels/lib/tool-format.mjs +1 -1
  209. package/src/runtime/channels/lib/transcript-discovery.mjs +4 -4
  210. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +6 -3
  211. package/src/runtime/channels/lib/voice-transcription.mjs +179 -0
  212. package/src/runtime/channels/lib/webhook/deliveries.mjs +312 -0
  213. package/src/runtime/channels/lib/webhook/log.mjs +42 -0
  214. package/src/runtime/channels/lib/webhook/ngrok.mjs +181 -0
  215. package/src/runtime/channels/lib/webhook/signature.mjs +60 -0
  216. package/src/runtime/channels/lib/webhook.mjs +36 -570
  217. package/src/runtime/channels/lib/whisper-language.mjs +42 -0
  218. package/src/runtime/channels/tool-defs.mjs +11 -130
  219. package/src/runtime/memory/index.mjs +258 -2050
  220. package/src/runtime/memory/lib/core-memory-store.mjs +351 -1
  221. package/src/runtime/memory/lib/cycle-llm-adapters.mjs +58 -0
  222. package/src/runtime/memory/lib/cycle-scheduler.mjs +497 -0
  223. package/src/runtime/memory/lib/cycle-signatures.mjs +34 -0
  224. package/src/runtime/memory/lib/embedding-warmup.mjs +58 -0
  225. package/src/runtime/memory/lib/http-wire.mjs +57 -0
  226. package/src/runtime/memory/lib/memory-config-flags.mjs +91 -0
  227. package/src/runtime/memory/lib/memory-cycle.mjs +1 -1
  228. package/src/runtime/memory/lib/memory-cycle2-gate.mjs +515 -0
  229. package/src/runtime/memory/lib/memory-cycle2-mutations.mjs +324 -0
  230. package/src/runtime/memory/lib/memory-cycle2-shared.mjs +18 -0
  231. package/src/runtime/memory/lib/memory-cycle2.mjs +72 -837
  232. package/src/runtime/memory/lib/memory-embed.mjs +149 -0
  233. package/src/runtime/memory/lib/memory-process-lock.mjs +162 -0
  234. package/src/runtime/memory/lib/memory-recall-scope-filter.mjs +24 -0
  235. package/src/runtime/memory/lib/memory-recall-store.mjs +22 -2
  236. package/src/runtime/memory/lib/memory-retrievers.mjs +8 -0
  237. package/src/runtime/memory/lib/memory.mjs +20 -0
  238. package/src/runtime/memory/lib/pg/supervisor.mjs +1 -1
  239. package/src/runtime/memory/lib/promotion-fingerprint.mjs +50 -0
  240. package/src/runtime/memory/lib/query-handlers.mjs +780 -0
  241. package/src/runtime/memory/lib/recall-format.mjs +238 -0
  242. package/src/runtime/memory/lib/runtime-fetcher.mjs +8 -3
  243. package/src/runtime/memory/lib/transcript-ingest.mjs +425 -0
  244. package/src/runtime/memory/tool-defs.mjs +6 -14
  245. package/src/runtime/search/lib/http-fetch.mjs +274 -0
  246. package/src/runtime/search/lib/ssrf-guard.mjs +333 -0
  247. package/src/runtime/search/lib/web-tools.mjs +24 -602
  248. package/src/runtime/shared/abort-controller.mjs +1 -1
  249. package/src/runtime/shared/atomic-file.mjs +26 -1
  250. package/src/runtime/shared/background-tasks.mjs +2 -3
  251. package/src/runtime/shared/buffered-appender.mjs +149 -0
  252. package/src/runtime/shared/launcher-control.mjs +2 -2
  253. package/src/runtime/shared/task-notification-envelope.mjs +98 -0
  254. package/src/runtime/shared/tool-execution-contract.mjs +2 -2
  255. package/src/runtime/shared/tool-primitives.mjs +308 -0
  256. package/src/runtime/shared/tool-result-summary.mjs +515 -0
  257. package/src/runtime/shared/tool-surface.mjs +80 -898
  258. package/src/runtime/shared/transcript-writer.mjs +52 -2
  259. package/src/runtime/shared/update-checker.mjs +7 -4
  260. package/src/session-runtime/config-helpers.mjs +291 -0
  261. package/src/session-runtime/config-lifecycle.mjs +232 -0
  262. package/src/session-runtime/cwd-plugins.mjs +226 -0
  263. package/src/session-runtime/effort.mjs +128 -0
  264. package/src/session-runtime/fs-utils.mjs +10 -0
  265. package/src/session-runtime/mcp-glue.mjs +177 -0
  266. package/src/session-runtime/model-capabilities.mjs +130 -0
  267. package/src/session-runtime/model-recency.mjs +111 -0
  268. package/src/session-runtime/native-search.mjs +247 -0
  269. package/src/session-runtime/output-styles.mjs +126 -0
  270. package/src/session-runtime/plugin-mcp.mjs +114 -0
  271. package/src/session-runtime/prewarm.mjs +142 -0
  272. package/src/session-runtime/provider-models.mjs +278 -0
  273. package/src/session-runtime/provider-usage.mjs +120 -0
  274. package/src/session-runtime/quick-model-rows.mjs +170 -0
  275. package/src/session-runtime/quick-search-models.mjs +46 -0
  276. package/src/session-runtime/session-hooks.mjs +93 -0
  277. package/src/session-runtime/session-text.mjs +100 -0
  278. package/src/session-runtime/settings-api.mjs +319 -0
  279. package/src/session-runtime/statusline-route.mjs +35 -0
  280. package/src/session-runtime/tool-catalog.mjs +720 -0
  281. package/src/session-runtime/tool-defs.mjs +84 -0
  282. package/src/session-runtime/warmup-schedulers.mjs +201 -0
  283. package/src/session-runtime/workflow.mjs +358 -0
  284. package/src/standalone/agent-tool/helpers.mjs +237 -0
  285. package/src/standalone/agent-tool/notify.mjs +107 -0
  286. package/src/standalone/agent-tool/provider-init.mjs +143 -0
  287. package/src/standalone/agent-tool/render.mjs +152 -0
  288. package/src/standalone/agent-tool/tool-def.mjs +55 -0
  289. package/src/standalone/agent-tool.mjs +155 -677
  290. package/src/standalone/channel-worker.mjs +7 -9
  291. package/src/standalone/explore-tool.mjs +40 -12
  292. package/src/standalone/hook-bus/config.mjs +207 -0
  293. package/src/standalone/hook-bus/constants.mjs +90 -0
  294. package/src/standalone/hook-bus/handlers.mjs +481 -0
  295. package/src/standalone/hook-bus/payload.mjs +31 -0
  296. package/src/standalone/hook-bus/rules.mjs +77 -0
  297. package/src/standalone/hook-bus.mjs +110 -746
  298. package/src/standalone/memory-runtime-proxy.mjs +7 -0
  299. package/src/standalone/opencode-go-login.mjs +125 -0
  300. package/src/standalone/provider-admin.mjs +15 -19
  301. package/src/standalone/usage-dashboard.mjs +3 -1
  302. package/src/tui/App.jsx +1163 -7571
  303. package/src/tui/app/app-format.mjs +206 -0
  304. package/src/tui/app/channel-pickers.mjs +510 -0
  305. package/src/tui/app/clipboard.mjs +67 -0
  306. package/src/tui/app/core-memory-picker.mjs +210 -0
  307. package/src/tui/app/extension-pickers.mjs +506 -0
  308. package/src/tui/app/input-parsers.mjs +193 -0
  309. package/src/tui/app/maintenance-pickers.mjs +324 -0
  310. package/src/tui/app/model-options.mjs +330 -0
  311. package/src/tui/app/model-picker.mjs +365 -0
  312. package/src/tui/app/onboarding-steps.mjs +400 -0
  313. package/src/tui/app/project-picker.mjs +247 -0
  314. package/src/tui/app/provider-setup-picker.mjs +580 -0
  315. package/src/tui/app/resume-picker.mjs +55 -0
  316. package/src/tui/app/route-pickers.mjs +419 -0
  317. package/src/tui/app/settings-picker.mjs +490 -0
  318. package/src/tui/app/slash-commands.mjs +101 -0
  319. package/src/tui/app/slash-dispatch.mjs +427 -0
  320. package/src/tui/app/text-layout.mjs +46 -0
  321. package/src/tui/app/theme-effort-pickers.mjs +154 -0
  322. package/src/tui/app/transcript-window.mjs +671 -0
  323. package/src/tui/app/use-mouse-input.mjs +460 -0
  324. package/src/tui/app/use-prompt-handlers.mjs +310 -0
  325. package/src/tui/app/use-transcript-scroll.mjs +510 -0
  326. package/src/tui/app/use-transcript-window.mjs +589 -0
  327. package/src/tui/components/ConfirmBar.jsx +1 -1
  328. package/src/tui/components/Picker.jsx +32 -4
  329. package/src/tui/components/PromptInput.jsx +259 -80
  330. package/src/tui/components/SlashCommandPalette.jsx +8 -1
  331. package/src/tui/components/StatusLine.jsx +63 -12
  332. package/src/tui/components/TextEntryPanel.jsx +11 -0
  333. package/src/tui/components/ToolExecution.jsx +56 -588
  334. package/src/tui/components/TranscriptItem.jsx +105 -0
  335. package/src/tui/components/UsagePanel.jsx +18 -4
  336. package/src/tui/components/prompt-input/edit-helpers.mjs +72 -0
  337. package/src/tui/components/prompt-input/voice-indicator.mjs +39 -0
  338. package/src/tui/components/tool-execution/ResultBody.jsx +56 -0
  339. package/src/tui/components/tool-execution/surface-detail.mjs +405 -0
  340. package/src/tui/components/tool-execution/text-format.mjs +161 -0
  341. package/src/tui/components/tool-output-format.mjs +2 -2
  342. package/src/tui/display-width.mjs +20 -3
  343. package/src/tui/dist/index.mjs +18034 -17188
  344. package/src/tui/engine/agent-envelope.mjs +296 -0
  345. package/src/tui/engine/agent-job-feed.mjs +133 -0
  346. package/src/tui/engine/boot-profile.mjs +21 -0
  347. package/src/tui/engine/labels.mjs +67 -0
  348. package/src/tui/engine/notice-text.mjs +112 -0
  349. package/src/tui/engine/notification-plan.mjs +76 -0
  350. package/src/tui/engine/queue-helpers.mjs +161 -0
  351. package/src/tui/engine/render-timing.mjs +17 -0
  352. package/src/tui/engine/session-stats.mjs +46 -0
  353. package/src/tui/engine/tool-approval.mjs +94 -0
  354. package/src/tui/engine/tool-call-fields.mjs +23 -0
  355. package/src/tui/engine/tool-card-results.mjs +234 -0
  356. package/src/tui/engine/tool-result-status.mjs +135 -0
  357. package/src/tui/engine/tool-result-text.mjs +126 -0
  358. package/src/tui/engine.mjs +405 -1385
  359. package/src/tui/figures.mjs +5 -0
  360. package/src/tui/index.jsx +105 -0
  361. package/src/tui/input-editing.mjs +60 -10
  362. package/src/tui/keyboard-protocol.mjs +2 -2
  363. package/src/tui/lib/voice-recorder.mjs +35 -19
  364. package/src/tui/markdown/format-token.mjs +11 -9
  365. package/src/tui/paste-attachments.mjs +38 -0
  366. package/src/tui/statusline-ansi-bridge.mjs +11 -3
  367. package/src/tui/theme.mjs +6 -0
  368. package/src/tui/themes/base.mjs +2 -2
  369. package/src/tui/themes/kanagawa.mjs +4 -4
  370. package/src/tui/themes/teal.mjs +4 -5
  371. package/src/tui/themes/utils.mjs +1 -1
  372. package/src/ui/statusline-agents.mjs +213 -0
  373. package/src/ui/statusline-format.mjs +146 -0
  374. package/src/ui/statusline-segments.mjs +148 -0
  375. package/src/ui/statusline.mjs +77 -462
  376. package/src/ui/tool-card.mjs +0 -1
  377. package/src/vendor/statusline/bin/statusline-route.mjs +15 -2
  378. package/src/workflows/default/WORKFLOW.md +16 -9
  379. package/src/workflows/sequential/WORKFLOW.md +16 -11
  380. package/src/workflows/solo/WORKFLOW.md +5 -1
  381. package/vendor/ink/build/display-width.js +19 -3
  382. package/vendor/ink/build/ink.js +103 -6
  383. package/vendor/ink/build/log-update.js +17 -3
  384. package/vendor/ink/build/wrap-text.js +125 -0
  385. package/scripts/_test-folder-dialog.mjs +0 -30
  386. package/scripts/fix-brief-fn.mjs +0 -35
  387. package/scripts/fix-format-tool-surface.mjs +0 -24
  388. package/scripts/fix-tool-exec-visible.mjs +0 -42
  389. package/scripts/patch-agent-brief.mjs +0 -48
  390. package/scripts/patch-app.mjs +0 -21
  391. package/scripts/patch-app2.mjs +0 -18
  392. package/scripts/patch-dist-brief.mjs +0 -96
  393. package/scripts/patch-tool-exec.mjs +0 -70
  394. package/src/examples/schedules/SCHEDULE.example.md +0 -32
  395. package/src/examples/webhooks/WEBHOOK.example.md +0 -40
  396. package/src/runtime/agent/orchestrator/session/manager.reactive-persist.test.mjs +0 -107
  397. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.test.mjs +0 -143
  398. package/src/runtime/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -285
  399. package/src/runtime/agent/orchestrator/tools/builtin/open-config-tool.mjs +0 -26
  400. package/src/runtime/shared/channel-notification-routing.test.mjs +0 -45
  401. package/src/runtime/shared/tool-execution-contract.test.mjs +0 -183
  402. package/src/standalone/agent-task-status.test.mjs +0 -76
  403. package/src/tui/components/tool-output-format.test.mjs +0 -399
  404. package/src/tui/display-width.test.mjs +0 -35
  405. package/src/tui/engine-runtime-notification.test.mjs +0 -115
  406. package/src/tui/engine-tool-result-text.test.mjs +0 -75
  407. package/src/tui/markdown/format-token.test.mjs +0 -354
  408. package/src/tui/markdown/render-ansi.test.mjs +0 -108
  409. package/src/tui/markdown/stream-fence.test.mjs +0 -26
  410. package/src/tui/markdown/streaming-markdown.test.mjs +0 -70
  411. package/src/tui/prompt-history-store.test.mjs +0 -52
  412. package/src/tui/statusline-ansi-bridge.test.mjs +0 -159
  413. package/src/tui/transcript-tool-failures.test.mjs +0 -111
  414. package/src/ui/markdown.test.mjs +0 -70
  415. package/src/ui/statusline-context-label.test.mjs +0 -15
  416. package/src/vendor/statusline/bin/statusline-lib.mjs +0 -186
  417. package/src/vendor/statusline/bin/statusline-route.test.mjs +0 -80
@@ -0,0 +1,580 @@
1
+ /*
2
+ * provider-setup-picker.mjs — the Provider setup picker cluster.
3
+ *
4
+ * Extracted from App.jsx behavior-preservingly as a dependency-injection
5
+ * factory. Every function body is the original App logic verbatim, with closure
6
+ * identifiers threaded through the factory argument. The internal action openers
7
+ * (openApiProviderActions/openOAuthProviderActions/openLocalProviderActions/
8
+ * startOAuthLogin) stay nested inside openProviderSetupPicker so they keep
9
+ * closing over the per-open `setup`/`items`/`returnTo`. Refs and cache
10
+ * invalidation thread directly.
11
+ */
12
+ import { theme } from '../theme.mjs';
13
+ import {
14
+ providerStatusLabel,
15
+ providerDetailText,
16
+ providerKindLabel,
17
+ } from './app-format.mjs';
18
+ import { providerDisplayRank } from './model-options.mjs';
19
+
20
+ export function createProviderSetupPicker({
21
+ store,
22
+ setPicker,
23
+ setProviderPrompt,
24
+ setChannelPrompt,
25
+ setHookPrompt,
26
+ setSettingsPrompt,
27
+ setContextPanel,
28
+ closeUsagePanel,
29
+ oauthSubmitRef,
30
+ clearModelCaches,
31
+ }) {
32
+ const openProviderSetupPicker = async (options = {}) => {
33
+ const returnTo = typeof options.returnTo === 'function' ? options.returnTo : null;
34
+ const onContinue = typeof options.onContinue === 'function' ? options.onContinue : returnTo;
35
+ const onCancel = typeof options.onCancel === 'function' ? options.onCancel : null;
36
+ setProviderPrompt(null);
37
+ setChannelPrompt(null);
38
+ setHookPrompt(null);
39
+ setSettingsPrompt(null);
40
+ // Close full-panel overlays too: they render ahead of providerPrompt in
41
+ // the floating-panel chain, so a lingering usage/context panel would mask
42
+ // any text-entry prompt opened from the provider actions (e.g. the
43
+ // OpenCode Go cookie prompt appeared to do nothing).
44
+ setContextPanel(null);
45
+ closeUsagePanel();
46
+ // Onboarding (and any caller) can pass a preloaded provider setup so we skip
47
+ // the "Checking Providers" placeholder frame that otherwise flashes before
48
+ // the real list — that swap is what looked like a jump on Step 1 entry.
49
+ let setup = options.preloadedSetup && typeof options.preloadedSetup === 'object'
50
+ ? options.preloadedSetup
51
+ : null;
52
+ if (!setup) {
53
+ setPicker({
54
+ title: options.title || 'Providers',
55
+ description: options.description || 'Choose a provider to configure.',
56
+ labelWidth: 18,
57
+ metaWidth: 10,
58
+ pickerKey: 'providers-loading',
59
+ initialIndex: 0,
60
+ items: [{
61
+ value: 'checking',
62
+ label: 'Checking Providers',
63
+ meta: '',
64
+ description: 'please wait',
65
+ _type: 'loading',
66
+ }],
67
+ onSelect: () => {},
68
+ onCancel: () => {
69
+ setPicker(null);
70
+ if (onCancel) onCancel();
71
+ },
72
+ });
73
+ try {
74
+ await new Promise((resolve) => setTimeout(resolve, 0));
75
+ setup = await store.getProviderSetup();
76
+ } catch (e) {
77
+ store.pushNotice(`providers failed: ${e?.message || e}`, 'error');
78
+ return;
79
+ }
80
+ }
81
+
82
+ const items = [];
83
+ if ((returnTo || onContinue) && !options.confirmBar) {
84
+ items.push({
85
+ value: 'continue-setup',
86
+ label: options.continueLabel || 'Continue setup',
87
+ description: options.continueDescription || 'return to setup',
88
+ _type: 'continue',
89
+ });
90
+ }
91
+ const providerFooter = (item) => {
92
+ const provider = item?._provider;
93
+ if (!provider) return '';
94
+ const active = provider.enabled || provider.authenticated || provider.detected;
95
+ return [{
96
+ glyph: active ? '●' : '○',
97
+ color: active ? theme.success : theme.inactive,
98
+ text: [providerKindLabel(provider), providerStatusLabel(provider), providerDetailText(provider)].filter(Boolean).join(' · '),
99
+ }];
100
+ };
101
+ const providerItemRank = (item) => providerDisplayRank(item._providerId || item.value);
102
+ const providerItems = [];
103
+ for (const p of setup.api || []) {
104
+ providerItems.push({
105
+ value: `api:${p.id}`,
106
+ label: p.name,
107
+ meta: providerStatusLabel(p),
108
+ description: '',
109
+ _type: 'api-key',
110
+ _providerId: p.id,
111
+ _providerName: p.name,
112
+ _provider: p,
113
+ _authenticated: p.authenticated,
114
+ _url: p.url,
115
+ });
116
+ }
117
+ for (const p of setup.oauth || []) {
118
+ providerItems.push({
119
+ value: `oauth:${p.id}`,
120
+ label: p.name,
121
+ meta: providerStatusLabel(p),
122
+ description: '',
123
+ _type: 'oauth',
124
+ _providerId: p.id,
125
+ _providerName: p.name,
126
+ _provider: p,
127
+ _authenticated: p.authenticated,
128
+ });
129
+ }
130
+ for (const p of setup.local || []) {
131
+ providerItems.push({
132
+ value: `local:${p.id}`,
133
+ label: p.name,
134
+ meta: providerStatusLabel(p),
135
+ description: '',
136
+ _type: 'local',
137
+ _providerId: p.id,
138
+ _providerName: p.name,
139
+ _provider: p,
140
+ _enabled: p.enabled,
141
+ _baseURL: p.baseURL,
142
+ _defaultURL: p.defaultURL,
143
+ });
144
+ }
145
+ providerItems.sort((a, b) => {
146
+ const rank = providerItemRank(a) - providerItemRank(b);
147
+ if (rank !== 0) return rank;
148
+ return String(a.label || '').localeCompare(String(b.label || ''), 'en', { sensitivity: 'base' });
149
+ });
150
+ items.push(...providerItems);
151
+
152
+ const rememberProviderSelection = (providerItem) => {
153
+ if (!providerItem?.value) return;
154
+ options.highlightProviderValue = providerItem.value;
155
+ };
156
+ const providerMainInitialIndex = () => {
157
+ const value = options.highlightProviderValue;
158
+ if (!value) return 0;
159
+ const idx = items.findIndex((item) => item.value === value);
160
+ return idx >= 0 ? idx : 0;
161
+ };
162
+
163
+ const reopenProviders = () => {
164
+ void openProviderSetupPicker(options);
165
+ };
166
+ const providerActionFooter = (provider) => provider ? [{
167
+ glyph: provider.enabled || provider.authenticated || provider.detected ? '●' : '○',
168
+ color: provider.enabled || provider.authenticated || provider.detected ? theme.success : theme.inactive,
169
+ text: [providerKindLabel(provider), providerStatusLabel(provider), providerDetailText(provider)].filter(Boolean).join(' · '),
170
+ }] : '';
171
+ const setApiKeyPrompt = (providerItem) => {
172
+ setProviderPrompt({
173
+ kind: 'api-key',
174
+ providerId: providerItem._providerId,
175
+ label: providerItem._providerName,
176
+ mode: providerItem._authenticated ? 'replace' : 'set',
177
+ envName: providerItem._provider?.envName || '',
178
+ source: providerDetailText(providerItem._provider),
179
+ afterSave: returnTo,
180
+ });
181
+ };
182
+ const openApiProviderActions = (providerItem) => {
183
+ rememberProviderSelection(providerItem);
184
+ const provider = providerItem._provider || {};
185
+ const hasAuth = providerItem._authenticated || provider.authenticated;
186
+ const hasStoredKey = provider.stored || (!provider.env && hasAuth);
187
+ const apiActions = [];
188
+ apiActions.push({
189
+ value: 'set-key',
190
+ label: hasAuth ? 'Replace API key' : 'Add API key',
191
+ description: provider.envName ? `masked input · ${provider.envName}` : 'masked input · stored in OS keychain',
192
+ _action: 'set-key',
193
+ });
194
+ if (hasStoredKey) {
195
+ apiActions.push({
196
+ value: 'forget-key',
197
+ label: 'Delete API key',
198
+ description: provider.env ? 'remove keychain key; env key remains active' : 'remove stored key for this provider',
199
+ _action: 'forget-key',
200
+ });
201
+ }
202
+ if (providerItem._providerId === 'opencode-go') {
203
+ apiActions.push({
204
+ value: 'usage-login-browser',
205
+ label: 'Usage login (browser)',
206
+ description: 'open browser; auth cookie captured automatically',
207
+ _action: 'usage-login-browser',
208
+ });
209
+ }
210
+ setPicker({
211
+ title: `Provider · ${providerItem._providerName}`,
212
+ description: 'Choose an API-key action.',
213
+ footer: () => providerActionFooter(provider),
214
+ help: '↑/↓ Select · Enter Choose · Esc Providers',
215
+ indexMode: 'always',
216
+ labelWidth: 22,
217
+ pickerKey: `providers-action:${providerItem.value}`,
218
+ initialIndex: 0,
219
+ items: apiActions,
220
+ onSelect: (_detailValue, detail) => {
221
+ setPicker(null);
222
+ if (detail._action === 'set-key') {
223
+ setApiKeyPrompt(providerItem);
224
+ return;
225
+ }
226
+ if (detail._action === 'forget-key') {
227
+ try {
228
+ store.forgetProviderAuth(providerItem._providerId);
229
+ clearModelCaches('all');
230
+ reopenProviders();
231
+ } catch (e) {
232
+ store.pushNotice(`auth-forget failed: ${e?.message || e}`, 'error');
233
+ }
234
+ }
235
+ if (detail._action === 'usage-login-browser') {
236
+ let backedOut = false;
237
+ const waitItems = [
238
+ {
239
+ value: 'waiting',
240
+ label: 'Waiting for login',
241
+ meta: 'Running',
242
+ description: 'sign in via the browser window',
243
+ _action: 'waiting',
244
+ },
245
+ {
246
+ value: 'back',
247
+ label: 'Back',
248
+ meta: '',
249
+ description: 'return to provider actions',
250
+ _action: 'back',
251
+ },
252
+ ];
253
+ setPicker({
254
+ title: `Provider · ${providerItem._providerName}`,
255
+ description: 'Opening browser. Sign in at opencode.ai/auth; the auth cookie is captured automatically.',
256
+ footer: () => providerActionFooter(provider),
257
+ help: '↑/↓ Select · Enter Choose · Esc Providers',
258
+ indexMode: 'never',
259
+ labelWidth: 22,
260
+ metaWidth: 12,
261
+ pickerKey: `providers-usage-login:${providerItem.value}`,
262
+ initialIndex: 0,
263
+ items: waitItems,
264
+ onSelect: (_value, item) => {
265
+ if (item?._action === 'back') {
266
+ backedOut = true;
267
+ openApiProviderActions(providerItem);
268
+ }
269
+ },
270
+ onCancel: () => {
271
+ backedOut = true;
272
+ openApiProviderActions(providerItem);
273
+ },
274
+ });
275
+ void store.loginOpenCodeGoUsage()
276
+ .then(() => {
277
+ store.pushNotice('OpenCode Go usage auth captured', 'info');
278
+ if (!backedOut) reopenProviders();
279
+ })
280
+ .catch((e) => {
281
+ store.pushNotice(`OpenCode Go usage login failed: ${e?.message || e}`, 'error');
282
+ if (!backedOut) openApiProviderActions(providerItem);
283
+ });
284
+ return;
285
+ }
286
+ },
287
+ onCancel: reopenProviders,
288
+ });
289
+ };
290
+
291
+ const startOAuthLogin = (providerItem) => {
292
+ const provider = providerItem._provider || {};
293
+ const showOAuthProgress = (message = 'Opening login flow. Complete it in the browser if prompted.', opts = {}) => {
294
+ const onBack = typeof opts.onBack === 'function' ? opts.onBack : () => openOAuthProviderActions(providerItem);
295
+ const actions = [
296
+ {
297
+ value: 'waiting',
298
+ label: opts.waitLabel || 'Waiting for login',
299
+ meta: 'Running',
300
+ description: opts.waitDescription || 'finish the browser/OAuth prompt',
301
+ _action: 'waiting',
302
+ },
303
+ {
304
+ value: 'back',
305
+ label: 'Back',
306
+ meta: '',
307
+ description: 'return to provider actions',
308
+ _action: 'back',
309
+ },
310
+ ];
311
+ setPicker({
312
+ title: `Provider · ${providerItem._providerName}`,
313
+ description: message,
314
+ footer: () => providerActionFooter(provider),
315
+ help: '↑/↓ Select · Enter Choose · Esc Providers',
316
+ indexMode: 'never',
317
+ labelWidth: 22,
318
+ metaWidth: 12,
319
+ pickerKey: `providers-oauth-progress:${providerItem.value}`,
320
+ initialIndex: 0,
321
+ items: actions,
322
+ onSelect: (_value, item) => {
323
+ if (item?._action === 'back') onBack();
324
+ },
325
+ onCancel: onBack,
326
+ });
327
+ };
328
+ const showOAuthResult = (ok, message = '') => {
329
+ setProviderPrompt(null);
330
+ setPicker({
331
+ title: `Provider · ${providerItem._providerName}`,
332
+ description: message || (ok ? 'Login complete.' : 'Login did not complete.'),
333
+ footer: () => providerActionFooter(provider),
334
+ help: ok ? 'Enter Refresh Providers · Esc Providers' : 'Enter Back · Esc Providers',
335
+ indexMode: 'never',
336
+ labelWidth: 22,
337
+ metaWidth: 12,
338
+ pickerKey: `providers-oauth-result:${providerItem.value}:${ok ? 'ok' : 'fail'}`,
339
+ initialIndex: 0,
340
+ items: [{
341
+ value: ok ? 'success' : 'back',
342
+ label: ok ? 'Success' : 'Back',
343
+ meta: ok ? 'Done' : 'Ready',
344
+ description: ok ? 'refresh provider status' : 'return to provider actions',
345
+ _action: ok ? 'success' : 'back',
346
+ }],
347
+ onSelect: () => {
348
+ if (ok) reopenProviders();
349
+ else openOAuthProviderActions(providerItem);
350
+ },
351
+ onCancel: () => {
352
+ if (ok) reopenProviders();
353
+ else openOAuthProviderActions(providerItem);
354
+ },
355
+ });
356
+ };
357
+ let backedOut = false;
358
+ showOAuthProgress('Opening login flow. Complete it in the browser if prompted.', {
359
+ onBack: () => {
360
+ backedOut = true;
361
+ openOAuthProviderActions(providerItem);
362
+ },
363
+ });
364
+ if (typeof store.beginOAuthProviderLogin === 'function') {
365
+ let handled = false;
366
+ const providerName = providerItem._providerName || providerItem._providerId || 'OAuth';
367
+ const finish = (ok, message = '') => {
368
+ if (handled) return;
369
+ handled = true;
370
+ if (ok) clearModelCaches('all');
371
+ if (backedOut) {
372
+ if (message) store.pushNotice(message, ok ? 'info' : 'error');
373
+ return;
374
+ }
375
+ showOAuthResult(ok, message || (ok ? `${providerName} login complete.` : `${providerName} login failed.`));
376
+ };
377
+ void store.beginOAuthProviderLogin(providerItem._providerId)
378
+ .then((login) => {
379
+ setPicker(null);
380
+ const manualUrl = login?.manualUrl || '';
381
+ setProviderPrompt({
382
+ kind: 'oauth-code',
383
+ providerId: providerItem._providerId,
384
+ providerName,
385
+ label: `${providerName} OAuth code`,
386
+ hint: manualUrl
387
+ ? 'If the browser callback does not finish, open the URL below manually and paste code#state.'
388
+ : `Paste the authorization code or full redirect URL for ${providerName}.`,
389
+ // Shown inside the live panel only — never written to the
390
+ // transcript, so it cannot linger in scrollback after the flow.
391
+ detail: manualUrl,
392
+ login,
393
+ afterSave: returnTo,
394
+ successReturn: () => {
395
+ showOAuthResult(true, `${providerName} login complete.`);
396
+ },
397
+ failureReturn: (e) => {
398
+ showOAuthResult(false, `${providerName} code failed: ${e?.message || e}`);
399
+ },
400
+ cancelReturn: () => {
401
+ openOAuthProviderActions(providerItem);
402
+ },
403
+ });
404
+ store.pushNotice(`browser opened for ${providerName}; paste code/redirect here if callback does not finish`, 'info');
405
+ login.waitForCallback
406
+ ?.then((result) => {
407
+ if (result && !oauthSubmitRef.current) finish(true, `${providerName} login complete`);
408
+ })
409
+ .catch((e) => finish(false, `oauth login failed: ${e?.message || e}`));
410
+ })
411
+ .catch((e) => {
412
+ store.pushNotice(`oauth login failed: ${e?.message || e}`, 'error');
413
+ openOAuthProviderActions(providerItem);
414
+ });
415
+ return;
416
+ }
417
+ void store.loginOAuthProvider(providerItem._providerId)
418
+ .then(() => {
419
+ clearModelCaches('all');
420
+ if (backedOut) {
421
+ store.pushNotice(`${providerItem._providerName} login complete`, 'info');
422
+ return;
423
+ }
424
+ showOAuthResult(true, `${providerItem._providerName} login complete.`);
425
+ })
426
+ .catch((e) => {
427
+ if (backedOut) {
428
+ store.pushNotice(`oauth login failed: ${e?.message || e}`, 'error');
429
+ return;
430
+ }
431
+ showOAuthResult(false, `OAuth login failed: ${e?.message || e}`);
432
+ });
433
+ };
434
+ const openOAuthProviderActions = (providerItem) => {
435
+ rememberProviderSelection(providerItem);
436
+ const provider = providerItem._provider || {};
437
+ const hasAuth = providerItem._authenticated || provider.authenticated;
438
+ const oauthActions = [];
439
+ oauthActions.push({
440
+ value: 'login-oauth',
441
+ label: hasAuth ? 'Re-login' : 'Login',
442
+ description: providerDetailText(provider) || 'open browser or OAuth flow',
443
+ _action: 'login-oauth',
444
+ });
445
+ if (hasAuth) {
446
+ oauthActions.push({
447
+ value: 'forget-oauth',
448
+ label: 'Forget login',
449
+ description: 'remove stored OAuth credentials',
450
+ _action: 'forget-oauth',
451
+ });
452
+ }
453
+ setPicker({
454
+ title: `Provider · ${providerItem._providerName}`,
455
+ description: 'Choose an OAuth login action.',
456
+ footer: () => providerActionFooter(provider),
457
+ help: '↑/↓ Select · Enter Choose · Esc Providers',
458
+ indexMode: 'always',
459
+ labelWidth: 22,
460
+ pickerKey: `providers-action:${providerItem.value}`,
461
+ initialIndex: 0,
462
+ items: oauthActions,
463
+ onSelect: (_detailValue, detail) => {
464
+ if (detail._action === 'login-oauth') {
465
+ startOAuthLogin(providerItem);
466
+ return;
467
+ }
468
+ if (detail._action === 'forget-oauth') {
469
+ try {
470
+ store.forgetProviderAuth(providerItem._providerId);
471
+ clearModelCaches('all');
472
+ reopenProviders();
473
+ } catch (e) {
474
+ store.pushNotice(`auth-forget failed: ${e?.message || e}`, 'error');
475
+ }
476
+ }
477
+ },
478
+ onCancel: reopenProviders,
479
+ });
480
+ };
481
+
482
+ const openLocalProviderActions = (providerItem) => {
483
+ rememberProviderSelection(providerItem);
484
+ const provider = providerItem._provider || {};
485
+ const localActions = [
486
+ {
487
+ value: 'set-local-url',
488
+ label: providerItem._enabled ? 'Update Base URL' : 'Enable / Set URL',
489
+ description: providerDetailText(provider) || providerItem._defaultURL,
490
+ _action: 'set-local-url',
491
+ },
492
+ ];
493
+ if (providerItem._enabled) {
494
+ localActions.push({
495
+ value: 'disable-local',
496
+ label: 'Disable provider',
497
+ description: 'keep URL but stop using this local provider',
498
+ _action: 'disable-local',
499
+ });
500
+ }
501
+ setPicker({
502
+ title: `Provider · ${providerItem._providerName}`,
503
+ description: 'Choose a local endpoint action.',
504
+ footer: () => providerActionFooter(provider),
505
+ help: '↑/↓ Select · Enter Choose · Esc Providers',
506
+ indexMode: 'always',
507
+ labelWidth: 22,
508
+ pickerKey: `providers-action:${providerItem.value}`,
509
+ initialIndex: 0,
510
+ items: localActions,
511
+ onSelect: (_detailValue, detail) => {
512
+ setPicker(null);
513
+ if (detail._action === 'set-local-url') {
514
+ setProviderPrompt({
515
+ kind: 'local-url',
516
+ providerId: providerItem._providerId,
517
+ label: providerItem._providerName,
518
+ defaultURL: providerItem._baseURL || providerItem._defaultURL,
519
+ afterSave: returnTo,
520
+ });
521
+ return;
522
+ }
523
+ if (detail._action === 'disable-local') {
524
+ try {
525
+ store.setLocalProvider(providerItem._providerId, { enabled: false, baseURL: providerItem._baseURL });
526
+ clearModelCaches('all');
527
+ reopenProviders();
528
+ } catch (e) {
529
+ store.pushNotice(`local provider update failed: ${e?.message || e}`, 'error');
530
+ }
531
+ }
532
+ },
533
+ onCancel: reopenProviders,
534
+ });
535
+ };
536
+
537
+ setPicker({
538
+ title: options.title || 'Providers',
539
+ description: options.description || 'Choose a provider. Enter opens provider actions.',
540
+ footer: providerFooter,
541
+ footerGapRows: 1,
542
+ help: options.confirmBar ? undefined : '↑/↓ Select · Enter Open · Esc Back',
543
+ indexMode: 'always',
544
+ labelWidth: 18,
545
+ metaWidth: 12,
546
+ pickerKey: `providers-main:${options.highlightProviderValue || 'root'}`,
547
+ initialIndex: providerMainInitialIndex(),
548
+ items,
549
+ confirmBar: options.confirmBar || null,
550
+ onHighlight: (_value, item) => {
551
+ if (item?._providerId) rememberProviderSelection(item);
552
+ },
553
+ onSelect: (_value, item) => {
554
+ setPicker(null);
555
+ if (item._type === 'continue') {
556
+ onContinue?.();
557
+ return;
558
+ }
559
+ if (item._type === 'api-key') {
560
+ openApiProviderActions(item);
561
+ return;
562
+ }
563
+ if (item._type === 'oauth') {
564
+ openOAuthProviderActions(item);
565
+ return;
566
+ }
567
+ if (item._type === 'local') {
568
+ openLocalProviderActions(item);
569
+ }
570
+ },
571
+ onCancel: () => {
572
+ setPicker(null);
573
+ if (onCancel) onCancel();
574
+ else if (returnTo) returnTo();
575
+ },
576
+ });
577
+ };
578
+
579
+ return { openProviderSetupPicker };
580
+ }
@@ -0,0 +1,55 @@
1
+ /**
2
+ * resume-picker.mjs — the /resume saved-chat session picker.
3
+ *
4
+ * Extracted from App.jsx behavior-preservingly as a dependency-injection
5
+ * factory: openResumePicker drives setPicker and reads live store state, so it
6
+ * can't be pure. The function body is the original App logic verbatim, with
7
+ * closure identifiers (store, setPicker, and the two session formatters from
8
+ * projects.mjs) threaded in through the factory argument.
9
+ */
10
+ export function createResumePicker({
11
+ store,
12
+ setPicker,
13
+ formatSessionUpdatedAt,
14
+ formatSessionMessageCount,
15
+ }) {
16
+ const openResumePicker = () => {
17
+ let sessions;
18
+ try {
19
+ sessions = store.listSessions();
20
+ } catch (e) {
21
+ store.pushNotice(`could not list saved chats: ${e?.message || e}`, 'error');
22
+ return;
23
+ }
24
+ if (!sessions || sessions.length === 0) {
25
+ store.pushNotice('no saved chats', 'warn');
26
+ return;
27
+ }
28
+ const items = sessions.map((s) => {
29
+ const preview = String(s.preview || '').replace(/\n/g, ' ').trim();
30
+ const count = formatSessionMessageCount(s.messageCount);
31
+ return {
32
+ value: s.id,
33
+ label: `${formatSessionUpdatedAt(s.updatedAt)} ${count}`,
34
+ description: preview || '(no message)',
35
+ };
36
+ });
37
+ setPicker({
38
+ title: 'Resume',
39
+ description: 'Restore a saved chat session.',
40
+ items,
41
+ labelWidth: 21,
42
+ onSelect: (value) => {
43
+ setPicker(null);
44
+ void store.resume(value)
45
+ .then(ok => store.pushNotice(ok ? `Resumed ${value}` : 'Couldn’t resume chat.', ok ? 'info' : 'warn'))
46
+ .catch((e) => store.pushNotice(`Couldn’t resume chat: ${e?.message || e}`, 'error'));
47
+ },
48
+ onCancel: () => {
49
+ setPicker(null);
50
+ },
51
+ });
52
+ };
53
+
54
+ return { openResumePicker };
55
+ }