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,497 @@
1
+ // Background cycle scheduling cluster, extracted from index.mjs (pass 3).
2
+ //
3
+ // This owns the mutually-referential cycle machinery that pass-2 flagged as
4
+ // entangled: cycle-health ledger (_cycleHealth), the run-state file, the
5
+ // cycle1 outer coalesce layer (_startCycle1Run/_awaitCycle1Run), the scheduled
6
+ // enqueue/retry paths for cycle1/2/3, checkCycles(), and the self-rescheduling
7
+ // tick loop. index.mjs keeps lifecycle ownership by injecting live getters
8
+ // (getDb/getConfig/setConfig) plus the cycle runners and LLM adapters.
9
+ //
10
+ // Factory contract — everything the extracted functions closed over in the
11
+ // facade is passed in:
12
+ // getDb() -> live db handle (null before _initStore)
13
+ // getConfig() -> live mainConfig
14
+ // setConfig(cfg) -> checkCycles re-reads config each tick (poll-on-use)
15
+ // dataDir -> DATA_DIR
16
+ // log -> __mixdogMemoryLog
17
+ // getCycleLastRun / setCycleLastRun -> meta-backed cycle timestamps
18
+ // readMainConfig / memoryCyclesEnabled -> config-flag helpers
19
+ // getCycle{1,2,3}CallLlm -> in-process LLM adapters
20
+ // runCycle1 / runCycle2 / runCycle3 / parseInterval / flushRawEmbeddings
21
+ // getInFlightCycle1 -> inner cycle1 guard handle (rebuild drain)
22
+ // claimAndMarkScheduledCycle / resolveCoalesceMaxRetries /
23
+ // scheduleCoalescedCycleRetry -> coalesced queue primitives
24
+ // scheduledCycle{1,2,3}Signature -> queue signatures
25
+ // cycleStateFile -> path to memory-cycle-state.json
26
+ import fs from 'node:fs'
27
+
28
+ const CYCLE1_HEALTH_OVERDUE_MS = 5 * 60_000
29
+ const CYCLE1_AUTO_RESTART_COOLDOWN_MS = 5 * 60_000
30
+ const BACKLOG_WARN_COOLDOWN_MS = 10 * 60_000
31
+ const BACKLOG_WARN_PENDING = 500
32
+ const BACKLOG_WARN_FAILURES = 5
33
+
34
+ export function createCycleScheduler(deps) {
35
+ const {
36
+ getDb,
37
+ getConfig,
38
+ setConfig,
39
+ dataDir,
40
+ log = () => {},
41
+ getCycleLastRun,
42
+ setCycleLastRun,
43
+ readMainConfig,
44
+ memoryCyclesEnabled,
45
+ getCycle1CallLlm,
46
+ getCycle2CallLlm,
47
+ getCycle3CallLlm,
48
+ runCycle1,
49
+ runCycle2,
50
+ runCycle3,
51
+ parseInterval,
52
+ flushRawEmbeddings,
53
+ getInFlightCycle1,
54
+ claimAndMarkScheduledCycle,
55
+ resolveCoalesceMaxRetries,
56
+ scheduleCoalescedCycleRetry,
57
+ scheduledCycle1Signature,
58
+ scheduledCycle2Signature,
59
+ scheduledCycle3Signature,
60
+ cycleStateFile,
61
+ } = deps
62
+
63
+ // ── Cycle health state ────────────────────────────────────────────────────
64
+ const _cycleHealth = {
65
+ cycle1: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
66
+ cycle2: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
67
+ cycle3: { last_success_at: 0, last_error_at: 0, last_error: null, consecutive_failures: 0 },
68
+ }
69
+ let _cycleRunning = null // { cycle, started_at }
70
+ let _cycleBacklogSnapshot = { unchunked: 0, cycle2_pending: 0, at: 0 }
71
+ let _lastBacklogWarnAt = 0
72
+
73
+ // ── Cycle1 outer coalesce layer + tick loop state ─────────────────────────
74
+ let _cycle1InFlight = null
75
+ let _cycle2InFlight = false
76
+ let _cycle3InFlight = false
77
+ let _rawEmbedFlushInFlight = false
78
+ let _checkCyclesInFlight = false
79
+ let _cyclesActive = false
80
+ let _cycleInterval = null
81
+ let _startupTimeout = null
82
+
83
+ function _writeCycleStateFile() {
84
+ try {
85
+ fs.writeFileSync(cycleStateFile, JSON.stringify({
86
+ running: _cycleRunning,
87
+ backlog: _cycleBacklogSnapshot,
88
+ cycles: _cycleHealth,
89
+ updatedAt: Date.now(),
90
+ }))
91
+ } catch { /* best-effort; statusline just shows nothing */ }
92
+ }
93
+
94
+ function markCycleRunning(cycle) {
95
+ _cycleRunning = { cycle, started_at: Date.now() }
96
+ _writeCycleStateFile()
97
+ }
98
+
99
+ function markCycleDone(cycle, ok, err = null) {
100
+ const h = _cycleHealth[cycle]
101
+ if (h) {
102
+ const now = Date.now()
103
+ if (ok) { h.last_success_at = now; h.consecutive_failures = 0; h.last_error = null }
104
+ else { h.last_error_at = now; h.consecutive_failures += 1; h.last_error = String(err || 'unknown').slice(0, 200) }
105
+ if (!ok && h.consecutive_failures >= BACKLOG_WARN_FAILURES) {
106
+ _warnCycleHealth(`${cycle} failing repeatedly (consecutive=${h.consecutive_failures}, last="${h.last_error}")`)
107
+ }
108
+ }
109
+ if (_cycleRunning?.cycle === cycle) _cycleRunning = null
110
+ _writeCycleStateFile()
111
+ }
112
+
113
+ function _warnCycleHealth(msg) {
114
+ const now = Date.now()
115
+ if (now - _lastBacklogWarnAt < BACKLOG_WARN_COOLDOWN_MS) return
116
+ _lastBacklogWarnAt = now
117
+ log(`[cycle-health] WARN ${msg}\n`)
118
+ }
119
+
120
+ async function recordCycle1Result(result) {
121
+ const now = Date.now()
122
+ await setCycleLastRun('cycle1_heartbeat', now)
123
+ const skipped = result?.skippedInFlight === true
124
+ const coalescedNoop = result?.coalescedRetryNoop === true
125
+ const allFailed = !skipped
126
+ && Number(result?.chunks ?? 0) === 0
127
+ && Number(result?.processed ?? 0) === 0
128
+ && Number(result?.skipped ?? 0) > 0
129
+ if (!skipped && !coalescedNoop && !allFailed) {
130
+ await setCycleLastRun('cycle1', now)
131
+ }
132
+ if (!skipped && !coalescedNoop) markCycleDone('cycle1', !allFailed, allFailed ? 'all rows skipped' : null)
133
+ }
134
+
135
+ function _startCycle1Run(config = {}, options = {}) {
136
+ if (typeof options?.callLlm !== 'function') {
137
+ options = { ...options, callLlm: getCycle1CallLlm() }
138
+ }
139
+ markCycleRunning('cycle1')
140
+ _cycle1InFlight = (async () => {
141
+ try {
142
+ const result = await runCycle1(getDb(), config, options, dataDir)
143
+ if (typeof options?.onCoalescedSuccess !== 'function') {
144
+ await recordCycle1Result(result)
145
+ }
146
+ return result
147
+ } catch (err) {
148
+ markCycleDone('cycle1', false, err?.message || err)
149
+ throw err
150
+ } finally {
151
+ if (_cycleRunning?.cycle === 'cycle1') { _cycleRunning = null; _writeCycleStateFile() }
152
+ if (_cycle1InFlight === promise) _cycle1InFlight = null
153
+ }
154
+ })()
155
+ const promise = _cycle1InFlight
156
+ return _cycle1InFlight
157
+ }
158
+
159
+ async function _awaitCycle1Run(config = {}, options = {}) {
160
+ const target = _cycle1InFlight || _startCycle1Run(config, options)
161
+ const callerDeadlineMs = Number(options.callerDeadlineMs) || 0
162
+ if (callerDeadlineMs <= 0) return await target
163
+ let timer
164
+ const deadlinePromise = new Promise((resolve) => {
165
+ timer = setTimeout(() => {
166
+ resolve({
167
+ processed: 0,
168
+ chunks: 0,
169
+ skipped: 0,
170
+ sessions: 0,
171
+ skippedInFlight: true,
172
+ timedOutWaiting: true,
173
+ callerDeadlineMs,
174
+ })
175
+ }, callerDeadlineMs)
176
+ })
177
+ try {
178
+ return await Promise.race([target, deadlinePromise])
179
+ } finally {
180
+ clearTimeout(timer)
181
+ }
182
+ }
183
+
184
+ function periodicCycle1Config() {
185
+ return {
186
+ min_batch: 20,
187
+ session_cap: 2,
188
+ batch_size: 50,
189
+ concurrency: 2,
190
+ ...(getConfig()?.cycle1 || {}),
191
+ }
192
+ }
193
+
194
+ async function enqueueScheduledCycle(kind, intervalMs, signature) {
195
+ const claim = await claimAndMarkScheduledCycle(getDb(), kind, intervalMs, signature, { reason: 'scheduled' })
196
+ return claim.claimed === true
197
+ }
198
+
199
+ async function enqueueScheduledCycle1(intervalMs, _reason = 'scheduled') {
200
+ const config = periodicCycle1Config()
201
+ const signature = scheduledCycle1Signature(config)
202
+ if (await enqueueScheduledCycle('cycle1', intervalMs, signature)) {
203
+ scheduleScheduledCycle1(config, signature)
204
+ }
205
+ }
206
+
207
+ async function enqueueScheduledCycle2(intervalMs, _reason = 'scheduled') {
208
+ const config = getConfig()?.cycle2 || {}
209
+ const signature = scheduledCycle2Signature(config)
210
+ if (await enqueueScheduledCycle('cycle2', intervalMs, signature)) {
211
+ scheduleScheduledCycle2(config, signature)
212
+ }
213
+ }
214
+
215
+ async function enqueueScheduledCycle3(intervalMs, _reason = 'scheduled') {
216
+ const config = getConfig() || {}
217
+ const signature = scheduledCycle3Signature(config)
218
+ if (await enqueueScheduledCycle('cycle3', intervalMs, signature)) {
219
+ scheduleScheduledCycle3(config, signature)
220
+ }
221
+ }
222
+
223
+ function scheduleScheduledCycle1(config, signature, attempt = 0) {
224
+ const maxRetries = resolveCoalesceMaxRetries(config, 3)
225
+ if (attempt > maxRetries) {
226
+ log('[cycle1] scheduled queue retry cap reached\n')
227
+ return
228
+ }
229
+ scheduleCoalescedCycleRetry(getDb(), 'cycle1', async () => {
230
+ if (!memoryCyclesEnabled()) return
231
+ if (_cycle1InFlight) {
232
+ scheduleScheduledCycle1(config, signature, attempt + 1)
233
+ return
234
+ }
235
+ const result = await _awaitCycle1Run(config, {
236
+ coalescedRetry: true,
237
+ onCoalescedSuccess: recordCycle1Result,
238
+ })
239
+ if (result?.skippedInFlight) scheduleScheduledCycle1(config, signature, attempt + 1)
240
+ }, config, signature)
241
+ }
242
+
243
+ function scheduleScheduledCycle2(config, signature, attempt = 0) {
244
+ const maxRetries = resolveCoalesceMaxRetries(config, 3)
245
+ if (attempt > maxRetries) {
246
+ log('[cycle2] scheduled queue retry cap reached\n')
247
+ return
248
+ }
249
+ scheduleCoalescedCycleRetry(getDb(), 'cycle2', async () => {
250
+ if (!memoryCyclesEnabled()) return
251
+ if (_cycle2InFlight) {
252
+ scheduleScheduledCycle2(config, signature, attempt + 1)
253
+ return
254
+ }
255
+ _cycle2InFlight = true
256
+ markCycleRunning('cycle2')
257
+ try {
258
+ let c2Options = {
259
+ coalescedRetry: true,
260
+ onCoalescedSuccess: _finalizeCycle2Run,
261
+ }
262
+ if (typeof c2Options?.callLlm !== 'function') {
263
+ c2Options = { ...c2Options, callLlm: getCycle2CallLlm() }
264
+ }
265
+ const result = await runCycle2(getDb(), config, c2Options, dataDir)
266
+ if (result?.skippedInFlight) {
267
+ scheduleScheduledCycle2(config, signature, attempt + 1)
268
+ } else if (result?.coalescedRetryNoop) {
269
+ log('[cycle2] scheduled queue noop\n')
270
+ } else if (result?.ok === false) {
271
+ await _finalizeCycle2Run(result)
272
+ }
273
+ } catch (err) {
274
+ log(`[cycle2] scheduled queue failed: ${err?.message || err}\n`)
275
+ markCycleDone('cycle2', false, err?.message || err)
276
+ } finally {
277
+ _cycle2InFlight = false
278
+ if (_cycleRunning?.cycle === 'cycle2') { _cycleRunning = null; _writeCycleStateFile() }
279
+ }
280
+ }, config, signature)
281
+ }
282
+
283
+ function scheduleScheduledCycle3(config, signature, attempt = 0) {
284
+ const retryConfig = config?.cycle3 || config
285
+ const maxRetries = resolveCoalesceMaxRetries(retryConfig, 3)
286
+ if (attempt > maxRetries) {
287
+ log('[cycle3] scheduled queue retry cap reached\n')
288
+ return
289
+ }
290
+ scheduleCoalescedCycleRetry(getDb(), 'cycle3', async () => {
291
+ if (!memoryCyclesEnabled()) return
292
+ if (_cycle3InFlight) {
293
+ scheduleScheduledCycle3(config, signature, attempt + 1)
294
+ return
295
+ }
296
+ _cycle3InFlight = true
297
+ markCycleRunning('cycle3')
298
+ try {
299
+ let c3Options = {
300
+ coalescedRetry: true,
301
+ onCoalescedSuccess: async () => { await setCycleLastRun('cycle3', Date.now()); markCycleDone('cycle3', true) },
302
+ }
303
+ if (typeof c3Options?.callLlm !== 'function') {
304
+ c3Options = { ...c3Options, callLlm: getCycle3CallLlm() }
305
+ }
306
+ const result = await runCycle3(getDb(), config, dataDir, c3Options)
307
+ if (result?.skippedInFlight) {
308
+ scheduleScheduledCycle3(config, signature, attempt + 1)
309
+ } else if (result?.coalescedRetryNoop) {
310
+ log('[cycle3] scheduled queue noop\n')
311
+ }
312
+ } catch (err) {
313
+ log(`[cycle3] scheduled queue failed: ${err?.message || err}\n`)
314
+ markCycleDone('cycle3', false, err?.message || err)
315
+ } finally {
316
+ _cycle3InFlight = false
317
+ if (_cycleRunning?.cycle === 'cycle3') { _cycleRunning = null; _writeCycleStateFile() }
318
+ }
319
+ }, retryConfig, signature)
320
+ }
321
+
322
+ async function _finalizeCycle2Run(result) {
323
+ if (result?.skippedInFlight) {
324
+ log('[cycle2] skipped: in flight\n')
325
+ return
326
+ }
327
+ if (result.ok) {
328
+ await setCycleLastRun('cycle2', Date.now())
329
+ await setCycleLastRun('cycle2_last_error', '')
330
+ log('[cycle2] completed\n')
331
+ markCycleDone('cycle2', true)
332
+ } else {
333
+ await setCycleLastRun('cycle2_last_error', result.error || 'unknown error')
334
+ log(`[cycle2] failed: ${result.error}\n`)
335
+ markCycleDone('cycle2', false, result.error || 'unknown error')
336
+ }
337
+ }
338
+
339
+ async function checkCycles() {
340
+ const mainConfig = readMainConfig()
341
+ setConfig(mainConfig)
342
+ const cyclesOn = memoryCyclesEnabled()
343
+ const db = getDb()
344
+
345
+ const cycle1Ms = parseInterval(mainConfig?.cycle1?.interval || '10m')
346
+ const cycle2Ms = parseInterval(mainConfig?.cycle2?.interval || '1h')
347
+ const cycle3Ms = parseInterval(mainConfig?.cycle3?.interval || '24h')
348
+
349
+ const now = Date.now()
350
+ const last = await getCycleLastRun()
351
+
352
+ if (cyclesOn) {
353
+ const cycle1OverdueMs = last.cycle1 > 0
354
+ ? Math.max(0, now - last.cycle1 - cycle1Ms)
355
+ : 0
356
+ if (cycle1OverdueMs > CYCLE1_HEALTH_OVERDUE_MS) {
357
+ const lastSeen = last.cycle1 ? new Date(last.cycle1).toISOString() : 'never'
358
+ log(
359
+ `[cycle1] overdue by ${Math.floor(cycle1OverdueMs / 60_000)}min `
360
+ + `(last=${lastSeen}). Pool B Anthropic shard may be cold.\n`
361
+ )
362
+ const lastAutoRestart = last.cycle1_autoRestart || 0
363
+ if (now - lastAutoRestart >= CYCLE1_AUTO_RESTART_COOLDOWN_MS) {
364
+ await setCycleLastRun('cycle1_autoRestart_attempt', now)
365
+ try {
366
+ const result = await _awaitCycle1Run(periodicCycle1Config())
367
+ await setCycleLastRun('cycle1_autoRestart', Date.now())
368
+ log(
369
+ `[cycle1] auto-restart completed chunks=${result?.chunks ?? 0} processed=${result?.processed ?? 0}\n`
370
+ )
371
+ return
372
+ } catch (e) {
373
+ log(`[cycle1] auto-restart error: ${e.message}\n`)
374
+ return
375
+ }
376
+ }
377
+ }
378
+
379
+ if (now - last.cycle1 >= cycle1Ms) {
380
+ await enqueueScheduledCycle1(cycle1Ms, 'scheduled')
381
+ }
382
+
383
+ if (now - last.cycle2 >= cycle2Ms) {
384
+ await enqueueScheduledCycle2(cycle2Ms, 'scheduled')
385
+ }
386
+
387
+ if (now - last.cycle3 >= cycle3Ms) {
388
+ await enqueueScheduledCycle3(cycle3Ms, 'scheduled')
389
+ }
390
+ }
391
+
392
+ try {
393
+ const unchunked = Number((await db.query(
394
+ `SELECT COUNT(*) c FROM entries WHERE chunk_root IS NULL AND NULLIF(btrim(session_id), '') IS NOT NULL`,
395
+ )).rows[0]?.c ?? 0)
396
+ const cycle2Pending = Number((await db.query(
397
+ `SELECT COUNT(*) c FROM entries WHERE is_root = 1 AND status = 'pending'`,
398
+ )).rows[0]?.c ?? 0)
399
+ _cycleBacklogSnapshot = { unchunked, cycle2_pending: cycle2Pending, at: now }
400
+ _writeCycleStateFile()
401
+ if (unchunked > BACKLOG_WARN_PENDING || cycle2Pending > BACKLOG_WARN_PENDING) {
402
+ _warnCycleHealth(`backlog unchunked=${unchunked} cycle2_pending=${cycle2Pending}`)
403
+ }
404
+ if (unchunked > 0 && !_rawEmbedFlushInFlight) {
405
+ _rawEmbedFlushInFlight = true
406
+ flushRawEmbeddings(db, { limit: 200 })
407
+ .then((r) => {
408
+ if (r.attempted > 0) log(`[embed] raw fallback flush attempted=${r.attempted} embedded=${r.embedded}\n`)
409
+ })
410
+ .catch((err) => log(`[embed] raw fallback flush failed: ${err?.message || err}\n`))
411
+ .finally(() => { _rawEmbedFlushInFlight = false })
412
+ }
413
+ const SELF_KICK_STALE_MS = 2 * 3600_000
414
+ const c1Stale = (_cycleHealth.cycle1.last_success_at || last.cycle1 || 0) < now - SELF_KICK_STALE_MS
415
+ const c2Stale = (_cycleHealth.cycle2.last_success_at || last.cycle2 || 0) < now - SELF_KICK_STALE_MS
416
+ if (cyclesOn && c1Stale && unchunked > BACKLOG_WARN_PENDING) {
417
+ _warnCycleHealth(`cycle1 self-kick: no success 2h+, unchunked=${unchunked}`)
418
+ await enqueueScheduledCycle1(0, 'self-kick')
419
+ } else if (cyclesOn && c2Stale && cycle2Pending > BACKLOG_WARN_PENDING) {
420
+ _warnCycleHealth(`cycle2 self-kick: no success 2h+, pending=${cycle2Pending}`)
421
+ await enqueueScheduledCycle2(0, 'self-kick')
422
+ }
423
+ } catch { /* counts are best-effort; never fail the tick */ }
424
+ }
425
+
426
+ async function _runCheckCyclesGuarded() {
427
+ if (_checkCyclesInFlight) return
428
+ _checkCyclesInFlight = true
429
+ try { await checkCycles() }
430
+ catch (e) { log(`[cycle-tick] error: ${e.message}\n`) }
431
+ finally { _checkCyclesInFlight = false }
432
+ }
433
+
434
+ function _scheduleNextCheck() {
435
+ _cycleInterval = setTimeout(async () => {
436
+ _cycleInterval = null
437
+ try {
438
+ await _runCheckCyclesGuarded()
439
+ } catch (e) {
440
+ log(`[cycle-tick] re-arm guard caught: ${e?.message || e}\n`)
441
+ } finally {
442
+ if (_cyclesActive) _scheduleNextCheck()
443
+ }
444
+ }, 60_000)
445
+ }
446
+
447
+ function startCycles() {
448
+ if (_cyclesActive) return
449
+ _cyclesActive = true
450
+ // Boot reset: a previous daemon that crashed mid-run leaves the state
451
+ // file's `running` marker set, and the statusline keeps showing a
452
+ // phantom "Memory cycle running" spinner until its 10-minute stale
453
+ // guard kicks in. No cycle can be running when this scheduler starts,
454
+ // so clear the marker (health/backlog reset to this process's state).
455
+ _cycleRunning = null
456
+ _writeCycleStateFile()
457
+ _scheduleNextCheck()
458
+ _startupTimeout = setTimeout(() => { void _runCheckCyclesGuarded() }, 30_000)
459
+ }
460
+
461
+ function stopCycles() {
462
+ _cyclesActive = false
463
+ if (_cycleInterval) { clearTimeout(_cycleInterval); _cycleInterval = null }
464
+ if (_startupTimeout) { clearTimeout(_startupTimeout); _startupTimeout = null }
465
+ }
466
+
467
+ // Full-shutdown reset — baseline stop() cleared these module-level flags so
468
+ // a later init() starts from a clean slate instead of coalescing onto (or
469
+ // skipping behind) pre-stop in-flight work / stale running state.
470
+ function resetInFlight() {
471
+ _cycle1InFlight = null
472
+ _cycle2InFlight = false
473
+ _cycle3InFlight = false
474
+ _checkCyclesInFlight = false
475
+ _rawEmbedFlushInFlight = false
476
+ _cycleRunning = null
477
+ }
478
+
479
+ return {
480
+ // health/state accessors (HTTP /health, statusline)
481
+ getCycleHealth: () => _cycleHealth,
482
+ getCycleRunning: () => _cycleRunning,
483
+ getCycleBacklogSnapshot: () => _cycleBacklogSnapshot,
484
+ // cycle1 in-flight handle (rebuild drain in index.mjs)
485
+ getCycle1InFlight: () => _cycle1InFlight,
486
+ // run primitives used by MCP action handlers
487
+ startCycle1Run: _startCycle1Run,
488
+ awaitCycle1Run: _awaitCycle1Run,
489
+ finalizeCycle2Run: _finalizeCycle2Run,
490
+ periodicCycle1Config,
491
+ // lifecycle
492
+ startCycles,
493
+ stopCycles,
494
+ resetInFlight,
495
+ checkCycles,
496
+ }
497
+ }
@@ -0,0 +1,34 @@
1
+ // Scheduled-cycle request-signature helpers extracted from index.mjs.
2
+ // Pure functions of the passed `config` object; they call the imported
3
+ // makeCycleRequestSignature and touch no module state (no db/timers).
4
+ // index.mjs imports these; signatures and behavior are unchanged.
5
+
6
+ import { makeCycleRequestSignature } from './memory-cycle-requests.mjs'
7
+
8
+ export function scheduledCycle1Signature(config) {
9
+ return makeCycleRequestSignature('cycle1', config, {
10
+ preset: undefined,
11
+ concurrency: undefined,
12
+ maxConcurrent: undefined,
13
+ })
14
+ }
15
+
16
+ export function scheduledCycle2Signature(config) {
17
+ return makeCycleRequestSignature('cycle2', config, {
18
+ cascadePreset: undefined,
19
+ concurrency: undefined,
20
+ })
21
+ }
22
+
23
+ export function scheduledCycle3ApplyMode(config) {
24
+ const raw = String(config?.cycle3?.applyMode || 'conservative').trim().toLowerCase()
25
+ return (raw === 'proposal' || raw === 'dry-run' || raw === 'dryrun') ? 'proposal' : 'conservative'
26
+ }
27
+
28
+ export function scheduledCycle3Signature(config) {
29
+ const retryConfig = config?.cycle3 || config
30
+ return makeCycleRequestSignature('cycle3', retryConfig, {
31
+ applyMode: scheduledCycle3ApplyMode(config),
32
+ apply: undefined,
33
+ })
34
+ }
@@ -0,0 +1,58 @@
1
+ // Boot-edge embedding warmup queue, extracted from index.mjs (pass 2).
2
+ //
3
+ // ONNX session creation on the embedding worker thread is CPU-heavy, so it must
4
+ // not overlap the worker's own init (DB open, schema, cycle wiring). The warmup
5
+ // is queued during _initStore and fired at the _initRuntime completion edge, so
6
+ // it starts the instant boot's CPU-heavy work is done — no magic-number delay.
7
+ //
8
+ // This is a small pure factory: index.mjs owns the DATA_DIR-derived meta path
9
+ // and the embedding-provider imports, injecting them here as callbacks. No
10
+ // import-time side effects.
11
+ export function createEmbeddingWarmup({
12
+ canStart,
13
+ warmup,
14
+ getDims,
15
+ persistMeta,
16
+ log = () => {},
17
+ }) {
18
+ let _pending = null
19
+
20
+ // Queue the warmup; fireDeferred() runs it once boot completes. Re-queuing
21
+ // overwrites any prior pending closure (matches the original single-slot
22
+ // module var). MIXDOG_EMBED_WARMUP=0 (checked via canStart) disables it.
23
+ function schedule(metaPath, metaKey) {
24
+ if (!canStart()) {
25
+ // Silent skip here previously made "warmup never ran" boots
26
+ // indistinguishable from failed warmups. One line, boot-edge only.
27
+ log('[memory-service] embedding warmup skipped (disabled by env/secondary mode) — recall stays lexical until first embed\n')
28
+ return
29
+ }
30
+ _pending = () => {
31
+ warmup()
32
+ .then(() => {
33
+ const measured = Number(getDims())
34
+ try {
35
+ persistMeta(metaPath, { ...metaKey, dims: measured })
36
+ } catch (e) {
37
+ log(`[memory-service] could not persist embedding-meta: ${e?.message || e}\n`)
38
+ }
39
+ })
40
+ .catch(err => {
41
+ log(`[memory-service] background warmup failed: ${err?.message || err}\n`)
42
+ })
43
+ }
44
+ }
45
+
46
+ function fireDeferred() {
47
+ const fire = _pending
48
+ if (!fire) return
49
+ _pending = null
50
+ fire()
51
+ }
52
+
53
+ function reset() {
54
+ _pending = null
55
+ }
56
+
57
+ return { schedule, fireDeferred, reset }
58
+ }
@@ -0,0 +1,57 @@
1
+ // HTTP wire helpers extracted from index.mjs. All pure request/response
2
+ // utilities with no module state — no db, _traceDb, or timer dependencies.
3
+ // index.mjs imports these; behavior and signatures are unchanged.
4
+
5
+ export function readBody(req) {
6
+ return new Promise((resolve, reject) => {
7
+ const chunks = []
8
+ req.on('data', c => chunks.push(c))
9
+ req.on('end', () => {
10
+ const raw = Buffer.concat(chunks).toString('utf8').trim()
11
+ if (!raw) { resolve({}); return }
12
+ try { resolve(JSON.parse(raw)) }
13
+ catch (error) {
14
+ const e = new Error(`invalid JSON body: ${error.message}`)
15
+ e.statusCode = 400
16
+ reject(e)
17
+ }
18
+ })
19
+ req.on('error', reject)
20
+ })
21
+ }
22
+
23
+ export function sendJson(res, data, status = 200) {
24
+ const body = JSON.stringify(data)
25
+ res.writeHead(status, {
26
+ 'Content-Type': 'application/json; charset=utf-8',
27
+ 'Content-Length': Buffer.byteLength(body),
28
+ })
29
+ res.end(body)
30
+ }
31
+
32
+ export function sendError(res, msg, status = 500) {
33
+ sendJson(res, { error: msg }, status)
34
+ }
35
+
36
+ // Origin/Referer guard for /admin/* mutation routes. Memory-service binds
37
+ // 127.0.0.1, but browser DNS-rebinding or a stray cross-origin fetch could
38
+ // still reach destructive endpoints (purge, backfill, entry mutations).
39
+ // Server-to-server callers (setup-server, hooks) issue raw http.request
40
+ // without a browser Origin/Referer, so absent headers pass; any non-loopback
41
+ // Origin/Referer is rejected. Mirrors setup-server.mjs isAllowedOrigin.
42
+ export function isLocalOrigin(req) {
43
+ const LOOP = /^https?:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?(\/|$)/i
44
+ const origin = req.headers.origin || ''
45
+ const referer = req.headers.referer || ''
46
+ if (origin && !LOOP.test(origin)) return false
47
+ if (referer && !LOOP.test(referer)) return false
48
+ return true
49
+ }
50
+
51
+ export function normalizeCoreProjectId(value, { allowStar = false } = {}) {
52
+ if (value == null) return null
53
+ const s = String(value).trim()
54
+ if (!s || s.toLowerCase() === 'common') return null
55
+ if (allowStar && s === '*') return '*'
56
+ return s
57
+ }