mixdog 0.7.18 → 0.8.1

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 (847) hide show
  1. package/README.md +37 -331
  2. package/package.json +67 -99
  3. package/scripts/boot-smoke.mjs +94 -0
  4. package/scripts/build-tui.mjs +52 -0
  5. package/scripts/compact-smoke.mjs +199 -0
  6. package/scripts/lead-workflow-smoke.mjs +598 -0
  7. package/scripts/live-worker-smoke.mjs +239 -0
  8. package/scripts/output-style-smoke.mjs +101 -0
  9. package/scripts/session-context-bench.mjs +172 -0
  10. package/scripts/smoke-loop-report.mjs +221 -0
  11. package/scripts/smoke-loop.mjs +201 -0
  12. package/scripts/smoke.mjs +113 -0
  13. package/scripts/tool-failures.mjs +143 -0
  14. package/scripts/tool-smoke.mjs +452 -0
  15. package/src/agents/debugger/AGENT.md +3 -0
  16. package/src/agents/debugger/agent.json +6 -0
  17. package/src/agents/explore/AGENT.md +4 -0
  18. package/src/agents/explore/agent.json +6 -0
  19. package/src/agents/heavy-worker/AGENT.md +3 -0
  20. package/src/agents/heavy-worker/agent.json +6 -0
  21. package/src/agents/maintainer/AGENT.md +3 -0
  22. package/src/agents/maintainer/agent.json +6 -0
  23. package/src/agents/reviewer/AGENT.md +3 -0
  24. package/src/agents/reviewer/agent.json +6 -0
  25. package/src/agents/scheduler-task.md +3 -0
  26. package/src/agents/web-researcher/AGENT.md +3 -0
  27. package/src/agents/web-researcher/agent.json +6 -0
  28. package/src/agents/webhook-handler.md +3 -0
  29. package/src/agents/worker/AGENT.md +3 -0
  30. package/src/agents/worker/agent.json +6 -0
  31. package/src/app.mjs +90 -0
  32. package/src/cli.mjs +11 -0
  33. package/src/defaults/hidden-roles.json +72 -0
  34. package/src/defaults/mixdog-config.template.json +15 -0
  35. package/src/hooks/lib/permission-evaluator.cjs +488 -0
  36. package/src/hooks/lib/settings-loader.cjs +112 -0
  37. package/src/lib/keychain-cjs.cjs +332 -0
  38. package/src/lib/plugin-paths.cjs +28 -0
  39. package/src/lib/rules-builder.cjs +315 -0
  40. package/src/mixdog-session-runtime.mjs +3813 -0
  41. package/src/output-styles/default.md +38 -0
  42. package/src/output-styles/extreme-simple.md +17 -0
  43. package/src/output-styles/simple.md +17 -0
  44. package/src/repl.mjs +330 -0
  45. package/src/rules/bridge/00-common.md +5 -0
  46. package/src/rules/bridge/20-skip-protocol.md +11 -0
  47. package/src/rules/bridge/30-explorer.md +4 -0
  48. package/src/rules/bridge/40-cycle1-agent.md +28 -0
  49. package/src/rules/bridge/41-cycle2-agent.md +59 -0
  50. package/src/rules/lead/00-tool-lead.md +5 -0
  51. package/src/rules/lead/01-general.md +5 -0
  52. package/src/rules/lead/02-channels.md +3 -0
  53. package/src/rules/lead/04-workflow.md +12 -0
  54. package/src/rules/shared/00-language.md +3 -0
  55. package/src/rules/shared/01-tool.md +3 -0
  56. package/src/runtime/agent/orchestrator/bridge-trace.mjs +814 -0
  57. package/src/runtime/agent/orchestrator/cache-mtime.mjs +60 -0
  58. package/src/runtime/agent/orchestrator/config.mjs +446 -0
  59. package/src/runtime/agent/orchestrator/context/collect.mjs +796 -0
  60. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +417 -0
  61. package/src/runtime/agent/orchestrator/internal-roles.mjs +188 -0
  62. package/src/runtime/agent/orchestrator/internal-tools.mjs +88 -0
  63. package/src/runtime/agent/orchestrator/mcp/client.mjs +345 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2104 -0
  65. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +784 -0
  66. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +341 -0
  67. package/src/runtime/agent/orchestrator/providers/gemini.mjs +1679 -0
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +959 -0
  69. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +213 -0
  70. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +38 -0
  71. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +471 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +615 -0
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +808 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +1719 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2587 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1953 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +136 -0
  78. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +317 -0
  79. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +109 -0
  80. package/src/runtime/agent/orchestrator/providers/registry.mjs +247 -0
  81. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +332 -0
  82. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +11 -0
  83. package/src/runtime/agent/orchestrator/providers/trace-utils.mjs +50 -0
  84. package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
  85. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  86. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +318 -0
  87. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +367 -0
  88. package/src/runtime/agent/orchestrator/session/compact.mjs +882 -0
  89. package/src/runtime/agent/orchestrator/session/context-utils.mjs +233 -0
  90. package/src/runtime/agent/orchestrator/session/loop.mjs +2269 -0
  91. package/src/runtime/agent/orchestrator/session/manager.mjs +2972 -0
  92. package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
  93. package/src/runtime/agent/orchestrator/session/store.mjs +870 -0
  94. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  95. package/src/runtime/agent/orchestrator/smart-bridge/bridge-llm.mjs +339 -0
  96. package/src/runtime/agent/orchestrator/smart-bridge/cache-strategy.mjs +419 -0
  97. package/src/runtime/agent/orchestrator/stall-policy.mjs +227 -0
  98. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +235 -0
  99. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +723 -0
  100. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
  101. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +389 -0
  102. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +637 -0
  103. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +165 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +104 -0
  105. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +194 -0
  106. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +596 -0
  107. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +110 -0
  108. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +153 -0
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +189 -0
  111. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +731 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +168 -0
  113. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +465 -0
  115. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +160 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +982 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1087 -0
  118. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +231 -0
  119. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +223 -0
  120. package/src/runtime/agent/orchestrator/tools/builtin.mjs +478 -0
  121. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  122. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4102 -0
  123. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  124. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +154 -0
  125. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +26 -0
  126. package/src/runtime/agent/orchestrator/tools/patch-binary-fetcher.mjs +143 -0
  127. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +18 -0
  128. package/src/runtime/agent/orchestrator/tools/patch.mjs +2772 -0
  129. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +114 -0
  130. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +880 -0
  131. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +312 -0
  132. package/src/runtime/channels/backends/discord.mjs +781 -0
  133. package/src/runtime/channels/data/voice-runtime-manifest.json +138 -0
  134. package/src/runtime/channels/index.mjs +3309 -0
  135. package/src/runtime/channels/lib/config.mjs +285 -0
  136. package/src/runtime/channels/lib/drop-trace.mjs +71 -0
  137. package/src/runtime/channels/lib/event-pipeline.mjs +81 -0
  138. package/src/runtime/channels/lib/holidays.mjs +138 -0
  139. package/src/runtime/channels/lib/hook-pipe-server.mjs +671 -0
  140. package/src/runtime/channels/lib/output-forwarder.mjs +765 -0
  141. package/src/runtime/channels/lib/runtime-paths.mjs +497 -0
  142. package/src/runtime/channels/lib/scheduler.mjs +710 -0
  143. package/src/runtime/channels/lib/session-discovery.mjs +102 -0
  144. package/src/runtime/channels/lib/state-file.mjs +68 -0
  145. package/src/runtime/channels/lib/status-snapshot.mjs +224 -0
  146. package/src/runtime/channels/lib/tool-format.mjs +122 -0
  147. package/src/runtime/channels/lib/transcript-discovery.mjs +195 -0
  148. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +734 -0
  149. package/src/runtime/channels/lib/webhook.mjs +1288 -0
  150. package/src/runtime/channels/tool-defs.mjs +177 -0
  151. package/src/runtime/lib/keychain-cjs.cjs +289 -0
  152. package/src/runtime/memory/data/runtime-manifest.json +40 -0
  153. package/src/runtime/memory/index.mjs +3706 -0
  154. package/src/runtime/memory/lib/core-memory-store.mjs +336 -0
  155. package/src/runtime/memory/lib/embedding-provider.mjs +275 -0
  156. package/src/runtime/memory/lib/embedding-worker.mjs +331 -0
  157. package/src/runtime/memory/lib/memory-cycle-requests.mjs +276 -0
  158. package/src/runtime/memory/lib/memory-cycle1.mjs +783 -0
  159. package/src/runtime/memory/lib/memory-cycle2.mjs +1389 -0
  160. package/src/runtime/memory/lib/memory-cycle3.mjs +646 -0
  161. package/src/runtime/memory/lib/memory-embed.mjs +300 -0
  162. package/src/runtime/memory/lib/memory-ops-policy.mjs +149 -0
  163. package/src/runtime/memory/lib/memory-recall-store.mjs +644 -0
  164. package/src/runtime/memory/lib/memory.mjs +418 -0
  165. package/src/runtime/memory/lib/pg/adapter.mjs +328 -0
  166. package/src/runtime/memory/lib/pg/process.mjs +366 -0
  167. package/src/runtime/memory/lib/pg/supervisor.mjs +495 -0
  168. package/src/runtime/memory/lib/runtime-fetcher.mjs +464 -0
  169. package/src/runtime/memory/lib/trace-store.mjs +734 -0
  170. package/src/runtime/memory/tool-defs.mjs +79 -0
  171. package/src/runtime/search/index.mjs +925 -0
  172. package/src/runtime/search/lib/config.mjs +61 -0
  173. package/src/runtime/search/lib/web-tools.mjs +1278 -0
  174. package/src/runtime/search/tool-defs.mjs +64 -0
  175. package/src/runtime/shared/atomic-file.mjs +435 -0
  176. package/src/runtime/shared/background-tasks.mjs +376 -0
  177. package/src/runtime/shared/child-guardian.mjs +98 -0
  178. package/src/runtime/shared/config.mjs +393 -0
  179. package/src/runtime/shared/err-text.mjs +121 -0
  180. package/src/runtime/shared/launcher-control.mjs +259 -0
  181. package/src/runtime/shared/llm/http-agent.mjs +129 -0
  182. package/src/runtime/shared/open-url.mjs +37 -0
  183. package/src/runtime/shared/plugin-paths.mjs +25 -0
  184. package/src/runtime/shared/process-shutdown.mjs +147 -0
  185. package/src/runtime/shared/schedules-store.mjs +70 -0
  186. package/src/runtime/shared/tool-execution-contract.mjs +104 -0
  187. package/src/runtime/shared/tool-surface.mjs +947 -0
  188. package/src/runtime/shared/user-cwd.mjs +221 -0
  189. package/src/runtime/shared/user-data-guard.mjs +232 -0
  190. package/src/runtime/shared/workspace-router.mjs +259 -0
  191. package/src/standalone/bridge-tool.mjs +1414 -0
  192. package/src/standalone/channel-admin.mjs +366 -0
  193. package/src/standalone/channel-worker-preload.cjs +3 -0
  194. package/src/standalone/channel-worker.mjs +353 -0
  195. package/src/standalone/explore-tool.mjs +233 -0
  196. package/src/standalone/hook-bus.mjs +246 -0
  197. package/src/standalone/plugin-admin.mjs +247 -0
  198. package/src/standalone/provider-admin.mjs +338 -0
  199. package/src/standalone/seeds.mjs +94 -0
  200. package/src/standalone/usage-dashboard.mjs +510 -0
  201. package/src/tui/App.jsx +5446 -0
  202. package/src/tui/components/AnsiText.jsx +199 -0
  203. package/src/tui/components/ContextPanel.jsx +265 -0
  204. package/src/tui/components/Markdown.jsx +205 -0
  205. package/src/tui/components/MarkdownTable.jsx +204 -0
  206. package/src/tui/components/Message.jsx +103 -0
  207. package/src/tui/components/Picker.jsx +317 -0
  208. package/src/tui/components/PromptInput.jsx +584 -0
  209. package/src/tui/components/QueuedCommands.jsx +47 -0
  210. package/src/tui/components/SlashCommandPalette.jsx +114 -0
  211. package/src/tui/components/Spinner.jsx +317 -0
  212. package/src/tui/components/StatusLine.jsx +87 -0
  213. package/src/tui/components/TextEntryPanel.jsx +323 -0
  214. package/src/tui/components/ToolExecution.jsx +791 -0
  215. package/src/tui/components/TurnDone.jsx +78 -0
  216. package/src/tui/components/UsagePanel.jsx +331 -0
  217. package/src/tui/dist/index.mjs +12420 -0
  218. package/src/tui/engine.mjs +2410 -0
  219. package/src/tui/figures.mjs +50 -0
  220. package/src/tui/hooks/useEngine.mjs +16 -0
  221. package/src/tui/index.jsx +254 -0
  222. package/src/tui/input-editing.mjs +242 -0
  223. package/src/tui/markdown/format-token.mjs +194 -0
  224. package/src/tui/paste-attachments.mjs +198 -0
  225. package/src/tui/runtime/shared/process-shutdown.mjs +1 -0
  226. package/src/tui/spinner-verbs.mjs +45 -0
  227. package/src/tui/theme.mjs +67 -0
  228. package/src/tui/time-format.mjs +53 -0
  229. package/src/ui/ansi.mjs +115 -0
  230. package/src/ui/markdown.mjs +195 -0
  231. package/src/ui/statusline.mjs +730 -0
  232. package/src/ui/tool-card.mjs +99 -0
  233. package/src/vendor/statusline/bin/statusline-lib.mjs +805 -0
  234. package/src/vendor/statusline/bin/statusline-route.mjs +596 -0
  235. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +285 -0
  236. package/src/vendor/statusline/src/gateway/claude-current.mjs +320 -0
  237. package/src/vendor/statusline/src/gateway/route-meta.mjs +753 -0
  238. package/src/vendor/statusline/src/gateway/session-routes.mjs +244 -0
  239. package/src/workflows/default/WORKFLOW.md +7 -0
  240. package/src/workflows/default/workflow.json +14 -0
  241. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  242. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  243. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  244. package/vendor/ink/build/colorize.d.ts +3 -0
  245. package/vendor/ink/build/colorize.js +48 -0
  246. package/vendor/ink/build/colorize.js.map +1 -0
  247. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  248. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  249. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  250. package/vendor/ink/build/components/AnimationContext.d.ts +9 -0
  251. package/vendor/ink/build/components/AnimationContext.js +13 -0
  252. package/vendor/ink/build/components/AnimationContext.js.map +1 -0
  253. package/vendor/ink/build/components/App.d.ts +24 -0
  254. package/vendor/ink/build/components/App.js +554 -0
  255. package/vendor/ink/build/components/App.js.map +1 -0
  256. package/vendor/ink/build/components/AppContext.d.ts +80 -0
  257. package/vendor/ink/build/components/AppContext.js +25 -0
  258. package/vendor/ink/build/components/AppContext.js.map +1 -0
  259. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  260. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  261. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  262. package/vendor/ink/build/components/Box.d.ts +130 -0
  263. package/vendor/ink/build/components/Box.js +34 -0
  264. package/vendor/ink/build/components/Box.js.map +1 -0
  265. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  266. package/vendor/ink/build/components/CursorContext.js +8 -0
  267. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  268. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  269. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  270. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  271. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  272. package/vendor/ink/build/components/ErrorOverview.js +90 -0
  273. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  274. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  275. package/vendor/ink/build/components/FocusContext.js +17 -0
  276. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  277. package/vendor/ink/build/components/Newline.d.ts +13 -0
  278. package/vendor/ink/build/components/Newline.js +8 -0
  279. package/vendor/ink/build/components/Newline.js.map +1 -0
  280. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  281. package/vendor/ink/build/components/Spacer.js +11 -0
  282. package/vendor/ink/build/components/Spacer.js.map +1 -0
  283. package/vendor/ink/build/components/Static.d.ts +24 -0
  284. package/vendor/ink/build/components/Static.js +28 -0
  285. package/vendor/ink/build/components/Static.js.map +1 -0
  286. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  287. package/vendor/ink/build/components/StderrContext.js +13 -0
  288. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  289. package/vendor/ink/build/components/StdinContext.d.ts +28 -0
  290. package/vendor/ink/build/components/StdinContext.js +20 -0
  291. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  292. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  293. package/vendor/ink/build/components/StdoutContext.js +13 -0
  294. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  295. package/vendor/ink/build/components/Text.d.ts +55 -0
  296. package/vendor/ink/build/components/Text.js +50 -0
  297. package/vendor/ink/build/components/Text.js.map +1 -0
  298. package/vendor/ink/build/components/Transform.d.ts +16 -0
  299. package/vendor/ink/build/components/Transform.js +15 -0
  300. package/vendor/ink/build/components/Transform.js.map +1 -0
  301. package/vendor/ink/build/cursor-helpers.d.ts +39 -0
  302. package/vendor/ink/build/cursor-helpers.js +62 -0
  303. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  304. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  305. package/vendor/ink/build/devtools-window-polyfill.js +68 -0
  306. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  307. package/vendor/ink/build/devtools.d.ts +1 -0
  308. package/vendor/ink/build/devtools.js +36 -0
  309. package/vendor/ink/build/devtools.js.map +1 -0
  310. package/vendor/ink/build/dom.d.ts +62 -0
  311. package/vendor/ink/build/dom.js +143 -0
  312. package/vendor/ink/build/dom.js.map +1 -0
  313. package/vendor/ink/build/get-max-width.d.ts +3 -0
  314. package/vendor/ink/build/get-max-width.js +10 -0
  315. package/vendor/ink/build/get-max-width.js.map +1 -0
  316. package/vendor/ink/build/hooks/use-animation.d.ts +49 -0
  317. package/vendor/ink/build/hooks/use-animation.js +87 -0
  318. package/vendor/ink/build/hooks/use-animation.js.map +1 -0
  319. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  320. package/vendor/ink/build/hooks/use-app.js +8 -0
  321. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  322. package/vendor/ink/build/hooks/use-box-metrics.d.ts +59 -0
  323. package/vendor/ink/build/hooks/use-box-metrics.js +81 -0
  324. package/vendor/ink/build/hooks/use-box-metrics.js.map +1 -0
  325. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  326. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  327. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  328. package/vendor/ink/build/hooks/use-focus-manager.d.ts +43 -0
  329. package/vendor/ink/build/hooks/use-focus-manager.js +18 -0
  330. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  331. package/vendor/ink/build/hooks/use-focus.d.ts +30 -0
  332. package/vendor/ink/build/hooks/use-focus.js +43 -0
  333. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  334. package/vendor/ink/build/hooks/use-input.d.ts +132 -0
  335. package/vendor/ink/build/hooks/use-input.js +126 -0
  336. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  337. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +6 -0
  338. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +12 -0
  339. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  340. package/vendor/ink/build/hooks/use-paste.d.ts +35 -0
  341. package/vendor/ink/build/hooks/use-paste.js +62 -0
  342. package/vendor/ink/build/hooks/use-paste.js.map +1 -0
  343. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  344. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  345. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  346. package/vendor/ink/build/hooks/use-stdin.d.ts +7 -0
  347. package/vendor/ink/build/hooks/use-stdin.js +9 -0
  348. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  349. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  350. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  351. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  352. package/vendor/ink/build/hooks/use-window-size.d.ts +18 -0
  353. package/vendor/ink/build/hooks/use-window-size.js +22 -0
  354. package/vendor/ink/build/hooks/use-window-size.js.map +1 -0
  355. package/vendor/ink/build/index.d.ts +42 -0
  356. package/vendor/ink/build/index.js +24 -0
  357. package/vendor/ink/build/index.js.map +1 -0
  358. package/vendor/ink/build/ink.d.ts +146 -0
  359. package/vendor/ink/build/ink.js +1022 -0
  360. package/vendor/ink/build/ink.js.map +1 -0
  361. package/vendor/ink/build/input-parser.d.ts +10 -0
  362. package/vendor/ink/build/input-parser.js +194 -0
  363. package/vendor/ink/build/input-parser.js.map +1 -0
  364. package/vendor/ink/build/instances.d.ts +3 -0
  365. package/vendor/ink/build/instances.js +8 -0
  366. package/vendor/ink/build/instances.js.map +1 -0
  367. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  368. package/vendor/ink/build/kitty-keyboard.js +32 -0
  369. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  370. package/vendor/ink/build/log-update.d.ts +20 -0
  371. package/vendor/ink/build/log-update.js +261 -0
  372. package/vendor/ink/build/log-update.js.map +1 -0
  373. package/vendor/ink/build/measure-element.d.ts +20 -0
  374. package/vendor/ink/build/measure-element.js +13 -0
  375. package/vendor/ink/build/measure-element.js.map +1 -0
  376. package/vendor/ink/build/measure-text.d.ts +6 -0
  377. package/vendor/ink/build/measure-text.js +21 -0
  378. package/vendor/ink/build/measure-text.js.map +1 -0
  379. package/vendor/ink/build/output.d.ts +35 -0
  380. package/vendor/ink/build/output.js +328 -0
  381. package/vendor/ink/build/output.js.map +1 -0
  382. package/vendor/ink/build/parse-keypress.d.ts +20 -0
  383. package/vendor/ink/build/parse-keypress.js +495 -0
  384. package/vendor/ink/build/parse-keypress.js.map +1 -0
  385. package/vendor/ink/build/reconciler.d.ts +4 -0
  386. package/vendor/ink/build/reconciler.js +306 -0
  387. package/vendor/ink/build/reconciler.js.map +1 -0
  388. package/vendor/ink/build/render-background.d.ts +4 -0
  389. package/vendor/ink/build/render-background.js +25 -0
  390. package/vendor/ink/build/render-background.js.map +1 -0
  391. package/vendor/ink/build/render-border.d.ts +4 -0
  392. package/vendor/ink/build/render-border.js +84 -0
  393. package/vendor/ink/build/render-border.js.map +1 -0
  394. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  395. package/vendor/ink/build/render-node-to-output.js +162 -0
  396. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  397. package/vendor/ink/build/render-to-string.d.ts +38 -0
  398. package/vendor/ink/build/render-to-string.js +116 -0
  399. package/vendor/ink/build/render-to-string.js.map +1 -0
  400. package/vendor/ink/build/render.d.ts +176 -0
  401. package/vendor/ink/build/render.js +71 -0
  402. package/vendor/ink/build/render.js.map +1 -0
  403. package/vendor/ink/build/renderer.d.ts +8 -0
  404. package/vendor/ink/build/renderer.js +64 -0
  405. package/vendor/ink/build/renderer.js.map +1 -0
  406. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  407. package/vendor/ink/build/sanitize-ansi.js +27 -0
  408. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  409. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  410. package/vendor/ink/build/squash-text-nodes.js +36 -0
  411. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  412. package/vendor/ink/build/styles.d.ts +302 -0
  413. package/vendor/ink/build/styles.js +303 -0
  414. package/vendor/ink/build/styles.js.map +1 -0
  415. package/vendor/ink/build/utils.d.ts +9 -0
  416. package/vendor/ink/build/utils.js +19 -0
  417. package/vendor/ink/build/utils.js.map +1 -0
  418. package/vendor/ink/build/wrap-text.d.ts +3 -0
  419. package/vendor/ink/build/wrap-text.js +38 -0
  420. package/vendor/ink/build/wrap-text.js.map +1 -0
  421. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  422. package/vendor/ink/build/write-synchronized.js +9 -0
  423. package/vendor/ink/build/write-synchronized.js.map +1 -0
  424. package/vendor/ink/license +10 -0
  425. package/vendor/ink/package.json +137 -0
  426. package/.claude-plugin/marketplace.json +0 -34
  427. package/.claude-plugin/plugin.json +0 -20
  428. package/.gitattributes +0 -34
  429. package/.mcp.json +0 -14
  430. package/ARCHITECTURE.md +0 -77
  431. package/CHANGELOG.md +0 -30
  432. package/CONTRIBUTING.md +0 -45
  433. package/DATA-FLOW.md +0 -79
  434. package/LICENSE +0 -21
  435. package/SECURITY.md +0 -138
  436. package/UNINSTALL.md +0 -115
  437. package/agents/maintenance.md +0 -5
  438. package/agents/memory-classification.md +0 -30
  439. package/agents/scheduler-task.md +0 -18
  440. package/agents/webhook-handler.md +0 -27
  441. package/agents/worker.md +0 -24
  442. package/bin/bridge +0 -133
  443. package/bin/statusline-launcher.mjs +0 -82
  444. package/bin/statusline-lib.mjs +0 -581
  445. package/bin/statusline-route.mjs +0 -273
  446. package/bin/statusline.mjs +0 -638
  447. package/bun.lock +0 -927
  448. package/commands/config.md +0 -16
  449. package/commands/doctor.md +0 -13
  450. package/commands/model.md +0 -61
  451. package/commands/setup.md +0 -17
  452. package/defaults/hidden-roles.json +0 -68
  453. package/defaults/memory-chunk-prompt.md +0 -63
  454. package/defaults/mixdog-config.template.json +0 -27
  455. package/defaults/user-workflow.json +0 -8
  456. package/defaults/user-workflow.md +0 -17
  457. package/hooks/hooks.json +0 -73
  458. package/hooks/lib/active-instance.cjs +0 -77
  459. package/hooks/lib/permission-evaluator.cjs +0 -411
  460. package/hooks/lib/permission-route.cjs +0 -63
  461. package/hooks/lib/settings-loader.cjs +0 -117
  462. package/hooks/post-tool-use.cjs +0 -84
  463. package/hooks/pre-mcp-sandbox.cjs +0 -158
  464. package/hooks/pre-tool-subagent.cjs +0 -258
  465. package/hooks/session-start.cjs +0 -1493
  466. package/hooks/shim-launcher.cjs +0 -65
  467. package/hooks/turn-timer.cjs +0 -82
  468. package/lib/claude-md-writer.cjs +0 -386
  469. package/lib/keychain-cjs.cjs +0 -290
  470. package/lib/plugin-paths.cjs +0 -69
  471. package/lib/rules-builder.cjs +0 -241
  472. package/native/README.md +0 -117
  473. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  474. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  475. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  476. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  477. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  478. package/prompts/code-review.txt +0 -16
  479. package/prompts/security-audit.txt +0 -17
  480. package/rules/bridge/00-common.md +0 -39
  481. package/rules/bridge/20-skip-protocol.md +0 -18
  482. package/rules/bridge/30-explorer.md +0 -33
  483. package/rules/bridge/40-cycle1-agent.md +0 -52
  484. package/rules/bridge/41-cycle2-agent.md +0 -62
  485. package/rules/lead/00-tool-lead.md +0 -61
  486. package/rules/lead/01-general.md +0 -26
  487. package/rules/lead/02-channels.md +0 -49
  488. package/rules/lead/03-team.md +0 -27
  489. package/rules/lead/04-workflow.md +0 -20
  490. package/rules/shared/00-language.md +0 -14
  491. package/rules/shared/01-tool.md +0 -138
  492. package/scripts/bootstrap.mjs +0 -130
  493. package/scripts/bridge-unify-smoke.mjs +0 -308
  494. package/scripts/build-runtime-linux.sh +0 -348
  495. package/scripts/build-runtime-macos.sh +0 -217
  496. package/scripts/build-runtime-windows.ps1 +0 -242
  497. package/scripts/builtin-utils-smoke.mjs +0 -398
  498. package/scripts/bump.mjs +0 -80
  499. package/scripts/check-json.mjs +0 -45
  500. package/scripts/check-syntax-changed.mjs +0 -102
  501. package/scripts/check-syntax.mjs +0 -58
  502. package/scripts/code-graph-batch.test.mjs +0 -33
  503. package/scripts/config-preserve-smoke.mjs +0 -180
  504. package/scripts/doctor.mjs +0 -489
  505. package/scripts/edit-normalize-fuzz.mjs +0 -130
  506. package/scripts/edit-normalize-smoke.mjs +0 -401
  507. package/scripts/edit-operation-smoke.mjs +0 -369
  508. package/scripts/edit2-smoke.mjs +0 -63
  509. package/scripts/ensure-deps.mjs +0 -259
  510. package/scripts/fuzzy-e2e.mjs +0 -28
  511. package/scripts/fuzzy-smoke.mjs +0 -26
  512. package/scripts/gateway-model.mjs +0 -596
  513. package/scripts/generate-runtime-manifest.mjs +0 -166
  514. package/scripts/guard-smoke.mjs +0 -66
  515. package/scripts/hidden-role-schema-smoke.mjs +0 -162
  516. package/scripts/hook-routing-smoke.mjs +0 -29
  517. package/scripts/inject-input.ps1 +0 -204
  518. package/scripts/io-complex-smoke.mjs +0 -667
  519. package/scripts/io-explore-bench.mjs +0 -424
  520. package/scripts/io-guardrails-smoke.mjs +0 -205
  521. package/scripts/io-mini-bench-baseline.json +0 -11
  522. package/scripts/io-mini-bench.mjs +0 -216
  523. package/scripts/io-route-harness.mjs +0 -933
  524. package/scripts/io-telemetry-report.mjs +0 -691
  525. package/scripts/lib/gateway-inventory.mjs +0 -178
  526. package/scripts/lib/gateway-settings.mjs +0 -78
  527. package/scripts/mutation-bench.mjs +0 -564
  528. package/scripts/mutation-io-smoke.mjs +0 -1097
  529. package/scripts/native-patch-bridge-smoke.mjs +0 -288
  530. package/scripts/native-patch-smoke.mjs +0 -304
  531. package/scripts/openai-oauth-catalog-smoke.mjs +0 -53
  532. package/scripts/patch-interior-context-smoke.mjs +0 -49
  533. package/scripts/patch-newline-utf8-smoke.mjs +0 -157
  534. package/scripts/perf-hook-smoke.mjs +0 -71
  535. package/scripts/permission-eval-smoke.mjs +0 -443
  536. package/scripts/prep-patch.mjs +0 -53
  537. package/scripts/prep-shim.mjs +0 -96
  538. package/scripts/provider-cache-smoke.mjs +0 -687
  539. package/scripts/report-runtime-health.mjs +0 -132
  540. package/scripts/resolve-bun.mjs +0 -60
  541. package/scripts/run-mcp.mjs +0 -1473
  542. package/scripts/salvage-v4a-shatter.test.mjs +0 -58
  543. package/scripts/scoped-cache-io-smoke.mjs +0 -103
  544. package/scripts/shell-policy-round3-smoke.mjs +0 -46
  545. package/scripts/smoke-runtime-negative.ps1 +0 -100
  546. package/scripts/smoke-runtime-negative.sh +0 -95
  547. package/scripts/stall-policy-smoke.mjs +0 -50
  548. package/scripts/start-memory-worker.mjs +0 -23
  549. package/scripts/statusline-launcher-smoke.mjs +0 -235
  550. package/scripts/stress-atomic-write.mjs +0 -1028
  551. package/scripts/test-fault-inject.mjs +0 -164
  552. package/scripts/test-large-file.mjs +0 -174
  553. package/scripts/tool-edge-smoke.mjs +0 -209
  554. package/scripts/uninstall.mjs +0 -238
  555. package/scripts/webhook-selfheal-smoke.mjs +0 -27
  556. package/scripts/write-overwrite-guard-smoke.mjs +0 -56
  557. package/server-main.mjs +0 -3350
  558. package/server.mjs +0 -468
  559. package/setup/config-merge.mjs +0 -246
  560. package/setup/install.mjs +0 -574
  561. package/setup/launch-core.mjs +0 -617
  562. package/setup/launch.mjs +0 -101
  563. package/setup/locate-claude.mjs +0 -56
  564. package/setup/mixdog-cli.mjs +0 -122
  565. package/setup/setup-server.mjs +0 -3305
  566. package/setup/setup.html +0 -3740
  567. package/setup/tui.mjs +0 -325
  568. package/skills/retro-skill-proposer/SKILL.md +0 -92
  569. package/skills/schedule-add/SKILL.md +0 -77
  570. package/skills/setup/SKILL.md +0 -356
  571. package/skills/webhook-add/SKILL.md +0 -81
  572. package/src/agent/bridge-stall-watchdog.mjs +0 -337
  573. package/src/agent/index.mjs +0 -2229
  574. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +0 -1010
  575. package/src/agent/orchestrator/bridge-retry.mjs +0 -220
  576. package/src/agent/orchestrator/bridge-trace.mjs +0 -601
  577. package/src/agent/orchestrator/cache-mtime.mjs +0 -58
  578. package/src/agent/orchestrator/config.mjs +0 -405
  579. package/src/agent/orchestrator/context/collect.mjs +0 -651
  580. package/src/agent/orchestrator/dispatch-persist.mjs +0 -549
  581. package/src/agent/orchestrator/drain-registry.mjs +0 -50
  582. package/src/agent/orchestrator/explore-validator.mjs +0 -8
  583. package/src/agent/orchestrator/internal-roles.mjs +0 -118
  584. package/src/agent/orchestrator/internal-tools.mjs +0 -88
  585. package/src/agent/orchestrator/jobs.mjs +0 -116
  586. package/src/agent/orchestrator/mcp/client.mjs +0 -364
  587. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +0 -1884
  588. package/src/agent/orchestrator/providers/anthropic.mjs +0 -598
  589. package/src/agent/orchestrator/providers/gemini.mjs +0 -1530
  590. package/src/agent/orchestrator/providers/grok-oauth.mjs +0 -779
  591. package/src/agent/orchestrator/providers/model-catalog.mjs +0 -374
  592. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +0 -366
  593. package/src/agent/orchestrator/providers/openai-compat.mjs +0 -1511
  594. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -1891
  595. package/src/agent/orchestrator/providers/openai-oauth.mjs +0 -1456
  596. package/src/agent/orchestrator/providers/openai-ws.mjs +0 -127
  597. package/src/agent/orchestrator/providers/registry.mjs +0 -192
  598. package/src/agent/orchestrator/providers/retry-classifier.mjs +0 -325
  599. package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +0 -42
  600. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +0 -142
  601. package/src/agent/orchestrator/session/cache/read-cache.mjs +0 -319
  602. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +0 -361
  603. package/src/agent/orchestrator/session/loop.mjs +0 -1619
  604. package/src/agent/orchestrator/session/manager.mjs +0 -1991
  605. package/src/agent/orchestrator/session/result-classification.mjs +0 -65
  606. package/src/agent/orchestrator/session/store.mjs +0 -632
  607. package/src/agent/orchestrator/session/stream-watchdog.mjs +0 -130
  608. package/src/agent/orchestrator/session/tool-result-offload.mjs +0 -166
  609. package/src/agent/orchestrator/session/trim.mjs +0 -491
  610. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +0 -115
  611. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +0 -331
  612. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +0 -150
  613. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +0 -228
  614. package/src/agent/orchestrator/smart-bridge/index.mjs +0 -215
  615. package/src/agent/orchestrator/smart-bridge/profiles.mjs +0 -37
  616. package/src/agent/orchestrator/smart-bridge/registry.mjs +0 -348
  617. package/src/agent/orchestrator/stall-policy.mjs +0 -201
  618. package/src/agent/orchestrator/tool-loop-guard.mjs +0 -75
  619. package/src/agent/orchestrator/tools/bash-session.mjs +0 -722
  620. package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +0 -171
  621. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -511
  622. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -480
  623. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -256
  624. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +0 -58
  625. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +0 -240
  626. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +0 -113
  627. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +0 -74
  628. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +0 -242
  629. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +0 -211
  630. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +0 -1364
  631. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +0 -126
  632. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +0 -141
  633. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +0 -194
  634. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +0 -60
  635. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +0 -168
  636. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +0 -173
  637. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +0 -48
  638. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -99
  639. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +0 -193
  640. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +0 -597
  641. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  642. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +0 -300
  643. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +0 -152
  644. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +0 -118
  645. package/src/agent/orchestrator/tools/builtin/read-open.mjs +0 -190
  646. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +0 -728
  647. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +0 -173
  648. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +0 -602
  649. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +0 -196
  650. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +0 -422
  651. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +0 -158
  652. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +0 -869
  653. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +0 -962
  654. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +0 -223
  655. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +0 -206
  656. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +0 -401
  657. package/src/agent/orchestrator/tools/builtin.mjs +0 -503
  658. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +0 -24
  659. package/src/agent/orchestrator/tools/code-graph.mjs +0 -4095
  660. package/src/agent/orchestrator/tools/cwd-tool.mjs +0 -298
  661. package/src/agent/orchestrator/tools/destructive-warning.mjs +0 -323
  662. package/src/agent/orchestrator/tools/edit-normalize.mjs +0 -603
  663. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +0 -154
  664. package/src/agent/orchestrator/tools/graph-manifest.json +0 -26
  665. package/src/agent/orchestrator/tools/host-input.mjs +0 -204
  666. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +0 -143
  667. package/src/agent/orchestrator/tools/patch-manifest.json +0 -26
  668. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +0 -20
  669. package/src/agent/orchestrator/tools/patch.mjs +0 -2754
  670. package/src/agent/orchestrator/tools/progress-message.mjs +0 -118
  671. package/src/agent/orchestrator/tools/shell-command.mjs +0 -865
  672. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +0 -7
  673. package/src/agent/orchestrator/tools/shell-snapshot.mjs +0 -313
  674. package/src/agent/orchestrator/workflow-store.mjs +0 -93
  675. package/src/agent/tool-defs.mjs +0 -110
  676. package/src/channels/backends/discord.mjs +0 -784
  677. package/src/channels/data/voice-runtime-manifest.json +0 -138
  678. package/src/channels/index.mjs +0 -3268
  679. package/src/channels/lib/config.mjs +0 -292
  680. package/src/channels/lib/drop-trace.mjs +0 -71
  681. package/src/channels/lib/event-pipeline.mjs +0 -81
  682. package/src/channels/lib/holidays.mjs +0 -138
  683. package/src/channels/lib/hook-pipe-server.mjs +0 -822
  684. package/src/channels/lib/output-forwarder.mjs +0 -765
  685. package/src/channels/lib/runtime-paths.mjs +0 -552
  686. package/src/channels/lib/scheduler.mjs +0 -723
  687. package/src/channels/lib/session-discovery.mjs +0 -103
  688. package/src/channels/lib/state-file.mjs +0 -68
  689. package/src/channels/lib/status-snapshot.mjs +0 -219
  690. package/src/channels/lib/tool-format.mjs +0 -140
  691. package/src/channels/lib/transcript-discovery.mjs +0 -195
  692. package/src/channels/lib/voice-runtime-fetcher.mjs +0 -734
  693. package/src/channels/lib/webhook.mjs +0 -1318
  694. package/src/channels/tool-defs.mjs +0 -170
  695. package/src/daemon/host.mjs +0 -118
  696. package/src/daemon/mcp-transport.mjs +0 -47
  697. package/src/daemon/session.mjs +0 -100
  698. package/src/daemon/thin-client.mjs +0 -71
  699. package/src/daemon/transport.mjs +0 -163
  700. package/src/gateway/claude-current.mjs +0 -255
  701. package/src/gateway/oauth-usage.mjs +0 -598
  702. package/src/gateway/route-meta.mjs +0 -629
  703. package/src/gateway/server.mjs +0 -713
  704. package/src/memory/data/runtime-manifest.json +0 -40
  705. package/src/memory/index.mjs +0 -3332
  706. package/src/memory/lib/core-memory-store.mjs +0 -330
  707. package/src/memory/lib/embedding-provider.mjs +0 -269
  708. package/src/memory/lib/embedding-worker.mjs +0 -323
  709. package/src/memory/lib/memory-cycle1.mjs +0 -645
  710. package/src/memory/lib/memory-cycle2.mjs +0 -1284
  711. package/src/memory/lib/memory-cycle3.mjs +0 -540
  712. package/src/memory/lib/memory-embed.mjs +0 -299
  713. package/src/memory/lib/memory-ops-policy.mjs +0 -190
  714. package/src/memory/lib/memory-recall-store.mjs +0 -638
  715. package/src/memory/lib/memory.mjs +0 -412
  716. package/src/memory/lib/pg/adapter.mjs +0 -308
  717. package/src/memory/lib/pg/process.mjs +0 -360
  718. package/src/memory/lib/pg/supervisor.mjs +0 -396
  719. package/src/memory/lib/runtime-fetcher.mjs +0 -458
  720. package/src/memory/lib/trace-store.mjs +0 -728
  721. package/src/memory/tool-defs.mjs +0 -79
  722. package/src/search/index.mjs +0 -1173
  723. package/src/search/lib/backends/anthropic-oauth.mjs +0 -98
  724. package/src/search/lib/backends/exa.mjs +0 -50
  725. package/src/search/lib/backends/firecrawl.mjs +0 -61
  726. package/src/search/lib/backends/gemini-api.mjs +0 -83
  727. package/src/search/lib/backends/grok-oauth.mjs +0 -86
  728. package/src/search/lib/backends/index.mjs +0 -150
  729. package/src/search/lib/backends/openai-api.mjs +0 -144
  730. package/src/search/lib/backends/openai-oauth.mjs +0 -102
  731. package/src/search/lib/backends/openai-web-search.mjs +0 -76
  732. package/src/search/lib/backends/tavily.mjs +0 -55
  733. package/src/search/lib/backends/xai-api.mjs +0 -113
  734. package/src/search/lib/config.mjs +0 -192
  735. package/src/search/lib/provider-usage.mjs +0 -67
  736. package/src/search/lib/providers.mjs +0 -47
  737. package/src/search/lib/search-intent.mjs +0 -109
  738. package/src/search/lib/setup-handler.mjs +0 -261
  739. package/src/search/lib/web-tools.mjs +0 -1219
  740. package/src/search/tool-defs.mjs +0 -83
  741. package/src/setup/defender-exclusion.mjs +0 -183
  742. package/src/shared/atomic-file.mjs +0 -436
  743. package/src/shared/config.mjs +0 -372
  744. package/src/shared/daemon-recycle.mjs +0 -108
  745. package/src/shared/disable-claude-builtins.mjs +0 -91
  746. package/src/shared/err-text.mjs +0 -12
  747. package/src/shared/llm/http-agent.mjs +0 -123
  748. package/src/shared/open-url.mjs +0 -62
  749. package/src/shared/plugin-paths.mjs +0 -58
  750. package/src/shared/schedules-store.mjs +0 -70
  751. package/src/shared/seed.mjs +0 -161
  752. package/src/shared/user-cwd.mjs +0 -225
  753. package/src/shared/user-data-guard.mjs +0 -244
  754. package/src/status/aggregator.mjs +0 -584
  755. package/src/status/server.mjs +0 -413
  756. package/tools.json +0 -1671
  757. /package/{defaults → src/defaults}/cycle3-review-prompt.md +0 -0
  758. /package/{defaults → src/defaults}/memory-promote-prompt.md +0 -0
  759. /package/{hooks → src/hooks}/lib/permission-rules.cjs +0 -0
  760. /package/{lib → src/lib}/config-cjs.cjs +0 -0
  761. /package/{lib → src/lib}/hook-pipe-path.cjs +0 -0
  762. /package/{lib → src/lib}/mixdog-debug.cjs +0 -0
  763. /package/{lib → src/lib}/text-utils.cjs +0 -0
  764. /package/{rules → src/rules}/bridge/42-cycle3-agent.md +0 -0
  765. /package/src/{agent → runtime/agent}/orchestrator/activity-bus.mjs +0 -0
  766. /package/src/{agent → runtime/agent}/orchestrator/providers/anthropic-betas.mjs +0 -0
  767. /package/src/{agent → runtime/agent}/orchestrator/session/abort-lookup.mjs +0 -0
  768. /package/src/{agent → runtime/agent}/orchestrator/session/cache/scoped-cache-outcome.mjs +0 -0
  769. /package/src/{agent → runtime/agent}/orchestrator/session/cache/util.mjs +0 -0
  770. /package/src/{agent → runtime/agent}/orchestrator/session/read-dedup.mjs +0 -0
  771. /package/src/{agent → runtime/agent}/orchestrator/session/save-session-worker.mjs +0 -0
  772. /package/src/{agent → runtime/agent}/orchestrator/smart-bridge/session-builder.mjs +0 -0
  773. /package/src/{agent → runtime/agent}/orchestrator/tools/bash-policy-scan.mjs +0 -0
  774. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/atomic-write.mjs +0 -0
  775. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/binary-file.mjs +0 -0
  776. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cache-layers.mjs +0 -0
  777. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cwd-utils.mjs +0 -0
  778. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/device-paths.mjs +0 -0
  779. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -0
  780. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diff-utils.mjs +0 -0
  781. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/fs-reachability.mjs +0 -0
  782. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/grep-formatting.mjs +0 -0
  783. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/hash-utils.mjs +0 -0
  784. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/list-formatting.mjs +0 -0
  785. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/open-config-tool.mjs +0 -0
  786. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-locks.mjs +0 -0
  787. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-utils.mjs +0 -0
  788. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-args.mjs +0 -0
  789. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-batch.mjs +0 -0
  790. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-constants.mjs +0 -0
  791. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image-resize.mjs +0 -0
  792. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image.mjs +0 -0
  793. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-lines.mjs +0 -0
  794. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-mode-tool.mjs +0 -0
  795. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-range-index.mjs +0 -0
  796. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-ranges.mjs +0 -0
  797. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-special-files.mjs +0 -0
  798. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-tool.mjs +0 -0
  799. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-windows.mjs +0 -0
  800. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-analysis.mjs +0 -0
  801. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-output.mjs +0 -0
  802. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-helpers.mjs +0 -0
  803. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-validation.mjs +0 -0
  804. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/text-stats.mjs +0 -0
  805. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/windows-roots.mjs +0 -0
  806. /package/src/{agent → runtime/agent}/orchestrator/tools/code-graph-prewarm-worker.mjs +0 -0
  807. /package/src/{agent → runtime/agent}/orchestrator/tools/env-scrub.mjs +0 -0
  808. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-content-cache.mjs +0 -0
  809. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-planner.mjs +0 -0
  810. /package/src/{agent → runtime/agent}/orchestrator/tools/next-call-utils.mjs +0 -0
  811. /package/src/{agent → runtime/agent}/orchestrator/tools/result-compression.mjs +0 -0
  812. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-exec-policy.mjs +0 -0
  813. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy-danger-target.mjs +0 -0
  814. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy.mjs +0 -0
  815. /package/src/{channels → runtime/channels}/lib/cli-worker-host.mjs +0 -0
  816. /package/src/{channels → runtime/channels}/lib/config-lock.mjs +0 -0
  817. /package/src/{channels → runtime/channels}/lib/event-queue.mjs +0 -0
  818. /package/src/{channels → runtime/channels}/lib/executor.mjs +0 -0
  819. /package/src/{channels → runtime/channels}/lib/format.mjs +0 -0
  820. /package/src/{channels → runtime/channels}/lib/interaction-workflows.mjs +0 -0
  821. /package/src/{channels → runtime/channels}/lib/memory-client.mjs +0 -0
  822. /package/src/{channels → runtime/channels}/lib/session-control.mjs +0 -0
  823. /package/src/{channels → runtime/channels}/lib/settings.mjs +0 -0
  824. /package/src/{channels → runtime/channels}/lib/whisper-server.mjs +0 -0
  825. /package/src/{memory → runtime/memory}/lib/agent-ipc.mjs +0 -0
  826. /package/src/{memory → runtime/memory}/lib/bridge-trace-queries.mjs +0 -0
  827. /package/src/{memory → runtime/memory}/lib/llm-worker-host.mjs +0 -0
  828. /package/src/{memory → runtime/memory}/lib/memory-cycle.mjs +0 -0
  829. /package/src/{memory → runtime/memory}/lib/memory-extraction.mjs +0 -0
  830. /package/src/{memory → runtime/memory}/lib/memory-maintenance-store.mjs +0 -0
  831. /package/src/{memory → runtime/memory}/lib/memory-recall-id-patch.mjs +0 -0
  832. /package/src/{memory → runtime/memory}/lib/memory-recall-read-query.mjs +0 -0
  833. /package/src/{memory → runtime/memory}/lib/memory-recall-scope-filter.mjs +0 -0
  834. /package/src/{memory → runtime/memory}/lib/memory-retrievers.mjs +0 -0
  835. /package/src/{memory → runtime/memory}/lib/memory-score.mjs +0 -0
  836. /package/src/{memory → runtime/memory}/lib/memory-text-utils.mjs +0 -0
  837. /package/src/{memory → runtime/memory}/lib/model-profile.mjs +0 -0
  838. /package/src/{memory → runtime/memory}/lib/project-id-resolver.mjs +0 -0
  839. /package/src/{search → runtime/search}/lib/cache.mjs +0 -0
  840. /package/src/{search → runtime/search}/lib/formatter.mjs +0 -0
  841. /package/src/{search → runtime/search}/lib/state.mjs +0 -0
  842. /package/src/{shared → runtime/shared}/abort-controller.mjs +0 -0
  843. /package/src/{shared → runtime/shared}/llm/cost.mjs +0 -0
  844. /package/src/{shared → runtime/shared}/llm/index.mjs +0 -0
  845. /package/src/{shared → runtime/shared}/llm/pid-cleanup.mjs +0 -0
  846. /package/src/{shared → runtime/shared}/llm/usage-log.mjs +0 -0
  847. /package/src/{shared → runtime/shared}/wsl.mjs +0 -0
@@ -1,1493 +0,0 @@
1
- 'use strict';
2
-
3
- const fs = require('fs');
4
- const path = require('path');
5
- const os = require('os');
6
- const http = require('http');
7
- const net = require('net');
8
- const { spawn } = require('child_process');
9
- const { resolvePluginData } = require(path.join(__dirname, '..', 'lib', 'plugin-paths.cjs'));
10
- const { readSection } = require(path.join(__dirname, '..', 'lib', 'config-cjs.cjs'));
11
- const {
12
- isMixdogDebugEnabled,
13
- pruneStalePluginDataLogSiblings,
14
- appendSessionStartCriticalLog,
15
- sessionStartCriticalFallback,
16
- DEFAULT_STALE_LOG_SIBLING_MAX,
17
- } = require(path.join(__dirname, '..', 'lib', 'mixdog-debug.cjs'));
18
-
19
- // Verbose tracing → session-start.log (MIXDOG_DEBUG). Ship mode → critical
20
- // fail-open lines only in bounded session-start-critical.log.
21
- let _SESSION_START_LOG_PATH = null;
22
- let _SESSION_START_DATA_DIR = null;
23
- const MIXDOG_DEBUG_ENABLED = isMixdogDebugEnabled();
24
- let _sessionStartLogsPruned = false;
25
-
26
- function sessionStartDataDir() {
27
- if (_SESSION_START_DATA_DIR) return _SESSION_START_DATA_DIR;
28
- try {
29
- if (typeof DATA_DIR === 'string' && DATA_DIR) {
30
- _SESSION_START_DATA_DIR = DATA_DIR;
31
- return _SESSION_START_DATA_DIR;
32
- }
33
- } catch { /* safe before DATA_DIR const init */ }
34
- _SESSION_START_DATA_DIR = process.env.CLAUDE_PLUGIN_DATA
35
- || path.join(os.homedir(), '.claude', 'plugins', 'data', 'mixdog-trib-plugin');
36
- return _SESSION_START_DATA_DIR;
37
- }
38
-
39
- function sessionStartLogPath() {
40
- if (_SESSION_START_LOG_PATH) return _SESSION_START_LOG_PATH;
41
- _SESSION_START_LOG_PATH = path.join(sessionStartDataDir(), 'session-start.log');
42
- return _SESSION_START_LOG_PATH;
43
- }
44
- const SESSION_START_LOG_MAX_BYTES = 256 * 1024;
45
- const SESSION_START_LOG_KEEP_BYTES = 64 * 1024;
46
-
47
- function appendVerboseSessionStartLog(line) {
48
- try {
49
- const dir = sessionStartDataDir();
50
- const p = sessionStartLogPath();
51
- fs.mkdirSync(dir, { recursive: true });
52
- if (!_sessionStartLogsPruned) {
53
- _sessionStartLogsPruned = true;
54
- pruneStalePluginDataLogSiblings(dir, DEFAULT_STALE_LOG_SIBLING_MAX);
55
- }
56
- try {
57
- const st = fs.statSync(p);
58
- if (st.size > SESSION_START_LOG_MAX_BYTES) {
59
- const buf = fs.readFileSync(p);
60
- fs.writeFileSync(p, buf.subarray(buf.length - SESSION_START_LOG_KEEP_BYTES));
61
- }
62
- } catch {}
63
- fs.appendFileSync(p, line);
64
- } catch {}
65
- }
66
-
67
- function teeStderr(line, opts = {}) {
68
- const critical = opts.critical === true
69
- || (opts.critical !== false && sessionStartCriticalFallback(line));
70
- if (!MIXDOG_DEBUG_ENABLED) {
71
- if (!critical) return;
72
- appendSessionStartCriticalLog(sessionStartDataDir(), line);
73
- try { process.stderr.write(line); } catch {}
74
- return;
75
- }
76
- appendVerboseSessionStartLog(line);
77
- try { process.stderr.write(line); } catch {}
78
- }
79
-
80
- // ---------------------------------------------------------------------------
81
- // argv parsing — supports `--part rules`, `--part=rules`.
82
- // Invalid/unknown part falls back to `rules`.
83
- // ---------------------------------------------------------------------------
84
- function parseArgs(argv) {
85
- const out = { part: 'rules' };
86
- for (let i = 2; i < argv.length; i++) {
87
- const a = argv[i];
88
- if (!a) continue;
89
- let key = null;
90
- let val = null;
91
- if (a.startsWith('--') && a.includes('=')) {
92
- const eq = a.indexOf('=');
93
- key = a.slice(2, eq);
94
- val = a.slice(eq + 1);
95
- } else if (a.startsWith('--')) {
96
- key = a.slice(2);
97
- const next = argv[i + 1];
98
- if (typeof next === 'string' && !next.startsWith('--')) {
99
- val = next;
100
- i++;
101
- }
102
- }
103
- if (key === 'part' && typeof val === 'string') out.part = val;
104
- }
105
- if (!['rules', 'core', 'recap'].includes(out.part)) out.part = 'rules';
106
- return out;
107
- }
108
-
109
- const ARGS = parseArgs(process.argv);
110
- let PART = ARGS.part;
111
-
112
- const DATA_DIR = resolvePluginData();
113
- const PLUGIN_ROOT = process.env.CLAUDE_PLUGIN_ROOT;
114
-
115
- let _event = {};
116
- const IS_DAEMON_REQUIRE = !!process.env.MIXDOG_SKIP_TOP_STDIN;
117
- // In-daemon `require()` would otherwise read fd 0 (the daemon's MCP stdio
118
- // pipe), corrupting it. Skip the top-level stdin read when this env-var is
119
- // set by hook-pipe-server.mjs around the require boundary.
120
- if (!IS_DAEMON_REQUIRE) {
121
- try {
122
- const _input = fs.readFileSync(0, 'utf8');
123
- if (_input) _event = JSON.parse(_input);
124
- } catch {}
125
- }
126
-
127
- if (_event.isSidechain) {
128
- teeStderr(`[session-start] skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=isSidechain\n`);
129
- process.exit(0);
130
- }
131
- if (_event.agentId) {
132
- teeStderr(`[session-start] skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=agentId=${_event.agentId}\n`);
133
- process.exit(0);
134
- }
135
- if (_event.is_sidechain) {
136
- teeStderr(`[session-start] skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=is_sidechain\n`);
137
- process.exit(0);
138
- }
139
- if (_event.agent_id) {
140
- teeStderr(`[session-start] skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=agent_id=${_event.agent_id}\n`);
141
- process.exit(0);
142
- }
143
- if (_event.kind && _event.kind !== 'interactive') {
144
- teeStderr(`[session-start] skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=kind=${_event.kind}\n`);
145
- process.exit(0);
146
- }
147
-
148
- const SESSION_START_CYCLE1_TIMEOUT_MS = Number.parseInt(process.env.MIXDOG_SESSION_START_CYCLE1_TIMEOUT_MS || '110000', 10);
149
- const MIXDOG_RUNTIME_ROOT = process.env.MIXDOG_RUNTIME_ROOT
150
- ? path.resolve(process.env.MIXDOG_RUNTIME_ROOT)
151
- : path.join(os.tmpdir(), 'mixdog');
152
- const ACTIVE_INSTANCE_FILE = path.join(MIXDOG_RUNTIME_ROOT, 'active-instance.json');
153
- if (!DATA_DIR || !PLUGIN_ROOT) {
154
- teeStderr(`[session-start] skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=missing-dirs DATA_DIR=${!!DATA_DIR} PLUGIN_ROOT=${!!PLUGIN_ROOT}\n`);
155
- process.exit(0);
156
- }
157
-
158
- if (!IS_DAEMON_REQUIRE) {
159
- teeStderr(`[session-start] enter PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} sessionId=${_event.session_id || _event.sessionId || ''}\n`);
160
- }
161
-
162
- // ---------------------------------------------------------------------------
163
- // Common helpers (used by all parts).
164
- // ---------------------------------------------------------------------------
165
- function readJson(filePath) {
166
- try { return JSON.parse(fs.readFileSync(filePath, 'utf8')); } catch { return {}; }
167
- }
168
-
169
- function parsePositiveNumber(value) {
170
- const n = Number(value);
171
- return Number.isFinite(n) && n > 0 ? n : null;
172
- }
173
-
174
- function readAdvertisedMemoryPort() {
175
- const active = JSON.parse(fs.readFileSync(ACTIVE_INSTANCE_FILE, 'utf8'));
176
- const port = parsePositiveNumber(active && active.memory_port);
177
- if (!port) return null;
178
- const activeServerPid = parsePositiveNumber(active && active.server_pid);
179
- const memoryServerPid = parsePositiveNumber(active && active.memory_server_pid);
180
- if (activeServerPid && memoryServerPid && activeServerPid !== memoryServerPid) {
181
- return { stale: true, port, activeServerPid, memoryServerPid };
182
- }
183
- return { stale: false, port, active };
184
- }
185
-
186
- function sleepMs(ms) {
187
- return new Promise((resolve) => setTimeout(resolve, Math.max(0, ms)));
188
- }
189
-
190
- function readOwnerSecretFor(ownerInstanceId) {
191
- if (!ownerInstanceId) return '';
192
- try {
193
- const file = path.join(MIXDOG_RUNTIME_ROOT, `owner-secret-${String(ownerInstanceId)}.json`);
194
- const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
195
- return parsed && typeof parsed.secret === 'string' ? parsed.secret : '';
196
- } catch {
197
- return '';
198
- }
199
- }
200
-
201
- function ownerAuthHeaders(active) {
202
- const ownerInstanceId = active && active.instanceId;
203
- const ownerSecret = readOwnerSecretFor(ownerInstanceId);
204
- if (!ownerSecret) return null;
205
- return { 'x-owner-token': ownerSecret, 'x-owner-instance': String(ownerInstanceId) };
206
- }
207
-
208
- let _emitSink = null;
209
- function setEmitSink(fn) { _emitSink = fn || null; }
210
- function emit(additionalContext) {
211
- if (!additionalContext) {
212
- teeStderr(`[session-start] emit skipped: falsy context (empty string or null)\n`);
213
- return;
214
- }
215
- const byteLen = Buffer.byteLength(additionalContext, 'utf8');
216
- teeStderr(`[session-start] emit PART=${PART} bytes=${byteLen}\n`);
217
- const out = JSON.stringify({
218
- hookSpecificOutput: {
219
- hookEventName: 'SessionStart',
220
- additionalContext,
221
- },
222
- });
223
- if (_emitSink) _emitSink(out);
224
- else process.stdout.write(out);
225
- }
226
- function setEvent(e) { _event = e || {}; }
227
- function setPart(part) {
228
- if (['rules', 'core', 'recap'].includes(part)) PART = part;
229
- }
230
-
231
- // Memory-service HTTP port discovery. Single source of truth:
232
- // `<tmpdir>/mixdog/active-instance.json` `memory_port` field, written by
233
- // supervisor (server-main.mjs) on memory worker `ready` IPC. Throws when
234
- // missing — caller surfaces the failure rather than silently falling back
235
- // to a stale or default port.
236
- function getMemoryServicePort() {
237
- const advertised = readAdvertisedMemoryPort();
238
- if (!advertised || advertised.stale) {
239
- throw new Error(advertised && advertised.stale
240
- ? 'active-instance.json stale memory_port owner'
241
- : 'active-instance.json missing memory_port');
242
- }
243
- return advertised.port;
244
- }
245
-
246
- async function getLiveMemoryServicePort(probeMs = 200) {
247
- try {
248
- const advertised = readAdvertisedMemoryPort();
249
- if (!advertised || advertised.stale) return null;
250
- const port = advertised.port;
251
- const alive = await probeTcpPort(port, Math.max(1, probeMs));
252
- teeStderr(`[session-start] memoryDirect probePort=${port} probeMs=${probeMs} alive=${alive}\n`);
253
- return alive ? port : null;
254
- } catch {
255
- return null;
256
- }
257
- }
258
-
259
- async function memoryServicePost(urlPath, body, timeoutMs = 5000) {
260
- const port = getMemoryServicePort();
261
- const res = await httpPostJson({
262
- hostname: '127.0.0.1',
263
- port,
264
- path: urlPath,
265
- timeoutMs,
266
- body: body || {},
267
- });
268
- if (res.statusCode !== 200) {
269
- throw new Error(`memory-service ${urlPath} non-200 status=${res.statusCode}`);
270
- }
271
- try { return JSON.parse(res.body); }
272
- catch (e) { throw new Error(`memory-service ${urlPath} invalid JSON: ${e.message}`); }
273
- }
274
-
275
- function formatTs(ts) {
276
- const n = Number(ts);
277
- if (Number.isFinite(n) && n > 1e12) {
278
- return new Date(n).toLocaleString('sv-SE').slice(0, 16);
279
- }
280
- return String(ts ?? '').slice(0, 16);
281
- }
282
-
283
- // MM-DD HH:MM in local time for compact recap rendering.
284
- function formatTsShort(ts) {
285
- const n = Number(ts);
286
- if (!Number.isFinite(n) || n <= 1e12) return String(ts ?? '').slice(0, 16);
287
- const full = new Date(n).toLocaleString('sv-SE');
288
- return full.slice(5, 16);
289
- }
290
-
291
- // Single source of truth: lib/text-utils.cjs (also imported by memory-extraction.mjs).
292
- const { cleanMemoryText: cleanText } = require(path.join(PLUGIN_ROOT, 'lib', 'text-utils.cjs'));
293
-
294
- function resolveCwdScope(cwd) {
295
- try {
296
- let dir = path.resolve(cwd || process.cwd());
297
- while (true) {
298
- const candidate = path.join(dir, '.mixdog', 'project.id');
299
- try {
300
- const val = fs.readFileSync(candidate, 'utf8').trim();
301
- if (val.toLowerCase() === 'common') return null;
302
- if (val) {
303
- // Validate slug before returning — reject path traversal attempts.
304
- if (val.includes('..') || val.includes('\\')) return null;
305
- return val;
306
- }
307
- } catch {}
308
- const parent = path.dirname(dir);
309
- if (parent === dir) break;
310
- dir = parent;
311
- }
312
- } catch {}
313
- return null;
314
- }
315
-
316
- async function buildContext(cwd) {
317
- try {
318
- const _t0 = Date.now();
319
- const result = await memoryServicePost('/session-start/core-memory', {
320
- cwd: cwd || process.cwd(),
321
- });
322
- const _elapsed = Date.now() - _t0;
323
- if (!result || result.ok !== true) return '';
324
- const dbLines = Array.isArray(result.dbLines) ? result.dbLines : [];
325
- const userLines = Array.isArray(result.userLines) ? result.userLines : [];
326
- teeStderr(`[session-start] buildContext POST /session-start/core-memory elapsed=${_elapsed}ms dbLines=${dbLines.length} userLines=${userLines.length}\n`);
327
- const seen = new Set();
328
- const lines = [];
329
- // userLines (user-curated) and dbLines accumulate under the same char cap.
330
- // userLines go first so they win the budget. Each line is already short
331
- // (core_summary <=120, manual core <=120 at write time), so the cap is a
332
- // safety net rather than the primary limiter.
333
- const HEADER_LEN = '## Core Memory\n'.length;
334
- // CAP = 5000 chars — documented host-preview envelope. This is a byte cap,
335
- // not token-aware (adding a token counter would require a tokeniser dependency).
336
- // Deferred: token-aware cap once a lightweight counter is available.
337
- const CAP = 5000;
338
- let total = HEADER_LEN;
339
- for (const line of userLines) {
340
- const key = line.toLowerCase().replace(/\s+/g, ' ').slice(0, 120);
341
- if (seen.has(key)) continue;
342
- const add = line.length + 1;
343
- if (total + add > CAP) break;
344
- seen.add(key);
345
- lines.push(line);
346
- total += add;
347
- }
348
- // dbLines: accumulate score-DESC rows until the char cap is reached.
349
- for (const line of dbLines) {
350
- const key = line.toLowerCase().replace(/\s+/g, ' ').slice(0, 120);
351
- if (seen.has(key)) continue;
352
- const add = line.length + 1;
353
- if (total + add > CAP) break;
354
- seen.add(key);
355
- lines.push(line);
356
- total += add;
357
- }
358
- if (lines.length === 0) return '';
359
- return `## Core Memory\n${lines.join('\n')}`;
360
- } catch (e) {
361
- teeStderr(`[session-start] buildContext catch endpoint=/session-start/core-memory err=${e.message}\n`);
362
- process.stderr.write(`[session-start] context build failed: ${e.message}\n`);
363
- return '';
364
- }
365
- }
366
-
367
- // Returns { lines } — chronological "[MM-DD HH:MM] <summary>" entries
368
- // (oldest → newest), trimmed from the front so the rendered block fits the
369
- // SessionStart hook output cap (10,000 chars total — leaves margin for the
370
- // JSON wrapper around additionalContext; header "## Recap\n" reserved).
371
- async function buildRecapData(cwd) {
372
- const out = { lines: [] };
373
- try {
374
- const _t0 = Date.now();
375
- const result = await memoryServicePost('/session-start/recap', {
376
- cwd: cwd || process.cwd(),
377
- });
378
- const _elapsed = Date.now() - _t0;
379
- if (!result || result.ok !== true) return out;
380
- const rows = Array.isArray(result.rows) ? result.rows : [];
381
- teeStderr(`[session-start] buildRecapData POST /session-start/recap elapsed=${_elapsed}ms rows=${rows.length}\n`);
382
- if (rows.length === 0) return out;
383
-
384
- const rendered = rows.map(r => {
385
- const tsStr = formatTsShort(r.ts);
386
- const summary = String(r.summary || '').trim().slice(0, 1000);
387
- return summary ? `[${tsStr}] ${summary}` : '';
388
- }).filter(Boolean);
389
- if (rendered.length === 0) return out;
390
-
391
- // Dedup by normalized summary — newest-first, so older repeats drop.
392
- const seen = new Set();
393
- const uniq = [];
394
- for (const line of rendered) {
395
- const key = line.replace(/^\[[^\]]+\]\s*/, '').toLowerCase().replace(/\s+/g, ' ').slice(0, 80);
396
- if (seen.has(key)) continue;
397
- seen.add(key);
398
- uniq.push(line);
399
- }
400
-
401
- // Newest → oldest; keep accumulating from the newest end until the
402
- // running total would exceed the cap, then reverse to chronological.
403
- const HEADER_LEN = '## Recap\n'.length;
404
- const CAP = 5000;
405
- let total = HEADER_LEN;
406
- const kept = [];
407
- for (const line of uniq) {
408
- const add = line.length + 1;
409
- if (total + add > CAP) break;
410
- kept.push(line);
411
- total += add;
412
- }
413
- out.lines = kept.reverse();
414
- return out;
415
- } catch (e) {
416
- teeStderr(`[session-start] buildRecapData catch endpoint=/session-start/recap err=${e.message}\n`);
417
- process.stderr.write(`[session-start] recap build failed: ${e.message}\n`);
418
- return out;
419
- }
420
- }
421
-
422
- // ---------------------------------------------------------------------------
423
- // Skip flag — resume / compact reuses the existing context, so re-injecting
424
- // memory just bloats tokens. Rules still flow through so any rule changes
425
- // since the last turn take effect.
426
- // ---------------------------------------------------------------------------
427
- // Memoized: the memory module is enabled unless modules.memory.enabled === false
428
- // (mirrors server-main's isModuleEnabled). When disabled, server-main never
429
- // spawns the memory worker, so it never advertises a port — awaitMemoryPort would
430
- // otherwise burn its full ~8s grace every session-start before aborting. Detect
431
- // the disabled case up front and skip the inject entirely.
432
- let _memModuleEnabledCache;
433
- function _isMemoryModuleEnabled() {
434
- if (_memModuleEnabledCache !== undefined) return _memModuleEnabledCache;
435
- try {
436
- const mods = readSection('modules');
437
- _memModuleEnabledCache = !(mods && mods.memory && mods.memory.enabled === false);
438
- } catch { _memModuleEnabledCache = true; } // unreadable config → assume enabled (prior behavior)
439
- return _memModuleEnabledCache;
440
- }
441
- function _skipMemoryInject() { return _event.source === 'resume' || _event.source === 'compact' || !_isMemoryModuleEnabled(); }
442
- if (!IS_DAEMON_REQUIRE) {
443
- teeStderr(`[session-start] skipMemoryInject=${_skipMemoryInject()} PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()}\n`);
444
- }
445
-
446
- // ---------------------------------------------------------------------------
447
- // Part: rules (slot 1) — owns ALL one-shot session bootstrap work and emits
448
- // the rules block. Static .md content only; cycle1 is triggered by
449
- // core/recap slots (dedupe coalesces concurrent calls into one run).
450
- // ---------------------------------------------------------------------------
451
-
452
- function hasManagedClaudeMdBlock(targetPath) {
453
- if (!targetPath) return false;
454
- try {
455
- const { expandHome, MARKER_START, MARKER_END } = require(path.join(PLUGIN_ROOT, 'lib', 'claude-md-writer.cjs'));
456
- const resolved = expandHome(targetPath);
457
- if (!resolved || !fs.existsSync(resolved)) return false;
458
- const content = fs.readFileSync(resolved, 'utf8');
459
- return content.includes(MARKER_START) && content.includes(MARKER_END);
460
- } catch {
461
- return false;
462
- }
463
- }
464
-
465
- // Stable, NON-versioned launcher path in mixdog-owned plugin data — survives
466
- // cache cleanup and version rotation, so settings.json can point at it forever
467
- // (the launcher resolves the active install at runtime each tick).
468
- function stableLauncherPath() {
469
- return path.join(DATA_DIR, 'statusline-launcher.mjs').replace(/\\/g, '/');
470
- }
471
-
472
- function injectStatusLine(pluginRoot) {
473
- try {
474
- // Refresh the stable launcher copy from the current install each session
475
- // start so it tracks the latest committed launcher code.
476
- const launcherDst = stableLauncherPath();
477
- try {
478
- const launcherSrc = path.join(pluginRoot, 'bin', 'statusline-launcher.mjs');
479
- fs.mkdirSync(path.dirname(launcherDst), { recursive: true });
480
- fs.copyFileSync(launcherSrc, launcherDst);
481
- } catch (e) {
482
- process.stderr.write(`[session-start] statusLine launcher copy failed: ${e.message}\n`);
483
- }
484
-
485
- const settingsPath = path.join(os.homedir(), '.claude', 'settings.json');
486
- let raw;
487
- try { raw = fs.readFileSync(settingsPath, 'utf8'); } catch { return; }
488
- let settings;
489
- try { settings = JSON.parse(raw); } catch { return; }
490
- if (!settings || typeof settings !== 'object') return;
491
-
492
- const desiredCommand = `bun "${launcherDst}"`;
493
- // Launcher delegates to the fast native shim when present, so a constant
494
- // short tick is fine and avoids cadence ping-pong across versions.
495
- const desiredRefreshInterval = 5;
496
- const existing = settings.statusLine;
497
- // Recognize legacy mixdog-managed entries (versioned shim / statusline.mjs
498
- // commands and the new stable launcher) so old pinned commands are MIGRATED
499
- // to the stable launcher. A genuine user-custom statusLine is left alone.
500
- const _cmd = (existing && typeof existing === 'object' && typeof existing.command === 'string')
501
- ? existing.command : '';
502
- // Normalize Windows backslashes once, then require a mixdog-SPECIFIC marker
503
- // so a generic user command that merely mentions statusline.mjs is not
504
- // hijacked. A bare statusline.mjs NOT under a mixdog path must NOT match.
505
- const c = _cmd.replace(/\\/g, '/');
506
- // No standalone --kind=statusline arm: the real mixdog shim command always
507
- // carries the /mixdog-shim path (caught below), and a bare flag could be a
508
- // genuine user command (e.g. `node user-tool.mjs --kind=statusline`).
509
- const _looksMixdog = /\/mixdog-shim(?:\.exe)?/.test(c)
510
- || c.includes('/trib-plugin/mixdog/')
511
- || (c.includes('mixdog-trib-plugin') && c.includes('statusline-launcher.mjs'));
512
- const isOurs = existing && typeof existing === 'object'
513
- && (existing.source === 'mixdog-auto' || _looksMixdog);
514
-
515
- if (existing && !isOurs) return;
516
- if (
517
- isOurs
518
- && existing.command === desiredCommand
519
- && existing.type === 'command'
520
- && existing.refreshInterval === desiredRefreshInterval
521
- ) return;
522
-
523
- settings.statusLine = {
524
- type: 'command',
525
- command: desiredCommand,
526
- refreshInterval: desiredRefreshInterval,
527
- source: 'mixdog-auto',
528
- };
529
-
530
- const tmpPath = settingsPath + '.mixdog-tmp';
531
- fs.writeFileSync(tmpPath, JSON.stringify(settings, null, 2) + '\n');
532
- fs.renameSync(tmpPath, settingsPath);
533
- } catch (e) {
534
- process.stderr.write(`[session-start] statusLine inject failed: ${e.message}\n`);
535
- }
536
- }
537
-
538
- function cwdToProjectSlug(cwd) {
539
- return path.resolve(cwd).replace(/\\/g, '/').replace(/^([A-Za-z]):/, '$1-').replace(/\//g, '-');
540
- }
541
- function resolveTranscriptPath() {
542
- const direct = _event.transcript_path || _event.transcriptPath;
543
- if (typeof direct === 'string' && direct && fs.existsSync(direct)) return direct;
544
- const sessionId = _event.session_id || _event.sessionId;
545
- const cwd = _event.cwd || process.cwd();
546
- if (typeof sessionId === 'string' && sessionId) {
547
- const candidate = path.join(os.homedir(), '.claude', 'projects', cwdToProjectSlug(cwd), `${sessionId}.jsonl`);
548
- if (fs.existsSync(candidate)) return candidate;
549
- }
550
- return '';
551
- }
552
-
553
- // Prior-session transcript for the ingest-watermark barrier on `/clear`.
554
- // SessionStart carries the NEW session_id; rules-part rebind records the
555
- // outgoing path in active-instance.json `priorTranscriptPath` before updating
556
- // `transcriptPath`. Resolution is deterministic (no mtime scan).
557
- function resolvePriorTranscriptPath() {
558
- const sessionId = String(_event.session_id || _event.sessionId || '').trim();
559
- const active = readJson(ACTIVE_INSTANCE_FILE);
560
- const tp = active && active.transcriptPath;
561
- if (typeof tp === 'string' && tp && fs.existsSync(tp)) {
562
- const base = path.basename(tp, '.jsonl');
563
- if (sessionId && base !== sessionId) return tp;
564
- }
565
- const prior = active && active.priorTranscriptPath;
566
- if (typeof prior === 'string' && prior && fs.existsSync(prior)) {
567
- const base = path.basename(prior, '.jsonl');
568
- if (sessionId && base !== sessionId) return prior;
569
- }
570
- return '';
571
- }
572
-
573
- // Poll memory-service until offsetBytes >= fileSize for the prior transcript,
574
- // bounded by a dedicated sub-budget so cycle1 keeps a floor of the grace window.
575
- async function awaitPriorTranscriptIngested(deadline, opts = {}) {
576
- const slot = opts.slot || 'unknown';
577
- const start = Date.now();
578
- const windowMs = Math.max(0, deadline - start);
579
- // ~4s cap on the 8s graceMs case; smaller windows get half — cycle1 retains the rest.
580
- const BARRIER_BUDGET_MS = Math.min(4000, windowMs / 2);
581
- const barrierDeadline = Math.min(deadline, start + BARRIER_BUDGET_MS);
582
- const priorPath = resolvePriorTranscriptPath();
583
- if (!priorPath) {
584
- teeStderr(`[session-start] ingest-barrier slot=${slot} skip reason=no-prior-transcript source=${_event.source || ''}\n`);
585
- return;
586
- }
587
- teeStderr(`[session-start] ingest-barrier slot=${slot} priorPath=${priorPath}\n`);
588
- const pollMs = 200;
589
- while (Date.now() < barrierDeadline) {
590
- const remaining = barrierDeadline - Date.now();
591
- if (remaining <= 0) break;
592
- const port = await getLiveMemoryServicePort(Math.min(200, remaining));
593
- if (!port) {
594
- await sleepMs(Math.min(pollMs, remaining));
595
- continue;
596
- }
597
- try {
598
- const res = await httpPostJson({
599
- hostname: '127.0.0.1',
600
- port,
601
- path: '/transcript/ingest-sync',
602
- timeoutMs: Math.min(5000, remaining),
603
- body: { path: priorPath, cwd: _event.cwd || process.cwd() },
604
- });
605
- if (res.statusCode === 200) {
606
- let parsed;
607
- try { parsed = JSON.parse(res.body); } catch { parsed = null; }
608
- if (parsed && parsed.ok === true && parsed.complete === true) {
609
- teeStderr(`[session-start] ingest-barrier slot=${slot} complete offsetBytes=${parsed.offsetBytes} fileSize=${parsed.fileSize} elapsed=${Date.now() - start}ms\n`);
610
- return;
611
- }
612
- if (parsed && parsed.ok === true) {
613
- teeStderr(`[session-start] ingest-barrier slot=${slot} pending offsetBytes=${parsed.offsetBytes} fileSize=${parsed.fileSize}\n`);
614
- }
615
- }
616
- } catch (e) {
617
- teeStderr(`[session-start] ingest-barrier slot=${slot} err=${(e && e.message) || e}\n`);
618
- }
619
- await sleepMs(Math.min(pollMs, Math.max(0, barrierDeadline - Date.now())));
620
- }
621
- teeStderr(`[session-start] ingest-barrier slot=${slot} deadline-reached proceed elapsed=${Date.now() - start}ms\n`);
622
- }
623
-
624
- function rebindActiveInstance() {
625
- try {
626
- const activePath = ACTIVE_INSTANCE_FILE;
627
- if (!fs.existsSync(activePath)) return;
628
- const active = JSON.parse(fs.readFileSync(activePath, 'utf8'));
629
- if (!active.httpPort) return;
630
- const transcriptPath = resolveTranscriptPath();
631
- const payload = transcriptPath ? JSON.stringify({ transcriptPath }) : '';
632
- const authHeaders = ownerAuthHeaders(active);
633
- if (!authHeaders) return;
634
- const headers = { 'Content-Type': 'application/json', ...authHeaders };
635
- if (payload) headers['Content-Length'] = Buffer.byteLength(payload);
636
- const req2 = http.request({
637
- hostname: '127.0.0.1',
638
- port: active.httpPort,
639
- path: '/rebind',
640
- method: 'POST',
641
- timeout: 3000,
642
- headers,
643
- });
644
- req2.on('error', () => {});
645
- req2.on('timeout', () => req2.destroy());
646
- if (payload) req2.write(payload);
647
- req2.end();
648
- } catch {}
649
- }
650
-
651
- // TCP probe — resolves true if the port accepts a connection within probeMs,
652
- // false on ECONNREFUSED / EHOSTUNREACH / timeout / any other socket error.
653
- // Used by pollActiveInstance to skip stale active-instance.json entries left
654
- // over from a previous session whose channels owner is already dead.
655
- function probeTcpPort(port, probeMs) {
656
- return new Promise((resolve) => {
657
- let settled = false;
658
- const done = (alive) => {
659
- if (settled) return;
660
- settled = true;
661
- try { socket.destroy(); } catch {}
662
- resolve(alive);
663
- };
664
- const socket = net.createConnection({ port, host: '127.0.0.1' });
665
- socket.setTimeout(Math.max(1, probeMs));
666
- socket.once('connect', () => done(true));
667
- socket.once('error', () => done(false));
668
- socket.once('timeout', () => done(false));
669
- });
670
- }
671
-
672
- // Memory-runtime readiness probe. A promoted-but-uninitialized fork-proxy keeps
673
- // a live TCP listener while its `db` is still null (it short-circuited
674
- // _initRuntime), so a raw TCP accept does NOT prove the memory worker can serve
675
- // queries — recap/core would then 500 and silently drop context. GET /health
676
- // returns 200 only once the worker is _initialized with a live DB; 503 while
677
- // booting/promoting and 500 if the DB is broken. Gate awaitMemoryPort on a 200.
678
- function probeMemoryHealthy(port, timeoutMs) {
679
- return new Promise((resolve) => {
680
- let settled = false;
681
- const done = (ok) => { if (settled) return; settled = true; resolve(ok); };
682
- let req;
683
- try {
684
- req = http.request(
685
- { host: '127.0.0.1', port, path: '/health', method: 'GET', timeout: Math.max(1, timeoutMs) },
686
- (res) => {
687
- const ok = res.statusCode === 200;
688
- res.resume();
689
- res.once('end', () => done(ok));
690
- res.once('error', () => done(false));
691
- },
692
- );
693
- } catch { done(false); return; }
694
- req.once('error', () => done(false));
695
- req.once('timeout', () => { try { req.destroy(); } catch {} done(false); });
696
- req.end();
697
- });
698
- }
699
-
700
- async function pollActiveInstance(graceMs) {
701
- const activeDir = MIXDOG_RUNTIME_ROOT;
702
- const activeFile = ACTIVE_INSTANCE_FILE;
703
- const _pollStart = Date.now();
704
- const deadline = _pollStart + Math.max(0, graceMs);
705
- teeStderr(`[session-start] pollActiveInstance start graceMs=${graceMs}\n`);
706
- try { fs.mkdirSync(activeDir, { recursive: true }); } catch {}
707
-
708
- // Single read+probe attempt. Stale guard: file may be left by a dead owner,
709
- // so TCP-probe httpPort before accepting. Returns null on any failure
710
- // (missing file, missing httpPort, dead port, parse error, deadline hit).
711
- const tryRead = async () => {
712
- try {
713
- if (!fs.existsSync(activeFile)) return null;
714
- const active = JSON.parse(fs.readFileSync(activeFile, 'utf8'));
715
- if (!active || !active.httpPort) return null;
716
- const remaining = deadline - Date.now();
717
- if (remaining <= 0) return null;
718
- const probeMs = Math.min(200, remaining);
719
- const alive = await probeTcpPort(active.httpPort, probeMs);
720
- teeStderr(`[session-start] pollActiveInstance probePort=${active.httpPort} probeMs=${probeMs} alive=${alive}\n`);
721
- return alive ? active : null;
722
- } catch {
723
- return null;
724
- }
725
- };
726
-
727
- // Fast path: supervisor already up. Most sessions hit this — skips watch setup.
728
- const initial = await tryRead();
729
- if (initial) {
730
- teeStderr(`[session-start] pollActiveInstance done elapsed=${Date.now() - _pollStart}ms port=${initial.httpPort} via=initial\n`);
731
- return initial;
732
- }
733
-
734
- // Bounded poll loop. Windows fs.watch first-event latency averaged ~3.3s
735
- // on this directory (measured over recent sessions), so a fixed 200ms
736
- // tick is deterministic and faster on average. server.mjs writes
737
- // active-instance.json atomically via .tmp + rename, so every poll sees
738
- // either no file or a fully-written one — no torn-read window. setTimeout
739
- // caps total wait at graceMs so the function honors its contract.
740
- return new Promise((resolve) => {
741
- let settled = false;
742
- let inFlight = false;
743
- let pollTimer = null;
744
- let deadlineTimer = null;
745
-
746
- const finish = (result, via) => {
747
- if (settled) return;
748
- settled = true;
749
- if (pollTimer) { clearInterval(pollTimer); pollTimer = null; }
750
- if (deadlineTimer) { clearTimeout(deadlineTimer); deadlineTimer = null; }
751
- if (result) {
752
- teeStderr(`[session-start] pollActiveInstance done elapsed=${Date.now() - _pollStart}ms port=${result.httpPort} via=${via}\n`);
753
- } else {
754
- teeStderr(`[session-start] pollActiveInstance end elapsed=${Date.now() - _pollStart}ms result=null\n`, { critical: true });
755
- }
756
- resolve(result);
757
- };
758
-
759
- const checkOnce = async () => {
760
- if (settled || inFlight) return;
761
- inFlight = true;
762
- try {
763
- const a = await tryRead();
764
- if (a) finish(a, 'poll');
765
- } finally {
766
- inFlight = false;
767
- }
768
- };
769
-
770
- // Node setInterval / setTimeout are ref'd by default, so they keep the
771
- // event loop alive. The outer caller also awaits this Promise, which is
772
- // itself a liveness guarantee.
773
- pollTimer = setInterval(checkOnce, 200);
774
- const remaining = Math.max(0, deadline - Date.now());
775
- deadlineTimer = setTimeout(() => finish(null, null), remaining);
776
- });
777
- }
778
-
779
- // Wait until memory_port appears in active-instance.json and /health is ready.
780
- // pollActiveInstance only proves channels httpPort;
781
- // memory_port is written later via memory worker `ready` IPC. Without this,
782
- // getMemoryServicePort throws on fast /clear paths and recap emits 0 lines.
783
- async function awaitMemoryPort(graceMs) {
784
- const _t0 = Date.now();
785
- const deadline = _t0 + Math.max(0, graceMs);
786
- teeStderr(`[session-start] awaitMemoryPort start graceMs=${graceMs}\n`);
787
-
788
- while (Date.now() < deadline) {
789
- const remaining = deadline - Date.now();
790
- if (remaining <= 0) break;
791
- try {
792
- if (!fs.existsSync(ACTIVE_INSTANCE_FILE)) {
793
- await sleepMs(Math.min(200, remaining));
794
- continue;
795
- }
796
- const advertised = readAdvertisedMemoryPort();
797
- if (!advertised) {
798
- await sleepMs(Math.min(200, remaining));
799
- continue;
800
- }
801
- if (advertised.stale) {
802
- teeStderr(`[session-start] awaitMemoryPort stalePort=${advertised.port} activeServerPid=${advertised.activeServerPid} memoryServerPid=${advertised.memoryServerPid}\n`);
803
- await sleepMs(Math.min(200, remaining));
804
- continue;
805
- }
806
- const port = advertised.port;
807
- const probeMs = Math.min(200, remaining);
808
- const healthy = await probeMemoryHealthy(port, probeMs);
809
- let supersededBy = null;
810
- let staleAfterProbe = false;
811
- try {
812
- const latest = readAdvertisedMemoryPort();
813
- if (latest && latest.stale) staleAfterProbe = true;
814
- else if (latest && latest.port !== port) supersededBy = latest.port;
815
- } catch {}
816
- const suffix = `${staleAfterProbe ? ' staleAfterProbe=true' : ''}${supersededBy ? ` supersededBy=${supersededBy}` : ''}`;
817
- teeStderr(`[session-start] awaitMemoryPort probePort=${port} probeMs=${probeMs} healthy=${healthy}${suffix}\n`);
818
- if (staleAfterProbe || supersededBy) continue;
819
- if (healthy) {
820
- teeStderr(`[session-start] awaitMemoryPort done elapsed=${Date.now() - _t0}ms port=${port} via=poll\n`);
821
- return port;
822
- }
823
- } catch {
824
- // Re-read active-instance.json on the next tick; atomic rename can
825
- // transiently hide the file on Windows.
826
- }
827
- await sleepMs(Math.min(200, Math.max(0, deadline - Date.now())));
828
- }
829
-
830
- teeStderr(`[session-start] awaitMemoryPort end elapsed=${Date.now() - _t0}ms result=null\n`, { critical: true });
831
- return null;
832
- }
833
-
834
- function httpPostJson({ hostname, port, path: urlPath, timeoutMs, body, ownerActive, authHeaders: explicitAuthHeaders }) {
835
- return new Promise((resolve, reject) => {
836
- const _t0 = Date.now();
837
- const payload = typeof body === 'string' ? body : JSON.stringify(body);
838
- const authHeaders = explicitAuthHeaders || (ownerActive ? ownerAuthHeaders(ownerActive) : {});
839
- if (ownerActive && !authHeaders) {
840
- resolve({
841
- statusCode: 0,
842
- body: JSON.stringify({ ok: false, reason: 'owner-route-unavailable' }),
843
- ownerRouteUnavailable: true,
844
- });
845
- return;
846
- }
847
- const req = http.request({
848
- hostname,
849
- port,
850
- path: urlPath,
851
- method: 'POST',
852
- headers: {
853
- 'Content-Type': 'application/json',
854
- 'Content-Length': Buffer.byteLength(payload),
855
- ...authHeaders,
856
- },
857
- timeout: Math.max(1, timeoutMs),
858
- }, (res) => {
859
- const chunks = [];
860
- res.on('data', (c) => chunks.push(c));
861
- res.on('end', () => {
862
- const _body = Buffer.concat(chunks).toString('utf8');
863
- const _elapsed = Date.now() - _t0;
864
- let _bodyReason = null;
865
- try { const _p = JSON.parse(_body); if (_p && typeof _p.reason === 'string') _bodyReason = _p.reason; } catch {}
866
- teeStderr(`[session-start] httpPostJson path=${urlPath} port=${port} timeoutMs=${timeoutMs} statusCode=${res.statusCode} bodyReason=${_bodyReason || ''} elapsed=${_elapsed}ms\n`);
867
- resolve({ statusCode: res.statusCode, body: _body });
868
- });
869
- });
870
- req.on('error', (e) => reject(e));
871
- req.on('timeout', () => { req.destroy(new Error('timeout')); });
872
- req.end(payload);
873
- });
874
- }
875
-
876
- // Pull cycle1 signals from a cycle1 response. Memory worker returns an MCP
877
- // envelope { content:[{type:'text', text:'cycle1: chunks=N processed=M
878
- // skipped=K pending=P inFlight=B'}], isError }; channels owner returns
879
- // { ok, result } where result may carry the same text shape. Each field is
880
- // null when not parseable (treated downstream as "unknown / cannot verify").
881
- function extractCycleSignals(parsed) {
882
- const empty = { processed: null, pendingRows: null, skippedInFlight: null };
883
- if (!parsed) return empty;
884
- let text = '';
885
- if (Array.isArray(parsed.content) && parsed.content[0] && typeof parsed.content[0].text === 'string') {
886
- text = parsed.content[0].text;
887
- } else if (parsed.result && typeof parsed.result === 'object'
888
- && Array.isArray(parsed.result.content)
889
- && parsed.result.content[0]
890
- && typeof parsed.result.content[0].text === 'string') {
891
- // Channels owner wraps the memory worker's MCP envelope as
892
- // { ok, result: { content:[{type:'text',text:'cycle1: ...'}], isError } },
893
- // so the signal text lives at parsed.result.content[0].text.
894
- text = parsed.result.content[0].text;
895
- } else if (parsed.result && typeof parsed.result === 'object' && typeof parsed.result.text === 'string') {
896
- text = parsed.result.text;
897
- } else if (typeof parsed.result === 'string') {
898
- text = parsed.result;
899
- }
900
- if (typeof text !== 'string') return empty;
901
- const proc = text.match(/processed=(\d+)/);
902
- const pend = text.match(/pending=(\d+)/);
903
- const inflight = text.match(/inFlight=(true|false)/);
904
- return {
905
- processed: proc ? parseInt(proc[1], 10) : null,
906
- pendingRows: pend ? parseInt(pend[1], 10) : null,
907
- skippedInFlight: inflight ? inflight[1] === 'true' : null,
908
- };
909
- }
910
-
911
- async function requestCycle1MemoryDirect(deadline, opts = {}, priorReason = '') {
912
- const slot = opts.slot || 'unknown';
913
- const start = Date.now();
914
- const remainingForProbe = deadline - Date.now();
915
- if (remainingForProbe <= 0) {
916
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=timeout-before-probe prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
917
- return null;
918
- }
919
- const port = await getLiveMemoryServicePort(Math.min(200, remainingForProbe));
920
- if (!port) {
921
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=no-memory-port prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
922
- return null;
923
- }
924
- const remaining = deadline - Date.now();
925
- if (remaining <= 0) {
926
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=timeout-before-post prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
927
- return null;
928
- }
929
-
930
- try {
931
- const ON_DEMAND_CYCLE1_ARGS = { min_batch: 1, session_cap: 5, batch_size: 20, concurrency: 5 };
932
- const res = await httpPostJson({
933
- hostname: '127.0.0.1',
934
- port,
935
- path: '/api/tool',
936
- timeoutMs: remaining,
937
- body: {
938
- name: 'memory',
939
- arguments: {
940
- action: 'cycle1',
941
- ...ON_DEMAND_CYCLE1_ARGS,
942
- _callerDeadlineMs: remaining,
943
- },
944
- },
945
- });
946
- if (res.statusCode !== 200) {
947
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=non-200 statusCode=${res.statusCode} prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
948
- return { ok: false, reason: 'memory-direct-non-200', statusCode: res.statusCode, bodyReason: null, elapsedMs: Date.now() - start, route: 'memory-direct' };
949
- }
950
- let parsed;
951
- try { parsed = JSON.parse(res.body); }
952
- catch {
953
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=parse-error prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
954
- return { ok: false, reason: 'memory-direct-parse-error', statusCode: 200, bodyReason: null, elapsedMs: Date.now() - start, route: 'memory-direct' };
955
- }
956
- if (parsed && parsed.isError) {
957
- const sigText = Array.isArray(parsed.content) && parsed.content[0] ? parsed.content[0].text : '';
958
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=body-is-error text=${String(sigText || '').slice(0, 200)} prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
959
- return { ok: false, reason: 'memory-direct-body-is-error', statusCode: 200, bodyReason: null, elapsedMs: Date.now() - start, route: 'memory-direct' };
960
- }
961
- const sig = extractCycleSignals(parsed);
962
- const procStr = sig.processed != null ? sig.processed : '?';
963
- const pendStr = sig.pendingRows != null ? sig.pendingRows : '?';
964
- const inFlightStr = sig.skippedInFlight === true ? 'true'
965
- : sig.skippedInFlight === false ? 'false' : '?';
966
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=ok processed=${procStr} pending=${pendStr} inFlight=${inFlightStr} prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
967
- return {
968
- ok: true,
969
- processed: sig.processed,
970
- pendingRows: sig.pendingRows,
971
- skippedInFlight: sig.skippedInFlight,
972
- route: 'memory-direct',
973
- elapsedMs: Date.now() - start,
974
- };
975
- } catch (e) {
976
- const msg = (e && e.message) || e;
977
- const reason = /timeout/i.test(String(msg)) ? 'memory-direct-timeout' : 'memory-direct-http-error';
978
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct reason=${reason} err=${String(msg).slice(0, 200)} prior=${priorReason} elapsed=${Date.now() - start}ms\n`);
979
- return { ok: false, reason, statusCode: null, bodyReason: null, elapsedMs: Date.now() - start, route: 'memory-direct' };
980
- }
981
- }
982
-
983
- async function waitCycle1MemoryDirect(deadline, opts = {}, waitMs = 1800) {
984
- const slot = opts.slot || 'unknown';
985
- const start = Date.now();
986
- const waitUntil = Math.min(deadline, start + Math.max(0, waitMs));
987
- const pollMs = 50;
988
- let attempt = 0;
989
- while (Date.now() < waitUntil) {
990
- const sleepMs = Math.min(pollMs, waitUntil - Date.now());
991
- if (sleepMs > 0) await new Promise((r) => setTimeout(r, sleepMs));
992
- const direct = await requestCycle1MemoryDirect(deadline, opts, `pre-channels-wait-${attempt}`);
993
- if (direct && direct.ok) {
994
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct wait-hit attempt=${attempt} elapsed=${Date.now() - start}ms\n`);
995
- return direct;
996
- }
997
- if (direct && !direct.ok) {
998
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct wait-stop attempt=${attempt} reason=${direct.reason || 'unknown'} elapsed=${Date.now() - start}ms\n`);
999
- return null;
1000
- }
1001
- attempt++;
1002
- }
1003
- teeStderr(`[session-start] cycle1 slot=${slot} route=memory-direct wait-miss attempts=${attempt} elapsed=${Date.now() - start}ms\n`);
1004
- return null;
1005
- }
1006
-
1007
- // One full cycle1 attempt. Prefer the memory service when it is already
1008
- // advertised and alive: channels /cycle1 is only a proxy to the same memory
1009
- // action, while the channels owner can lag during session handoff. If memory
1010
- // is not ready, fall back to the channels owner readiness path.
1011
- async function requestCycle1Once(deadline, opts) {
1012
- const slot = opts.slot || 'unknown';
1013
- const graceMs = Number.isFinite(opts.graceMs) ? opts.graceMs : 5000;
1014
- const start = Date.now();
1015
-
1016
- const finish = (payload) => {
1017
- const elapsedMs = Date.now() - start;
1018
- if (payload.ok) {
1019
- const procStr = payload.processed != null ? payload.processed : '?';
1020
- const pendStr = payload.pendingRows != null ? payload.pendingRows : '?';
1021
- const inFlightStr = payload.skippedInFlight === true ? 'true'
1022
- : payload.skippedInFlight === false ? 'false' : '?';
1023
- teeStderr(`[session-start] cycle1 slot=${slot} route=channels reason=ok processed=${procStr} pending=${pendStr} inFlight=${inFlightStr} elapsed=${elapsedMs}ms\n`);
1024
- return {
1025
- ok: true,
1026
- processed: payload.processed,
1027
- pendingRows: payload.pendingRows,
1028
- skippedInFlight: payload.skippedInFlight,
1029
- route: 'channels',
1030
- elapsedMs,
1031
- };
1032
- }
1033
- const sc = payload.statusCode != null ? ` statusCode=${payload.statusCode}` : '';
1034
- teeStderr(`[session-start] cycle1 slot=${slot} route=channels reason=${payload.reason}${sc} elapsed=${elapsedMs}ms\n`);
1035
- return { ok: false, reason: payload.reason, statusCode: payload.statusCode, bodyReason: payload.bodyReason || null, elapsedMs, route: 'channels' };
1036
- };
1037
-
1038
- const classifyError = (e) => {
1039
- const msg = (e && e.message) || '';
1040
- if (/timeout/i.test(msg)) return 'timeout';
1041
- if ((e && e.code === 'ECONNREFUSED') || /ECONNREFUSED/i.test(msg)) return 'connect-refused';
1042
- return 'http-error';
1043
- };
1044
-
1045
- const directFirst = await requestCycle1MemoryDirect(deadline, opts, 'pre-channels');
1046
- if (directFirst && directFirst.ok) return directFirst;
1047
- if (!directFirst) {
1048
- const directAfterWait = await waitCycle1MemoryDirect(deadline, opts, Math.min(graceMs, 1800));
1049
- if (directAfterWait && directAfterWait.ok) return directAfterWait;
1050
- }
1051
-
1052
- const remainingForGrace = deadline - Date.now();
1053
- if (remainingForGrace <= 0) return finish({ ok: false, reason: 'timeout' });
1054
- const active = await pollActiveInstance(Math.min(graceMs, remainingForGrace));
1055
- const tPollEnd = Date.now();
1056
- if (!active) {
1057
- const direct = await requestCycle1MemoryDirect(deadline, opts, 'no-active-instance');
1058
- if (direct && direct.ok) return direct;
1059
- const reason = (Date.now() >= deadline) ? 'timeout' : 'no-active-instance';
1060
- return finish({ ok: false, reason });
1061
- }
1062
- const port = active.httpPort;
1063
- const remaining = deadline - Date.now();
1064
- if (remaining <= 0) return finish({ ok: false, reason: 'timeout' });
1065
- const authHeaders = ownerAuthHeaders(active);
1066
- if (!authHeaders) return finish({ ok: false, reason: 'owner-route-unavailable' });
1067
-
1068
- try {
1069
- const tPostStart = Date.now();
1070
- // On-demand cycle1 (SessionStart hook path): min_batch=1 triggers on a
1071
- // single pending row; session_cap=5 × batch_size=20 caps a single hook
1072
- // pass at 100 rows so wallclock stays low. Use modest 2-way fan-out when
1073
- // multiple windows are ready; periodic path also runs 2×50 in parallel.
1074
- const ON_DEMAND_CYCLE1_ARGS = { min_batch: 1, session_cap: 5, batch_size: 20, concurrency: 5 };
1075
- const res = await httpPostJson({
1076
- hostname: '127.0.0.1',
1077
- port,
1078
- path: '/cycle1',
1079
- timeoutMs: remaining,
1080
- ownerActive: active,
1081
- authHeaders,
1082
- body: { timeout_ms: remaining, args: ON_DEMAND_CYCLE1_ARGS },
1083
- });
1084
- teeStderr(`[session-start] cycle1 slot=${slot} timing pollMs=${tPollEnd - start} postMs=${Date.now() - tPostStart}\n`);
1085
- if (res.ownerRouteUnavailable) {
1086
- return finish({ ok: false, reason: 'owner-route-unavailable' });
1087
- }
1088
- if (res.statusCode !== 200) {
1089
- // Surface the channels endpoint's body `reason` (memory-not-ready,
1090
- // worker-unavailable, ipc-error, memory-timeout, ...) so downstream
1091
- // retry logic and operators can see the precise transient class.
1092
- let bodyReason = null;
1093
- try {
1094
- const parsed = JSON.parse(res.body);
1095
- if (parsed && typeof parsed.reason === 'string') bodyReason = parsed.reason;
1096
- } catch {}
1097
- const reason = bodyReason ? `non-200/${bodyReason}` : 'non-200';
1098
- return finish({ ok: false, reason, statusCode: res.statusCode, bodyReason });
1099
- }
1100
- try {
1101
- const parsed = JSON.parse(res.body);
1102
- if (parsed && parsed.ok) {
1103
- const sig = extractCycleSignals(parsed);
1104
- return finish({
1105
- ok: true,
1106
- processed: sig.processed,
1107
- pendingRows: sig.pendingRows,
1108
- skippedInFlight: sig.skippedInFlight,
1109
- });
1110
- }
1111
- return finish({ ok: false, reason: 'body-not-ok', statusCode: 200 });
1112
- } catch {
1113
- return finish({ ok: false, reason: 'parse-error', statusCode: 200 });
1114
- }
1115
- } catch (e) {
1116
- const reason = classifyError(e);
1117
- if (reason === 'connect-refused' || reason === 'timeout') {
1118
- const direct = await requestCycle1MemoryDirect(deadline, opts, reason);
1119
- if (direct && direct.ok) return direct;
1120
- }
1121
- return finish({ ok: false, reason });
1122
- }
1123
- }
1124
-
1125
- // Public entry point. Single in-flight call — server-main.callWorker now
1126
- // awaits the worker's first 'ready' IPC, so a pre-ready /cycle1 holds until
1127
- // memory is up instead of bouncing 503. Keep one follow-up retry for the
1128
- // processed=0 case: that means either an in-flight dedup hit (server
1129
- // returned the prior run's empty result) or a pre-ingest race
1130
- // (transcript-watch had not yet ingested pending raw entries). A short sleep
1131
- // + second call covers both. If the second pass also returns 0, genuinely
1132
- // empty.
1133
- async function requestCycle1(timeoutMs, opts = {}) {
1134
- const slot = opts.slot || 'unknown';
1135
- const graceMs = Number.isFinite(opts.graceMs) ? opts.graceMs : 5000;
1136
- const start = Date.now();
1137
- const deadline = start + Math.max(0, timeoutMs);
1138
- teeStderr(`[session-start] cycle1 slot=${slot} start graceMs=${graceMs} timeoutMs=${timeoutMs}\n`);
1139
- teeStderr(`[boot-time] tag=cycle1-entry slot=${slot} tMs=${start}\n`);
1140
-
1141
- // Boot-race transient classifier: a fresh session can fire cycle1 while the
1142
- // new owner's channels worker is still binding 3462 (connect-refused), the
1143
- // active-instance.json is briefly empty (no-active-instance), or channels is
1144
- // up but the parent's memory worker hasn't sent its first 'ready' IPC yet
1145
- // (503 with bodyReason in {memory-not-ready, worker-unavailable, ipc-error,
1146
- // memory-timeout}). Warm peer boots often clear in 1–3s; cold first-boot
1147
- // runtime init (PG attach + embedding warmup under multi-instance contention)
1148
- // can take longer, so retry with backoff up to a wider budget rather than
1149
- // skipping recap entirely.
1150
- const TRANSIENT_BOOT_BODY_REASONS = new Set([
1151
- 'memory-not-ready',
1152
- 'worker-unavailable',
1153
- 'ipc-error',
1154
- 'memory-timeout',
1155
- 'backend-not-ready',
1156
- 'beacon-booting',
1157
- ]);
1158
- // memory-degraded is NOT transient: restart cap exceeded or PG PANIC.
1159
- // Retrying it within the transient budget (~45s) would only delay the
1160
- // session with no benefit, so it is excluded before transient classification.
1161
- const NON_TRANSIENT_BOOT_BODY_REASONS = new Set([
1162
- 'memory-degraded',
1163
- ]);
1164
- const TRANSIENT_TOP_REASONS = new Set([
1165
- 'connect-refused',
1166
- 'no-active-instance',
1167
- ]);
1168
- const isTransientBootFailure = (r) => {
1169
- if (!r || r.ok) return false;
1170
- if (r.bodyReason && NON_TRANSIENT_BOOT_BODY_REASONS.has(r.bodyReason)) return false;
1171
- if (r.bodyReason && TRANSIENT_BOOT_BODY_REASONS.has(r.bodyReason)) return true;
1172
- if (TRANSIENT_TOP_REASONS.has(r.reason)) return true;
1173
- // 5xx + missing body — boot/restart race: a worker socket closed
1174
- // mid-request surfaces as a channels /cycle1 500 (bodyReason empty), and
1175
- // a pre-stub 503 looks the same. Both resolve once the worker finishes
1176
- // (re)starting, so retry within the boot budget instead of aborting
1177
- // recap/core. Known degraded states carry a bodyReason and are filtered
1178
- // by NON_TRANSIENT_BOOT_BODY_REASONS above before reaching here.
1179
- if (r.statusCode >= 500 && !r.bodyReason) return true;
1180
- return false;
1181
- };
1182
- const TRANSIENT_RETRY_DELAY_MS = 250;
1183
- const TRANSIENT_RETRY_BUDGET_MS = 45000;
1184
- const transientDeadline = start + TRANSIENT_RETRY_BUDGET_MS;
1185
-
1186
- try {
1187
- await awaitPriorTranscriptIngested(deadline, opts);
1188
- let r1 = await requestCycle1Once(deadline, opts);
1189
- let transientAttempt = 0;
1190
- while (
1191
- isTransientBootFailure(r1)
1192
- && Date.now() < transientDeadline
1193
- && (deadline - Date.now()) > TRANSIENT_RETRY_DELAY_MS + 500
1194
- ) {
1195
- transientAttempt++;
1196
- teeStderr(`[session-start] cycle1 slot=${slot} transient-retry attempt=${transientAttempt} bodyReason=${r1.bodyReason || ''} statusCode=${r1.statusCode != null ? r1.statusCode : ''} elapsed=${r1.elapsedMs}ms nextDelay=${TRANSIENT_RETRY_DELAY_MS}ms reason=${r1.reason}\n`);
1197
- await new Promise((r) => setTimeout(r, TRANSIENT_RETRY_DELAY_MS));
1198
- r1 = await requestCycle1Once(deadline, { ...opts, slot: `${slot}:t${transientAttempt}` });
1199
- }
1200
- if (!r1.ok) return r1;
1201
- if (r1.processed != null && r1.processed > 0) return r1;
1202
- // After ingest-barrier, pendingRows===0 with no in-flight dedup is terminal.
1203
- if (r1.pendingRows === 0 && r1.skippedInFlight === false) return r1;
1204
- const RETRY_DELAY_MS = 800;
1205
- const remaining = deadline - Date.now();
1206
- if (remaining <= RETRY_DELAY_MS + 200) return r1;
1207
- await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
1208
- const r2 = await requestCycle1Once(deadline, { ...opts, slot: `${slot}:r` });
1209
- if (!r2.ok) {
1210
- teeStderr(`[session-start] cycle1 slot=${slot} r2-failed stale-fallback r1.pendingRows=${r1.pendingRows != null ? r1.pendingRows : '?'} r1.skippedInFlight=${r1.skippedInFlight != null ? r1.skippedInFlight : '?'}\n`);
1211
- }
1212
- return r2.ok ? r2 : r1;
1213
- } catch (e) {
1214
- teeStderr(`[session-start] cycle1 slot=${slot} exception=${(e && e.message) || e}\n`);
1215
- return { ok: false, reason: 'exception', elapsedMs: Date.now() - start };
1216
- }
1217
- }
1218
-
1219
- // Best-effort POST /recap/reset to the channels owner. Used on `/clear` so
1220
- // the forked status server's recapState (which lives in a child process the
1221
- // hook can't reach via IPC) drops the prior session's badge. Bounded by
1222
- // graceMs and silent on failure — recap reset is cosmetic, never block
1223
- // SessionStart on it.
1224
- async function requestRecapReset(graceMs) {
1225
- try {
1226
- const active = await pollActiveInstance(Math.max(0, graceMs));
1227
- if (!active || !active.httpPort) {
1228
- teeStderr('[session-start] recap-reset skipped: no active instance\n');
1229
- return;
1230
- }
1231
- const authHeaders = ownerAuthHeaders(active);
1232
- if (!authHeaders) {
1233
- teeStderr('[session-start] recap-reset skipped: owner route unavailable in this session\n');
1234
- return;
1235
- }
1236
- const res = await httpPostJson({
1237
- hostname: '127.0.0.1',
1238
- port: active.httpPort,
1239
- path: '/recap/reset',
1240
- timeoutMs: 2000,
1241
- ownerActive: active,
1242
- authHeaders,
1243
- body: {},
1244
- });
1245
- if (res.statusCode !== 200) {
1246
- teeStderr(`[session-start] recap-reset non-200 status=${res.statusCode}\n`);
1247
- }
1248
- } catch (e) {
1249
- teeStderr(`[session-start] recap-reset failed: ${(e && e.message) || e}\n`);
1250
- }
1251
- }
1252
-
1253
- async function runRulesPart() {
1254
- teeStderr(`[session-start] runRulesPart enter PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()}\n`);
1255
- // First-boot one-shot work — only slot 1 (rules) runs this. Other slots
1256
- // skip it entirely so they stay read-only and side-effect free.
1257
- try {
1258
- const flagPath = path.join(DATA_DIR, '.first-boot-seen');
1259
- if (!fs.existsSync(flagPath)) {
1260
- // No first-boot config-window open here: it double-booted the
1261
- // setup-server against the unconditional every-session `--prewarm`
1262
- // below (both racing to bind the port). The server is warmed by the
1263
- // prewarm; the window opens only on an explicit `/mixdog:config`.
1264
- fs.writeFileSync(flagPath, '');
1265
- }
1266
- } catch {}
1267
-
1268
- // Every-session pre-warm: boot the config-UI setup-server in the
1269
- // background (window-free) so the first `/mixdog:config` open is instant.
1270
- // Fire-and-forget + hidden; `--prewarm` makes launch-core boot the server
1271
- // only when it is not already alive and never opens a browser window, so
1272
- // this is a cheap no-op once the server is running.
1273
- try {
1274
- const _prewarm = spawn('bun', [path.join(PLUGIN_ROOT, 'setup', 'launch.mjs'), '--prewarm'], {
1275
- detached: true,
1276
- stdio: 'ignore',
1277
- windowsHide: true,
1278
- });
1279
- // ENOENT (bun not on PATH) and other spawn failures surface ASYNC as an
1280
- // 'error' event, NOT via the try/catch above. Without a listener Node
1281
- // throws it as an uncaught exception and crashes the hook. Fail soft:
1282
- // prewarm is a best-effort optimization, never required for a session.
1283
- _prewarm.on('error', (e) => {
1284
- teeStderr(`[session-start] prewarm spawn failed (non-fatal): ${(e && e.message) || e}\n`);
1285
- });
1286
- _prewarm.unref();
1287
- } catch {}
1288
-
1289
- try {
1290
- const asp = path.join(DATA_DIR, 'active-session.txt');
1291
- if (fs.existsSync(asp)) fs.unlinkSync(asp);
1292
- } catch {}
1293
-
1294
- // Persist user cwd so the MCP server (spawned from cache dir) can resolve
1295
- // the correct sandbox root. Atomic rename prevents partial reads.
1296
- try {
1297
- const eventCwd = typeof _event.cwd === 'string' ? _event.cwd.trim() : '';
1298
- if (eventCwd) {
1299
- const cwdTxtPath = path.join(DATA_DIR, 'user-cwd.txt');
1300
- const cwdTmpPath = cwdTxtPath + '.tmp';
1301
- fs.writeFileSync(cwdTmpPath, eventCwd);
1302
- fs.renameSync(cwdTmpPath, cwdTxtPath);
1303
- }
1304
- } catch {}
1305
-
1306
- try {
1307
- const stalePending = path.join(DATA_DIR, 'recap-pending.json');
1308
- if (fs.existsSync(stalePending)) fs.unlinkSync(stalePending);
1309
- } catch {}
1310
-
1311
- injectStatusLine(PLUGIN_ROOT);
1312
- rebindActiveInstance();
1313
-
1314
- let _channelsConfig = {};
1315
- try { _channelsConfig = readSection('channels'); } catch {}
1316
- const injection = _channelsConfig && typeof _channelsConfig.promptInjection === 'object' ? _channelsConfig.promptInjection : {};
1317
- const claudeMdMode = injection.mode === 'claude_md';
1318
- const claudeMdTargetPath = typeof injection.targetPath === 'string' && injection.targetPath
1319
- ? injection.targetPath
1320
- : '~/.claude/CLAUDE.md';
1321
- const needsBootstrapInjection = claudeMdMode && !hasManagedClaudeMdBlock(claudeMdTargetPath);
1322
-
1323
- let additionalContext = '';
1324
- if (!claudeMdMode || needsBootstrapInjection) {
1325
- try {
1326
- const { buildInjectionContent } = require(path.join(PLUGIN_ROOT, 'lib', 'rules-builder.cjs'));
1327
- additionalContext = buildInjectionContent({ PLUGIN_ROOT, DATA_DIR }) || '';
1328
- } catch {}
1329
- }
1330
-
1331
- // claude_md mode + missing managed block: persist the file alongside emit so the
1332
- // next session boots from the managed block instead of the inline fallback.
1333
- if (claudeMdMode && needsBootstrapInjection && additionalContext) {
1334
- try {
1335
- const { upsertManagedBlock } = require(path.join(PLUGIN_ROOT, 'lib', 'claude-md-writer.cjs'));
1336
- upsertManagedBlock(claudeMdTargetPath, additionalContext);
1337
- teeStderr(`[session-start] claude_md: regenerated ${claudeMdTargetPath} after missing managed block\n`);
1338
- } catch (e) {
1339
- teeStderr(`[session-start] claude_md regenerate failed: ${e && e.message || e}\n`);
1340
- }
1341
- }
1342
-
1343
- // On `/clear`, drop the prior session's recap badge from the forked status
1344
- // server. Hook runs in a separate cjs process with no IPC handle to that
1345
- // child, so we POST /recap/reset to the channels owner instead. Best
1346
- // effort, short grace — channels owner is usually already up on /clear.
1347
- if (_event.source === 'clear') {
1348
- // Fire-and-forget — recap reset is cosmetic, never block response path.
1349
- requestRecapReset(3000).catch(() => {});
1350
- }
1351
-
1352
- // Surface the session-entry working directory so the Lead knows where
1353
- // relative paths resolve before any `cwd set`. Reads the user-cwd.txt seed
1354
- // written just above (mirrors the host's _event.cwd). Best-effort — never
1355
- // let it break rule injection.
1356
- let _startDir = '';
1357
- try {
1358
- _startDir = fs.readFileSync(path.join(DATA_DIR, 'user-cwd.txt'), 'utf8').trim();
1359
- if (_startDir) {
1360
- const _startBlock = `## Starting directory\n${_startDir}`;
1361
- additionalContext = additionalContext ? `${additionalContext}\n\n${_startBlock}` : _startBlock;
1362
- }
1363
- } catch {}
1364
-
1365
- // Other owned directories — full paths (the cwd tool's background scan
1366
- // persists them to cwd-projects.json). Best-effort — never let it break
1367
- // rule injection. Dynamic, so it lives here not in static rules.
1368
- try {
1369
- const _projParsed = JSON.parse(fs.readFileSync(path.join(DATA_DIR, 'cwd-projects.json'), 'utf8'));
1370
- const _projects = Array.isArray(_projParsed && _projParsed.projects) ? _projParsed.projects : [];
1371
- const _paths = _projects
1372
- .map((p) => String(p.path || '').trim())
1373
- .filter((p) => p && p !== _startDir);
1374
- if (_paths.length) {
1375
- const _otherBlock = `## Other directories\n${_paths.map((p) => `- ${p}`).join('\n')}`;
1376
- additionalContext = additionalContext ? `${additionalContext}\n\n${_otherBlock}` : _otherBlock;
1377
- }
1378
- } catch {}
1379
-
1380
- emit(additionalContext);
1381
- teeStderr(`[session-start] runRulesPart done\n`);
1382
- }
1383
-
1384
- // ---------------------------------------------------------------------------
1385
- // Part: core (slot 2) — Core Memory only. Runs in its own process so each
1386
- // SessionStart additionalContext is sized independently against the host
1387
- // preview cap. Pairs with recap (slot 3); both are spawned in parallel by
1388
- // the host and share the cycle1 await on the server side.
1389
- // ---------------------------------------------------------------------------
1390
- async function runCorePart() {
1391
- if (_skipMemoryInject()) {
1392
- teeStderr(`[session-start] runCorePart skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=skipMemoryInject\n`);
1393
- return;
1394
- }
1395
- // graceMs=8000 covers supervisor cold-start ceiling. fs.watch unblocks
1396
- // immediately on active-instance.json creation, so normal boots pay only
1397
- // the actual startup time (no extra wait). Without this, first attempt
1398
- // timed out at 3000ms before supervisor finished spawning, forcing a
1399
- // transient-retry round-trip that added ~3s to wall-clock.
1400
- const r = await requestCycle1(SESSION_START_CYCLE1_TIMEOUT_MS, { graceMs: 8000, slot: 'core' });
1401
- if (r.ok !== true) {
1402
- if (r.reason === 'owner-route-unavailable') {
1403
- teeStderr('[session-start] core cycle1 skipped: owner route unavailable in this session\n');
1404
- } else {
1405
- teeStderr(`[session-start] core aborted: cycle1 await failed reason=${r.reason}\n`);
1406
- return;
1407
- }
1408
- }
1409
- // cycle1 ok guarantees channels owner liveness only; memory_port lands
1410
- // later via worker `ready` IPC. Wait so getMemoryServicePort below does
1411
- // not throw on fast /clear paths.
1412
- const memPort = await awaitMemoryPort(8000);
1413
- if (!memPort) {
1414
- teeStderr(`[session-start] core aborted: memory_port unavailable within graceMs\n`);
1415
- return;
1416
- }
1417
- const tStart = Date.now();
1418
- try {
1419
- const tCtxStart = Date.now();
1420
- const ctx = await buildContext(_event.cwd || process.cwd());
1421
- teeStderr(`[session-start] core stage=buildContext elapsed=${Date.now() - tCtxStart}ms hasCtx=${!!ctx}\n`);
1422
- if (ctx) {
1423
- const tEmitStart = Date.now();
1424
- emit(ctx);
1425
- teeStderr(`[session-start] core stage=emit elapsed=${Date.now() - tEmitStart}ms\n`);
1426
- }
1427
- } catch (e) {
1428
- process.stderr.write(`[session-start] core build failed: ${e.message}\n`);
1429
- }
1430
- teeStderr(`[session-start] core done totalElapsed=${Date.now() - tStart}ms\n`);
1431
- }
1432
-
1433
- // ---------------------------------------------------------------------------
1434
- // Part: recap (slot 3) — Recap entries only. Spawned in parallel with core.
1435
- // ---------------------------------------------------------------------------
1436
- async function runRecapPart() {
1437
- if (_skipMemoryInject()) {
1438
- teeStderr(`[session-start] runRecapPart skip PART=${PART} source=${_event.source || ''} cwd=${_event.cwd || process.cwd()} reason=skipMemoryInject\n`);
1439
- return;
1440
- }
1441
- // graceMs=8000: see runCorePart for invariant rationale.
1442
- const r = await requestCycle1(SESSION_START_CYCLE1_TIMEOUT_MS, { graceMs: 8000, slot: 'recap' });
1443
- if (r.ok !== true) {
1444
- if (r.reason === 'owner-route-unavailable') {
1445
- teeStderr('[session-start] recap cycle1 skipped: owner route unavailable in this session\n');
1446
- } else {
1447
- teeStderr(`[session-start] recap aborted: cycle1 await failed reason=${r.reason}\n`);
1448
- return;
1449
- }
1450
- }
1451
- // See runCorePart: cycle1 success does not imply memory_port readiness.
1452
- const memPort = await awaitMemoryPort(8000);
1453
- if (!memPort) {
1454
- teeStderr(`[session-start] recap aborted: memory_port unavailable within graceMs\n`);
1455
- return;
1456
- }
1457
- const tStart = Date.now();
1458
- try {
1459
- const tRecapStart = Date.now();
1460
- const recapData = await buildRecapData(_event.cwd || process.cwd());
1461
- const lines = (recapData && recapData.lines) || [];
1462
- teeStderr(`[session-start] recap stage=buildRecapData elapsed=${Date.now() - tRecapStart}ms lines=${lines.length}\n`);
1463
- if (lines.length > 0) {
1464
- const tEmitStart = Date.now();
1465
- emit(`## Recap\n${lines.join('\n')}`);
1466
- teeStderr(`[session-start] recap stage=emit elapsed=${Date.now() - tEmitStart}ms\n`);
1467
- }
1468
- } catch (e) {
1469
- process.stderr.write(`[session-start] recap build failed: ${e.message}\n`);
1470
- }
1471
- teeStderr(`[session-start] recap done totalElapsed=${Date.now() - tStart}ms\n`);
1472
- }
1473
-
1474
- // ---------------------------------------------------------------------------
1475
- // Exports for in-process daemon use (mixdog-shim → hook-pipe-server.mjs).
1476
- // ---------------------------------------------------------------------------
1477
- module.exports = { runRulesPart, runCorePart, runRecapPart, setEvent, setEmitSink, setPart };
1478
-
1479
- // ---------------------------------------------------------------------------
1480
- // Main IIFE — dispatch on PART. Only runs when invoked as the entry script;
1481
- // require'd from the daemon stays a no-op (PART is undefined).
1482
- // ---------------------------------------------------------------------------
1483
- if (require.main === module) {
1484
- (async () => {
1485
- if (PART === 'rules') {
1486
- await runRulesPart();
1487
- } else if (PART === 'core') {
1488
- await runCorePart();
1489
- } else if (PART === 'recap') {
1490
- await runRecapPart();
1491
- }
1492
- })();
1493
- }