mixdog 0.7.18 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (844) 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/smoke-loop-report.mjs +221 -0
  10. package/scripts/smoke-loop.mjs +201 -0
  11. package/scripts/smoke.mjs +113 -0
  12. package/scripts/tool-failures.mjs +143 -0
  13. package/scripts/tool-smoke.mjs +456 -0
  14. package/src/agents/debugger/AGENT.md +3 -0
  15. package/src/agents/debugger/agent.json +6 -0
  16. package/src/agents/explore/AGENT.md +4 -0
  17. package/src/agents/explore/agent.json +6 -0
  18. package/src/agents/heavy-worker/AGENT.md +3 -0
  19. package/src/agents/heavy-worker/agent.json +6 -0
  20. package/src/agents/maintainer/AGENT.md +3 -0
  21. package/src/agents/maintainer/agent.json +6 -0
  22. package/src/agents/reviewer/AGENT.md +3 -0
  23. package/src/agents/reviewer/agent.json +6 -0
  24. package/src/agents/scheduler-task.md +3 -0
  25. package/src/agents/web-researcher/AGENT.md +3 -0
  26. package/src/agents/web-researcher/agent.json +6 -0
  27. package/src/agents/webhook-handler.md +3 -0
  28. package/src/agents/worker/AGENT.md +3 -0
  29. package/src/agents/worker/agent.json +6 -0
  30. package/src/app.mjs +90 -0
  31. package/src/cli.mjs +11 -0
  32. package/src/defaults/hidden-roles.json +72 -0
  33. package/src/defaults/mixdog-config.template.json +15 -0
  34. package/src/hooks/lib/permission-evaluator.cjs +488 -0
  35. package/src/hooks/lib/settings-loader.cjs +112 -0
  36. package/src/lib/keychain-cjs.cjs +332 -0
  37. package/src/lib/plugin-paths.cjs +28 -0
  38. package/src/lib/rules-builder.cjs +315 -0
  39. package/src/mixdog-session-runtime.mjs +3704 -0
  40. package/src/output-styles/default.md +38 -0
  41. package/src/output-styles/extreme-simple.md +17 -0
  42. package/src/output-styles/simple.md +17 -0
  43. package/src/repl.mjs +322 -0
  44. package/src/rules/bridge/00-common.md +5 -0
  45. package/src/rules/bridge/20-skip-protocol.md +11 -0
  46. package/src/rules/bridge/30-explorer.md +4 -0
  47. package/src/rules/bridge/40-cycle1-agent.md +28 -0
  48. package/src/rules/bridge/41-cycle2-agent.md +59 -0
  49. package/src/rules/lead/00-tool-lead.md +5 -0
  50. package/src/rules/lead/01-general.md +5 -0
  51. package/src/rules/lead/02-channels.md +3 -0
  52. package/src/rules/lead/04-workflow.md +12 -0
  53. package/src/rules/shared/00-language.md +3 -0
  54. package/src/rules/shared/01-tool.md +3 -0
  55. package/src/runtime/agent/orchestrator/bridge-trace.mjs +814 -0
  56. package/src/runtime/agent/orchestrator/cache-mtime.mjs +60 -0
  57. package/src/runtime/agent/orchestrator/config.mjs +446 -0
  58. package/src/runtime/agent/orchestrator/context/collect.mjs +796 -0
  59. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +417 -0
  60. package/src/runtime/agent/orchestrator/internal-roles.mjs +188 -0
  61. package/src/runtime/agent/orchestrator/internal-tools.mjs +88 -0
  62. package/src/runtime/agent/orchestrator/mcp/client.mjs +345 -0
  63. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2104 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +784 -0
  65. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +341 -0
  66. package/src/runtime/agent/orchestrator/providers/gemini.mjs +1679 -0
  67. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +959 -0
  68. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +213 -0
  69. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +38 -0
  70. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +471 -0
  71. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +615 -0
  72. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +808 -0
  73. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +1719 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2587 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1953 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +136 -0
  77. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +317 -0
  78. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +109 -0
  79. package/src/runtime/agent/orchestrator/providers/registry.mjs +247 -0
  80. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +332 -0
  81. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +11 -0
  82. package/src/runtime/agent/orchestrator/providers/trace-utils.mjs +50 -0
  83. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  84. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +318 -0
  85. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +367 -0
  86. package/src/runtime/agent/orchestrator/session/compact.mjs +882 -0
  87. package/src/runtime/agent/orchestrator/session/context-utils.mjs +233 -0
  88. package/src/runtime/agent/orchestrator/session/loop.mjs +2320 -0
  89. package/src/runtime/agent/orchestrator/session/manager.mjs +2960 -0
  90. package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
  91. package/src/runtime/agent/orchestrator/session/store.mjs +663 -0
  92. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  93. package/src/runtime/agent/orchestrator/smart-bridge/bridge-llm.mjs +339 -0
  94. package/src/runtime/agent/orchestrator/smart-bridge/cache-strategy.mjs +419 -0
  95. package/src/runtime/agent/orchestrator/stall-policy.mjs +227 -0
  96. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +235 -0
  97. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +723 -0
  98. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +389 -0
  99. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +637 -0
  100. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +165 -0
  101. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +104 -0
  102. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +194 -0
  103. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +596 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +110 -0
  105. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +153 -0
  106. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  107. package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +189 -0
  108. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +731 -0
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +168 -0
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  111. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +465 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +160 -0
  113. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +982 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1087 -0
  115. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +231 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +223 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin.mjs +478 -0
  118. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  119. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4102 -0
  120. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  121. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +154 -0
  122. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +26 -0
  123. package/src/runtime/agent/orchestrator/tools/patch-binary-fetcher.mjs +143 -0
  124. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +18 -0
  125. package/src/runtime/agent/orchestrator/tools/patch.mjs +2772 -0
  126. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +114 -0
  127. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +880 -0
  128. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +312 -0
  129. package/src/runtime/channels/backends/discord.mjs +781 -0
  130. package/src/runtime/channels/data/voice-runtime-manifest.json +138 -0
  131. package/src/runtime/channels/index.mjs +3309 -0
  132. package/src/runtime/channels/lib/config.mjs +285 -0
  133. package/src/runtime/channels/lib/drop-trace.mjs +71 -0
  134. package/src/runtime/channels/lib/event-pipeline.mjs +81 -0
  135. package/src/runtime/channels/lib/holidays.mjs +138 -0
  136. package/src/runtime/channels/lib/hook-pipe-server.mjs +671 -0
  137. package/src/runtime/channels/lib/output-forwarder.mjs +765 -0
  138. package/src/runtime/channels/lib/runtime-paths.mjs +497 -0
  139. package/src/runtime/channels/lib/scheduler.mjs +710 -0
  140. package/src/runtime/channels/lib/session-discovery.mjs +102 -0
  141. package/src/runtime/channels/lib/state-file.mjs +68 -0
  142. package/src/runtime/channels/lib/status-snapshot.mjs +224 -0
  143. package/src/runtime/channels/lib/tool-format.mjs +124 -0
  144. package/src/runtime/channels/lib/transcript-discovery.mjs +195 -0
  145. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +734 -0
  146. package/src/runtime/channels/lib/webhook.mjs +1288 -0
  147. package/src/runtime/channels/tool-defs.mjs +177 -0
  148. package/src/runtime/lib/keychain-cjs.cjs +289 -0
  149. package/src/runtime/memory/data/runtime-manifest.json +40 -0
  150. package/src/runtime/memory/index.mjs +3600 -0
  151. package/src/runtime/memory/lib/core-memory-store.mjs +336 -0
  152. package/src/runtime/memory/lib/embedding-provider.mjs +275 -0
  153. package/src/runtime/memory/lib/embedding-worker.mjs +331 -0
  154. package/src/runtime/memory/lib/memory-cycle-requests.mjs +276 -0
  155. package/src/runtime/memory/lib/memory-cycle1.mjs +783 -0
  156. package/src/runtime/memory/lib/memory-cycle2.mjs +1389 -0
  157. package/src/runtime/memory/lib/memory-cycle3.mjs +646 -0
  158. package/src/runtime/memory/lib/memory-embed.mjs +300 -0
  159. package/src/runtime/memory/lib/memory-ops-policy.mjs +149 -0
  160. package/src/runtime/memory/lib/memory-recall-store.mjs +644 -0
  161. package/src/runtime/memory/lib/memory.mjs +418 -0
  162. package/src/runtime/memory/lib/pg/adapter.mjs +314 -0
  163. package/src/runtime/memory/lib/pg/process.mjs +366 -0
  164. package/src/runtime/memory/lib/pg/supervisor.mjs +495 -0
  165. package/src/runtime/memory/lib/runtime-fetcher.mjs +464 -0
  166. package/src/runtime/memory/lib/trace-store.mjs +734 -0
  167. package/src/runtime/memory/tool-defs.mjs +79 -0
  168. package/src/runtime/search/index.mjs +925 -0
  169. package/src/runtime/search/lib/config.mjs +61 -0
  170. package/src/runtime/search/lib/web-tools.mjs +1278 -0
  171. package/src/runtime/search/tool-defs.mjs +64 -0
  172. package/src/runtime/shared/atomic-file.mjs +435 -0
  173. package/src/runtime/shared/background-tasks.mjs +376 -0
  174. package/src/runtime/shared/child-guardian.mjs +98 -0
  175. package/src/runtime/shared/config.mjs +393 -0
  176. package/src/runtime/shared/err-text.mjs +121 -0
  177. package/src/runtime/shared/launcher-control.mjs +259 -0
  178. package/src/runtime/shared/llm/http-agent.mjs +129 -0
  179. package/src/runtime/shared/open-url.mjs +37 -0
  180. package/src/runtime/shared/plugin-paths.mjs +25 -0
  181. package/src/runtime/shared/process-shutdown.mjs +147 -0
  182. package/src/runtime/shared/schedules-store.mjs +70 -0
  183. package/src/runtime/shared/tool-execution-contract.mjs +104 -0
  184. package/src/runtime/shared/tool-surface.mjs +950 -0
  185. package/src/runtime/shared/user-cwd.mjs +221 -0
  186. package/src/runtime/shared/user-data-guard.mjs +232 -0
  187. package/src/runtime/shared/workspace-router.mjs +259 -0
  188. package/src/standalone/bridge-tool.mjs +1414 -0
  189. package/src/standalone/channel-admin.mjs +366 -0
  190. package/src/standalone/channel-worker-preload.cjs +3 -0
  191. package/src/standalone/channel-worker.mjs +353 -0
  192. package/src/standalone/explore-tool.mjs +233 -0
  193. package/src/standalone/hook-bus.mjs +246 -0
  194. package/src/standalone/plugin-admin.mjs +247 -0
  195. package/src/standalone/provider-admin.mjs +338 -0
  196. package/src/standalone/seeds.mjs +94 -0
  197. package/src/standalone/usage-dashboard.mjs +510 -0
  198. package/src/tui/App.jsx +5438 -0
  199. package/src/tui/components/AnsiText.jsx +199 -0
  200. package/src/tui/components/ContextPanel.jsx +217 -0
  201. package/src/tui/components/Markdown.jsx +205 -0
  202. package/src/tui/components/MarkdownTable.jsx +204 -0
  203. package/src/tui/components/Message.jsx +103 -0
  204. package/src/tui/components/Picker.jsx +317 -0
  205. package/src/tui/components/PromptInput.jsx +584 -0
  206. package/src/tui/components/QueuedCommands.jsx +47 -0
  207. package/src/tui/components/SlashCommandPalette.jsx +114 -0
  208. package/src/tui/components/Spinner.jsx +317 -0
  209. package/src/tui/components/StatusLine.jsx +87 -0
  210. package/src/tui/components/TextEntryPanel.jsx +323 -0
  211. package/src/tui/components/ToolExecution.jsx +772 -0
  212. package/src/tui/components/TurnDone.jsx +78 -0
  213. package/src/tui/components/UsagePanel.jsx +331 -0
  214. package/src/tui/dist/index.mjs +12359 -0
  215. package/src/tui/engine.mjs +2410 -0
  216. package/src/tui/figures.mjs +50 -0
  217. package/src/tui/hooks/useEngine.mjs +16 -0
  218. package/src/tui/index.jsx +254 -0
  219. package/src/tui/input-editing.mjs +242 -0
  220. package/src/tui/markdown/format-token.mjs +194 -0
  221. package/src/tui/paste-attachments.mjs +198 -0
  222. package/src/tui/runtime/shared/process-shutdown.mjs +1 -0
  223. package/src/tui/spinner-verbs.mjs +45 -0
  224. package/src/tui/theme.mjs +67 -0
  225. package/src/tui/time-format.mjs +53 -0
  226. package/src/ui/ansi.mjs +115 -0
  227. package/src/ui/markdown.mjs +195 -0
  228. package/src/ui/statusline.mjs +730 -0
  229. package/src/ui/tool-card.mjs +101 -0
  230. package/src/vendor/statusline/bin/statusline-lib.mjs +805 -0
  231. package/src/vendor/statusline/bin/statusline-route.mjs +596 -0
  232. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +285 -0
  233. package/src/vendor/statusline/src/gateway/claude-current.mjs +320 -0
  234. package/src/vendor/statusline/src/gateway/route-meta.mjs +753 -0
  235. package/src/vendor/statusline/src/gateway/session-routes.mjs +244 -0
  236. package/src/workflows/default/WORKFLOW.md +7 -0
  237. package/src/workflows/default/workflow.json +14 -0
  238. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  239. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  240. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  241. package/vendor/ink/build/colorize.d.ts +3 -0
  242. package/vendor/ink/build/colorize.js +48 -0
  243. package/vendor/ink/build/colorize.js.map +1 -0
  244. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  245. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  246. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  247. package/vendor/ink/build/components/AnimationContext.d.ts +9 -0
  248. package/vendor/ink/build/components/AnimationContext.js +13 -0
  249. package/vendor/ink/build/components/AnimationContext.js.map +1 -0
  250. package/vendor/ink/build/components/App.d.ts +24 -0
  251. package/vendor/ink/build/components/App.js +554 -0
  252. package/vendor/ink/build/components/App.js.map +1 -0
  253. package/vendor/ink/build/components/AppContext.d.ts +80 -0
  254. package/vendor/ink/build/components/AppContext.js +25 -0
  255. package/vendor/ink/build/components/AppContext.js.map +1 -0
  256. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  257. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  258. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  259. package/vendor/ink/build/components/Box.d.ts +130 -0
  260. package/vendor/ink/build/components/Box.js +34 -0
  261. package/vendor/ink/build/components/Box.js.map +1 -0
  262. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  263. package/vendor/ink/build/components/CursorContext.js +8 -0
  264. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  265. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  266. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  267. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  268. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  269. package/vendor/ink/build/components/ErrorOverview.js +90 -0
  270. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  271. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  272. package/vendor/ink/build/components/FocusContext.js +17 -0
  273. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  274. package/vendor/ink/build/components/Newline.d.ts +13 -0
  275. package/vendor/ink/build/components/Newline.js +8 -0
  276. package/vendor/ink/build/components/Newline.js.map +1 -0
  277. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  278. package/vendor/ink/build/components/Spacer.js +11 -0
  279. package/vendor/ink/build/components/Spacer.js.map +1 -0
  280. package/vendor/ink/build/components/Static.d.ts +24 -0
  281. package/vendor/ink/build/components/Static.js +28 -0
  282. package/vendor/ink/build/components/Static.js.map +1 -0
  283. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  284. package/vendor/ink/build/components/StderrContext.js +13 -0
  285. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  286. package/vendor/ink/build/components/StdinContext.d.ts +28 -0
  287. package/vendor/ink/build/components/StdinContext.js +20 -0
  288. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  289. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  290. package/vendor/ink/build/components/StdoutContext.js +13 -0
  291. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  292. package/vendor/ink/build/components/Text.d.ts +55 -0
  293. package/vendor/ink/build/components/Text.js +50 -0
  294. package/vendor/ink/build/components/Text.js.map +1 -0
  295. package/vendor/ink/build/components/Transform.d.ts +16 -0
  296. package/vendor/ink/build/components/Transform.js +15 -0
  297. package/vendor/ink/build/components/Transform.js.map +1 -0
  298. package/vendor/ink/build/cursor-helpers.d.ts +39 -0
  299. package/vendor/ink/build/cursor-helpers.js +62 -0
  300. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  301. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  302. package/vendor/ink/build/devtools-window-polyfill.js +68 -0
  303. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  304. package/vendor/ink/build/devtools.d.ts +1 -0
  305. package/vendor/ink/build/devtools.js +36 -0
  306. package/vendor/ink/build/devtools.js.map +1 -0
  307. package/vendor/ink/build/dom.d.ts +62 -0
  308. package/vendor/ink/build/dom.js +143 -0
  309. package/vendor/ink/build/dom.js.map +1 -0
  310. package/vendor/ink/build/get-max-width.d.ts +3 -0
  311. package/vendor/ink/build/get-max-width.js +10 -0
  312. package/vendor/ink/build/get-max-width.js.map +1 -0
  313. package/vendor/ink/build/hooks/use-animation.d.ts +49 -0
  314. package/vendor/ink/build/hooks/use-animation.js +87 -0
  315. package/vendor/ink/build/hooks/use-animation.js.map +1 -0
  316. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  317. package/vendor/ink/build/hooks/use-app.js +8 -0
  318. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  319. package/vendor/ink/build/hooks/use-box-metrics.d.ts +59 -0
  320. package/vendor/ink/build/hooks/use-box-metrics.js +81 -0
  321. package/vendor/ink/build/hooks/use-box-metrics.js.map +1 -0
  322. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  323. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  324. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  325. package/vendor/ink/build/hooks/use-focus-manager.d.ts +43 -0
  326. package/vendor/ink/build/hooks/use-focus-manager.js +18 -0
  327. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  328. package/vendor/ink/build/hooks/use-focus.d.ts +30 -0
  329. package/vendor/ink/build/hooks/use-focus.js +43 -0
  330. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  331. package/vendor/ink/build/hooks/use-input.d.ts +132 -0
  332. package/vendor/ink/build/hooks/use-input.js +126 -0
  333. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  334. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +6 -0
  335. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +12 -0
  336. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  337. package/vendor/ink/build/hooks/use-paste.d.ts +35 -0
  338. package/vendor/ink/build/hooks/use-paste.js +62 -0
  339. package/vendor/ink/build/hooks/use-paste.js.map +1 -0
  340. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  341. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  342. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  343. package/vendor/ink/build/hooks/use-stdin.d.ts +7 -0
  344. package/vendor/ink/build/hooks/use-stdin.js +9 -0
  345. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  346. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  347. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  348. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  349. package/vendor/ink/build/hooks/use-window-size.d.ts +18 -0
  350. package/vendor/ink/build/hooks/use-window-size.js +22 -0
  351. package/vendor/ink/build/hooks/use-window-size.js.map +1 -0
  352. package/vendor/ink/build/index.d.ts +42 -0
  353. package/vendor/ink/build/index.js +24 -0
  354. package/vendor/ink/build/index.js.map +1 -0
  355. package/vendor/ink/build/ink.d.ts +146 -0
  356. package/vendor/ink/build/ink.js +1022 -0
  357. package/vendor/ink/build/ink.js.map +1 -0
  358. package/vendor/ink/build/input-parser.d.ts +10 -0
  359. package/vendor/ink/build/input-parser.js +194 -0
  360. package/vendor/ink/build/input-parser.js.map +1 -0
  361. package/vendor/ink/build/instances.d.ts +3 -0
  362. package/vendor/ink/build/instances.js +8 -0
  363. package/vendor/ink/build/instances.js.map +1 -0
  364. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  365. package/vendor/ink/build/kitty-keyboard.js +32 -0
  366. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  367. package/vendor/ink/build/log-update.d.ts +20 -0
  368. package/vendor/ink/build/log-update.js +261 -0
  369. package/vendor/ink/build/log-update.js.map +1 -0
  370. package/vendor/ink/build/measure-element.d.ts +20 -0
  371. package/vendor/ink/build/measure-element.js +13 -0
  372. package/vendor/ink/build/measure-element.js.map +1 -0
  373. package/vendor/ink/build/measure-text.d.ts +6 -0
  374. package/vendor/ink/build/measure-text.js +21 -0
  375. package/vendor/ink/build/measure-text.js.map +1 -0
  376. package/vendor/ink/build/output.d.ts +35 -0
  377. package/vendor/ink/build/output.js +328 -0
  378. package/vendor/ink/build/output.js.map +1 -0
  379. package/vendor/ink/build/parse-keypress.d.ts +20 -0
  380. package/vendor/ink/build/parse-keypress.js +495 -0
  381. package/vendor/ink/build/parse-keypress.js.map +1 -0
  382. package/vendor/ink/build/reconciler.d.ts +4 -0
  383. package/vendor/ink/build/reconciler.js +306 -0
  384. package/vendor/ink/build/reconciler.js.map +1 -0
  385. package/vendor/ink/build/render-background.d.ts +4 -0
  386. package/vendor/ink/build/render-background.js +25 -0
  387. package/vendor/ink/build/render-background.js.map +1 -0
  388. package/vendor/ink/build/render-border.d.ts +4 -0
  389. package/vendor/ink/build/render-border.js +84 -0
  390. package/vendor/ink/build/render-border.js.map +1 -0
  391. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  392. package/vendor/ink/build/render-node-to-output.js +162 -0
  393. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  394. package/vendor/ink/build/render-to-string.d.ts +38 -0
  395. package/vendor/ink/build/render-to-string.js +116 -0
  396. package/vendor/ink/build/render-to-string.js.map +1 -0
  397. package/vendor/ink/build/render.d.ts +176 -0
  398. package/vendor/ink/build/render.js +71 -0
  399. package/vendor/ink/build/render.js.map +1 -0
  400. package/vendor/ink/build/renderer.d.ts +8 -0
  401. package/vendor/ink/build/renderer.js +64 -0
  402. package/vendor/ink/build/renderer.js.map +1 -0
  403. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  404. package/vendor/ink/build/sanitize-ansi.js +27 -0
  405. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  406. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  407. package/vendor/ink/build/squash-text-nodes.js +36 -0
  408. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  409. package/vendor/ink/build/styles.d.ts +302 -0
  410. package/vendor/ink/build/styles.js +303 -0
  411. package/vendor/ink/build/styles.js.map +1 -0
  412. package/vendor/ink/build/utils.d.ts +9 -0
  413. package/vendor/ink/build/utils.js +19 -0
  414. package/vendor/ink/build/utils.js.map +1 -0
  415. package/vendor/ink/build/wrap-text.d.ts +3 -0
  416. package/vendor/ink/build/wrap-text.js +38 -0
  417. package/vendor/ink/build/wrap-text.js.map +1 -0
  418. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  419. package/vendor/ink/build/write-synchronized.js +9 -0
  420. package/vendor/ink/build/write-synchronized.js.map +1 -0
  421. package/vendor/ink/license +10 -0
  422. package/vendor/ink/package.json +137 -0
  423. package/.claude-plugin/marketplace.json +0 -34
  424. package/.claude-plugin/plugin.json +0 -20
  425. package/.gitattributes +0 -34
  426. package/.mcp.json +0 -14
  427. package/ARCHITECTURE.md +0 -77
  428. package/CHANGELOG.md +0 -30
  429. package/CONTRIBUTING.md +0 -45
  430. package/DATA-FLOW.md +0 -79
  431. package/LICENSE +0 -21
  432. package/SECURITY.md +0 -138
  433. package/UNINSTALL.md +0 -115
  434. package/agents/maintenance.md +0 -5
  435. package/agents/memory-classification.md +0 -30
  436. package/agents/scheduler-task.md +0 -18
  437. package/agents/webhook-handler.md +0 -27
  438. package/agents/worker.md +0 -24
  439. package/bin/bridge +0 -133
  440. package/bin/statusline-launcher.mjs +0 -82
  441. package/bin/statusline-lib.mjs +0 -581
  442. package/bin/statusline-route.mjs +0 -273
  443. package/bin/statusline.mjs +0 -638
  444. package/bun.lock +0 -927
  445. package/commands/config.md +0 -16
  446. package/commands/doctor.md +0 -13
  447. package/commands/model.md +0 -61
  448. package/commands/setup.md +0 -17
  449. package/defaults/hidden-roles.json +0 -68
  450. package/defaults/memory-chunk-prompt.md +0 -63
  451. package/defaults/mixdog-config.template.json +0 -27
  452. package/defaults/user-workflow.json +0 -8
  453. package/defaults/user-workflow.md +0 -17
  454. package/hooks/hooks.json +0 -73
  455. package/hooks/lib/active-instance.cjs +0 -77
  456. package/hooks/lib/permission-evaluator.cjs +0 -411
  457. package/hooks/lib/permission-route.cjs +0 -63
  458. package/hooks/lib/settings-loader.cjs +0 -117
  459. package/hooks/post-tool-use.cjs +0 -84
  460. package/hooks/pre-mcp-sandbox.cjs +0 -158
  461. package/hooks/pre-tool-subagent.cjs +0 -258
  462. package/hooks/session-start.cjs +0 -1493
  463. package/hooks/shim-launcher.cjs +0 -65
  464. package/hooks/turn-timer.cjs +0 -82
  465. package/lib/claude-md-writer.cjs +0 -386
  466. package/lib/keychain-cjs.cjs +0 -290
  467. package/lib/plugin-paths.cjs +0 -69
  468. package/lib/rules-builder.cjs +0 -241
  469. package/native/README.md +0 -117
  470. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  471. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  472. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  473. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  474. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  475. package/prompts/code-review.txt +0 -16
  476. package/prompts/security-audit.txt +0 -17
  477. package/rules/bridge/00-common.md +0 -39
  478. package/rules/bridge/20-skip-protocol.md +0 -18
  479. package/rules/bridge/30-explorer.md +0 -33
  480. package/rules/bridge/40-cycle1-agent.md +0 -52
  481. package/rules/bridge/41-cycle2-agent.md +0 -62
  482. package/rules/lead/00-tool-lead.md +0 -61
  483. package/rules/lead/01-general.md +0 -26
  484. package/rules/lead/02-channels.md +0 -49
  485. package/rules/lead/03-team.md +0 -27
  486. package/rules/lead/04-workflow.md +0 -20
  487. package/rules/shared/00-language.md +0 -14
  488. package/rules/shared/01-tool.md +0 -138
  489. package/scripts/bootstrap.mjs +0 -130
  490. package/scripts/bridge-unify-smoke.mjs +0 -308
  491. package/scripts/build-runtime-linux.sh +0 -348
  492. package/scripts/build-runtime-macos.sh +0 -217
  493. package/scripts/build-runtime-windows.ps1 +0 -242
  494. package/scripts/builtin-utils-smoke.mjs +0 -398
  495. package/scripts/bump.mjs +0 -80
  496. package/scripts/check-json.mjs +0 -45
  497. package/scripts/check-syntax-changed.mjs +0 -102
  498. package/scripts/check-syntax.mjs +0 -58
  499. package/scripts/code-graph-batch.test.mjs +0 -33
  500. package/scripts/config-preserve-smoke.mjs +0 -180
  501. package/scripts/doctor.mjs +0 -489
  502. package/scripts/edit-normalize-fuzz.mjs +0 -130
  503. package/scripts/edit-normalize-smoke.mjs +0 -401
  504. package/scripts/edit-operation-smoke.mjs +0 -369
  505. package/scripts/edit2-smoke.mjs +0 -63
  506. package/scripts/ensure-deps.mjs +0 -259
  507. package/scripts/fuzzy-e2e.mjs +0 -28
  508. package/scripts/fuzzy-smoke.mjs +0 -26
  509. package/scripts/gateway-model.mjs +0 -596
  510. package/scripts/generate-runtime-manifest.mjs +0 -166
  511. package/scripts/guard-smoke.mjs +0 -66
  512. package/scripts/hidden-role-schema-smoke.mjs +0 -162
  513. package/scripts/hook-routing-smoke.mjs +0 -29
  514. package/scripts/inject-input.ps1 +0 -204
  515. package/scripts/io-complex-smoke.mjs +0 -667
  516. package/scripts/io-explore-bench.mjs +0 -424
  517. package/scripts/io-guardrails-smoke.mjs +0 -205
  518. package/scripts/io-mini-bench-baseline.json +0 -11
  519. package/scripts/io-mini-bench.mjs +0 -216
  520. package/scripts/io-route-harness.mjs +0 -933
  521. package/scripts/io-telemetry-report.mjs +0 -691
  522. package/scripts/lib/gateway-inventory.mjs +0 -178
  523. package/scripts/lib/gateway-settings.mjs +0 -78
  524. package/scripts/mutation-bench.mjs +0 -564
  525. package/scripts/mutation-io-smoke.mjs +0 -1097
  526. package/scripts/native-patch-bridge-smoke.mjs +0 -288
  527. package/scripts/native-patch-smoke.mjs +0 -304
  528. package/scripts/openai-oauth-catalog-smoke.mjs +0 -53
  529. package/scripts/patch-interior-context-smoke.mjs +0 -49
  530. package/scripts/patch-newline-utf8-smoke.mjs +0 -157
  531. package/scripts/perf-hook-smoke.mjs +0 -71
  532. package/scripts/permission-eval-smoke.mjs +0 -443
  533. package/scripts/prep-patch.mjs +0 -53
  534. package/scripts/prep-shim.mjs +0 -96
  535. package/scripts/provider-cache-smoke.mjs +0 -687
  536. package/scripts/report-runtime-health.mjs +0 -132
  537. package/scripts/resolve-bun.mjs +0 -60
  538. package/scripts/run-mcp.mjs +0 -1473
  539. package/scripts/salvage-v4a-shatter.test.mjs +0 -58
  540. package/scripts/scoped-cache-io-smoke.mjs +0 -103
  541. package/scripts/shell-policy-round3-smoke.mjs +0 -46
  542. package/scripts/smoke-runtime-negative.ps1 +0 -100
  543. package/scripts/smoke-runtime-negative.sh +0 -95
  544. package/scripts/stall-policy-smoke.mjs +0 -50
  545. package/scripts/start-memory-worker.mjs +0 -23
  546. package/scripts/statusline-launcher-smoke.mjs +0 -235
  547. package/scripts/stress-atomic-write.mjs +0 -1028
  548. package/scripts/test-fault-inject.mjs +0 -164
  549. package/scripts/test-large-file.mjs +0 -174
  550. package/scripts/tool-edge-smoke.mjs +0 -209
  551. package/scripts/uninstall.mjs +0 -238
  552. package/scripts/webhook-selfheal-smoke.mjs +0 -27
  553. package/scripts/write-overwrite-guard-smoke.mjs +0 -56
  554. package/server-main.mjs +0 -3350
  555. package/server.mjs +0 -468
  556. package/setup/config-merge.mjs +0 -246
  557. package/setup/install.mjs +0 -574
  558. package/setup/launch-core.mjs +0 -617
  559. package/setup/launch.mjs +0 -101
  560. package/setup/locate-claude.mjs +0 -56
  561. package/setup/mixdog-cli.mjs +0 -122
  562. package/setup/setup-server.mjs +0 -3305
  563. package/setup/setup.html +0 -3740
  564. package/setup/tui.mjs +0 -325
  565. package/skills/retro-skill-proposer/SKILL.md +0 -92
  566. package/skills/schedule-add/SKILL.md +0 -77
  567. package/skills/setup/SKILL.md +0 -356
  568. package/skills/webhook-add/SKILL.md +0 -81
  569. package/src/agent/bridge-stall-watchdog.mjs +0 -337
  570. package/src/agent/index.mjs +0 -2229
  571. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +0 -1010
  572. package/src/agent/orchestrator/bridge-retry.mjs +0 -220
  573. package/src/agent/orchestrator/bridge-trace.mjs +0 -601
  574. package/src/agent/orchestrator/cache-mtime.mjs +0 -58
  575. package/src/agent/orchestrator/config.mjs +0 -405
  576. package/src/agent/orchestrator/context/collect.mjs +0 -651
  577. package/src/agent/orchestrator/dispatch-persist.mjs +0 -549
  578. package/src/agent/orchestrator/drain-registry.mjs +0 -50
  579. package/src/agent/orchestrator/explore-validator.mjs +0 -8
  580. package/src/agent/orchestrator/internal-roles.mjs +0 -118
  581. package/src/agent/orchestrator/internal-tools.mjs +0 -88
  582. package/src/agent/orchestrator/jobs.mjs +0 -116
  583. package/src/agent/orchestrator/mcp/client.mjs +0 -364
  584. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +0 -1884
  585. package/src/agent/orchestrator/providers/anthropic.mjs +0 -598
  586. package/src/agent/orchestrator/providers/gemini.mjs +0 -1530
  587. package/src/agent/orchestrator/providers/grok-oauth.mjs +0 -779
  588. package/src/agent/orchestrator/providers/model-catalog.mjs +0 -374
  589. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +0 -366
  590. package/src/agent/orchestrator/providers/openai-compat.mjs +0 -1511
  591. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -1891
  592. package/src/agent/orchestrator/providers/openai-oauth.mjs +0 -1456
  593. package/src/agent/orchestrator/providers/openai-ws.mjs +0 -127
  594. package/src/agent/orchestrator/providers/registry.mjs +0 -192
  595. package/src/agent/orchestrator/providers/retry-classifier.mjs +0 -325
  596. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +0 -142
  597. package/src/agent/orchestrator/session/cache/read-cache.mjs +0 -319
  598. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +0 -361
  599. package/src/agent/orchestrator/session/loop.mjs +0 -1619
  600. package/src/agent/orchestrator/session/manager.mjs +0 -1991
  601. package/src/agent/orchestrator/session/result-classification.mjs +0 -65
  602. package/src/agent/orchestrator/session/store.mjs +0 -632
  603. package/src/agent/orchestrator/session/stream-watchdog.mjs +0 -130
  604. package/src/agent/orchestrator/session/tool-result-offload.mjs +0 -166
  605. package/src/agent/orchestrator/session/trim.mjs +0 -491
  606. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +0 -115
  607. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +0 -331
  608. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +0 -150
  609. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +0 -228
  610. package/src/agent/orchestrator/smart-bridge/index.mjs +0 -215
  611. package/src/agent/orchestrator/smart-bridge/profiles.mjs +0 -37
  612. package/src/agent/orchestrator/smart-bridge/registry.mjs +0 -348
  613. package/src/agent/orchestrator/stall-policy.mjs +0 -201
  614. package/src/agent/orchestrator/tool-loop-guard.mjs +0 -75
  615. package/src/agent/orchestrator/tools/bash-session.mjs +0 -722
  616. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -511
  617. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -480
  618. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -256
  619. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +0 -58
  620. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +0 -240
  621. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +0 -113
  622. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +0 -74
  623. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +0 -242
  624. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +0 -211
  625. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +0 -1364
  626. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +0 -126
  627. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +0 -141
  628. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +0 -194
  629. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +0 -60
  630. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +0 -168
  631. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +0 -173
  632. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +0 -48
  633. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -99
  634. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +0 -193
  635. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +0 -597
  636. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  637. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +0 -300
  638. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +0 -152
  639. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +0 -118
  640. package/src/agent/orchestrator/tools/builtin/read-open.mjs +0 -190
  641. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +0 -728
  642. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +0 -173
  643. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +0 -602
  644. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +0 -196
  645. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +0 -422
  646. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +0 -158
  647. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +0 -869
  648. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +0 -962
  649. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +0 -223
  650. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +0 -206
  651. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +0 -401
  652. package/src/agent/orchestrator/tools/builtin.mjs +0 -503
  653. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +0 -24
  654. package/src/agent/orchestrator/tools/code-graph.mjs +0 -4095
  655. package/src/agent/orchestrator/tools/cwd-tool.mjs +0 -298
  656. package/src/agent/orchestrator/tools/destructive-warning.mjs +0 -323
  657. package/src/agent/orchestrator/tools/edit-normalize.mjs +0 -603
  658. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +0 -154
  659. package/src/agent/orchestrator/tools/graph-manifest.json +0 -26
  660. package/src/agent/orchestrator/tools/host-input.mjs +0 -204
  661. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +0 -143
  662. package/src/agent/orchestrator/tools/patch-manifest.json +0 -26
  663. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +0 -20
  664. package/src/agent/orchestrator/tools/patch.mjs +0 -2754
  665. package/src/agent/orchestrator/tools/progress-message.mjs +0 -118
  666. package/src/agent/orchestrator/tools/shell-command.mjs +0 -865
  667. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +0 -7
  668. package/src/agent/orchestrator/tools/shell-snapshot.mjs +0 -313
  669. package/src/agent/orchestrator/workflow-store.mjs +0 -93
  670. package/src/agent/tool-defs.mjs +0 -110
  671. package/src/channels/backends/discord.mjs +0 -784
  672. package/src/channels/data/voice-runtime-manifest.json +0 -138
  673. package/src/channels/index.mjs +0 -3268
  674. package/src/channels/lib/config.mjs +0 -292
  675. package/src/channels/lib/drop-trace.mjs +0 -71
  676. package/src/channels/lib/event-pipeline.mjs +0 -81
  677. package/src/channels/lib/holidays.mjs +0 -138
  678. package/src/channels/lib/hook-pipe-server.mjs +0 -822
  679. package/src/channels/lib/output-forwarder.mjs +0 -765
  680. package/src/channels/lib/runtime-paths.mjs +0 -552
  681. package/src/channels/lib/scheduler.mjs +0 -723
  682. package/src/channels/lib/session-discovery.mjs +0 -103
  683. package/src/channels/lib/state-file.mjs +0 -68
  684. package/src/channels/lib/status-snapshot.mjs +0 -219
  685. package/src/channels/lib/tool-format.mjs +0 -140
  686. package/src/channels/lib/transcript-discovery.mjs +0 -195
  687. package/src/channels/lib/voice-runtime-fetcher.mjs +0 -734
  688. package/src/channels/lib/webhook.mjs +0 -1318
  689. package/src/channels/tool-defs.mjs +0 -170
  690. package/src/daemon/host.mjs +0 -118
  691. package/src/daemon/mcp-transport.mjs +0 -47
  692. package/src/daemon/session.mjs +0 -100
  693. package/src/daemon/thin-client.mjs +0 -71
  694. package/src/daemon/transport.mjs +0 -163
  695. package/src/gateway/claude-current.mjs +0 -255
  696. package/src/gateway/oauth-usage.mjs +0 -598
  697. package/src/gateway/route-meta.mjs +0 -629
  698. package/src/gateway/server.mjs +0 -713
  699. package/src/memory/data/runtime-manifest.json +0 -40
  700. package/src/memory/index.mjs +0 -3332
  701. package/src/memory/lib/core-memory-store.mjs +0 -330
  702. package/src/memory/lib/embedding-provider.mjs +0 -269
  703. package/src/memory/lib/embedding-worker.mjs +0 -323
  704. package/src/memory/lib/memory-cycle1.mjs +0 -645
  705. package/src/memory/lib/memory-cycle2.mjs +0 -1284
  706. package/src/memory/lib/memory-cycle3.mjs +0 -540
  707. package/src/memory/lib/memory-embed.mjs +0 -299
  708. package/src/memory/lib/memory-ops-policy.mjs +0 -190
  709. package/src/memory/lib/memory-recall-store.mjs +0 -638
  710. package/src/memory/lib/memory.mjs +0 -412
  711. package/src/memory/lib/pg/adapter.mjs +0 -308
  712. package/src/memory/lib/pg/process.mjs +0 -360
  713. package/src/memory/lib/pg/supervisor.mjs +0 -396
  714. package/src/memory/lib/runtime-fetcher.mjs +0 -458
  715. package/src/memory/lib/trace-store.mjs +0 -728
  716. package/src/memory/tool-defs.mjs +0 -79
  717. package/src/search/index.mjs +0 -1173
  718. package/src/search/lib/backends/anthropic-oauth.mjs +0 -98
  719. package/src/search/lib/backends/exa.mjs +0 -50
  720. package/src/search/lib/backends/firecrawl.mjs +0 -61
  721. package/src/search/lib/backends/gemini-api.mjs +0 -83
  722. package/src/search/lib/backends/grok-oauth.mjs +0 -86
  723. package/src/search/lib/backends/index.mjs +0 -150
  724. package/src/search/lib/backends/openai-api.mjs +0 -144
  725. package/src/search/lib/backends/openai-oauth.mjs +0 -102
  726. package/src/search/lib/backends/openai-web-search.mjs +0 -76
  727. package/src/search/lib/backends/tavily.mjs +0 -55
  728. package/src/search/lib/backends/xai-api.mjs +0 -113
  729. package/src/search/lib/config.mjs +0 -192
  730. package/src/search/lib/provider-usage.mjs +0 -67
  731. package/src/search/lib/providers.mjs +0 -47
  732. package/src/search/lib/search-intent.mjs +0 -109
  733. package/src/search/lib/setup-handler.mjs +0 -261
  734. package/src/search/lib/web-tools.mjs +0 -1219
  735. package/src/search/tool-defs.mjs +0 -83
  736. package/src/setup/defender-exclusion.mjs +0 -183
  737. package/src/shared/atomic-file.mjs +0 -436
  738. package/src/shared/config.mjs +0 -372
  739. package/src/shared/daemon-recycle.mjs +0 -108
  740. package/src/shared/disable-claude-builtins.mjs +0 -91
  741. package/src/shared/err-text.mjs +0 -12
  742. package/src/shared/llm/http-agent.mjs +0 -123
  743. package/src/shared/open-url.mjs +0 -62
  744. package/src/shared/plugin-paths.mjs +0 -58
  745. package/src/shared/schedules-store.mjs +0 -70
  746. package/src/shared/seed.mjs +0 -161
  747. package/src/shared/user-cwd.mjs +0 -225
  748. package/src/shared/user-data-guard.mjs +0 -244
  749. package/src/status/aggregator.mjs +0 -584
  750. package/src/status/server.mjs +0 -413
  751. package/tools.json +0 -1671
  752. /package/{defaults → src/defaults}/cycle3-review-prompt.md +0 -0
  753. /package/{defaults → src/defaults}/memory-promote-prompt.md +0 -0
  754. /package/{hooks → src/hooks}/lib/permission-rules.cjs +0 -0
  755. /package/{lib → src/lib}/config-cjs.cjs +0 -0
  756. /package/{lib → src/lib}/hook-pipe-path.cjs +0 -0
  757. /package/{lib → src/lib}/mixdog-debug.cjs +0 -0
  758. /package/{lib → src/lib}/text-utils.cjs +0 -0
  759. /package/{rules → src/rules}/bridge/42-cycle3-agent.md +0 -0
  760. /package/src/{agent → runtime/agent}/orchestrator/activity-bus.mjs +0 -0
  761. /package/src/{agent → runtime/agent}/orchestrator/providers/anthropic-betas.mjs +0 -0
  762. /package/src/{agent → runtime/agent}/orchestrator/session/abort-lookup.mjs +0 -0
  763. /package/src/{agent → runtime/agent}/orchestrator/session/cache/post-edit-marks.mjs +0 -0
  764. /package/src/{agent → runtime/agent}/orchestrator/session/cache/scoped-cache-outcome.mjs +0 -0
  765. /package/src/{agent → runtime/agent}/orchestrator/session/cache/util.mjs +0 -0
  766. /package/src/{agent → runtime/agent}/orchestrator/session/read-dedup.mjs +0 -0
  767. /package/src/{agent → runtime/agent}/orchestrator/session/save-session-worker.mjs +0 -0
  768. /package/src/{agent → runtime/agent}/orchestrator/smart-bridge/session-builder.mjs +0 -0
  769. /package/src/{agent → runtime/agent}/orchestrator/tools/bash-policy-scan.mjs +0 -0
  770. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/advisory-lock.mjs +0 -0
  771. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/atomic-write.mjs +0 -0
  772. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/binary-file.mjs +0 -0
  773. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cache-layers.mjs +0 -0
  774. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cwd-utils.mjs +0 -0
  775. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/device-paths.mjs +0 -0
  776. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -0
  777. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diff-utils.mjs +0 -0
  778. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/fs-reachability.mjs +0 -0
  779. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/grep-formatting.mjs +0 -0
  780. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/hash-utils.mjs +0 -0
  781. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/list-formatting.mjs +0 -0
  782. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/open-config-tool.mjs +0 -0
  783. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-locks.mjs +0 -0
  784. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-utils.mjs +0 -0
  785. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-args.mjs +0 -0
  786. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-batch.mjs +0 -0
  787. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-constants.mjs +0 -0
  788. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image-resize.mjs +0 -0
  789. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image.mjs +0 -0
  790. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-lines.mjs +0 -0
  791. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-mode-tool.mjs +0 -0
  792. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-range-index.mjs +0 -0
  793. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-ranges.mjs +0 -0
  794. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-special-files.mjs +0 -0
  795. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-tool.mjs +0 -0
  796. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-windows.mjs +0 -0
  797. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-analysis.mjs +0 -0
  798. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-output.mjs +0 -0
  799. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-helpers.mjs +0 -0
  800. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-validation.mjs +0 -0
  801. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/text-stats.mjs +0 -0
  802. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/windows-roots.mjs +0 -0
  803. /package/src/{agent → runtime/agent}/orchestrator/tools/code-graph-prewarm-worker.mjs +0 -0
  804. /package/src/{agent → runtime/agent}/orchestrator/tools/env-scrub.mjs +0 -0
  805. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-content-cache.mjs +0 -0
  806. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-planner.mjs +0 -0
  807. /package/src/{agent → runtime/agent}/orchestrator/tools/next-call-utils.mjs +0 -0
  808. /package/src/{agent → runtime/agent}/orchestrator/tools/result-compression.mjs +0 -0
  809. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-exec-policy.mjs +0 -0
  810. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy-danger-target.mjs +0 -0
  811. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy.mjs +0 -0
  812. /package/src/{channels → runtime/channels}/lib/cli-worker-host.mjs +0 -0
  813. /package/src/{channels → runtime/channels}/lib/config-lock.mjs +0 -0
  814. /package/src/{channels → runtime/channels}/lib/event-queue.mjs +0 -0
  815. /package/src/{channels → runtime/channels}/lib/executor.mjs +0 -0
  816. /package/src/{channels → runtime/channels}/lib/format.mjs +0 -0
  817. /package/src/{channels → runtime/channels}/lib/interaction-workflows.mjs +0 -0
  818. /package/src/{channels → runtime/channels}/lib/memory-client.mjs +0 -0
  819. /package/src/{channels → runtime/channels}/lib/session-control.mjs +0 -0
  820. /package/src/{channels → runtime/channels}/lib/settings.mjs +0 -0
  821. /package/src/{channels → runtime/channels}/lib/whisper-server.mjs +0 -0
  822. /package/src/{memory → runtime/memory}/lib/agent-ipc.mjs +0 -0
  823. /package/src/{memory → runtime/memory}/lib/bridge-trace-queries.mjs +0 -0
  824. /package/src/{memory → runtime/memory}/lib/llm-worker-host.mjs +0 -0
  825. /package/src/{memory → runtime/memory}/lib/memory-cycle.mjs +0 -0
  826. /package/src/{memory → runtime/memory}/lib/memory-extraction.mjs +0 -0
  827. /package/src/{memory → runtime/memory}/lib/memory-maintenance-store.mjs +0 -0
  828. /package/src/{memory → runtime/memory}/lib/memory-recall-id-patch.mjs +0 -0
  829. /package/src/{memory → runtime/memory}/lib/memory-recall-read-query.mjs +0 -0
  830. /package/src/{memory → runtime/memory}/lib/memory-recall-scope-filter.mjs +0 -0
  831. /package/src/{memory → runtime/memory}/lib/memory-retrievers.mjs +0 -0
  832. /package/src/{memory → runtime/memory}/lib/memory-score.mjs +0 -0
  833. /package/src/{memory → runtime/memory}/lib/memory-text-utils.mjs +0 -0
  834. /package/src/{memory → runtime/memory}/lib/model-profile.mjs +0 -0
  835. /package/src/{memory → runtime/memory}/lib/project-id-resolver.mjs +0 -0
  836. /package/src/{search → runtime/search}/lib/cache.mjs +0 -0
  837. /package/src/{search → runtime/search}/lib/formatter.mjs +0 -0
  838. /package/src/{search → runtime/search}/lib/state.mjs +0 -0
  839. /package/src/{shared → runtime/shared}/abort-controller.mjs +0 -0
  840. /package/src/{shared → runtime/shared}/llm/cost.mjs +0 -0
  841. /package/src/{shared → runtime/shared}/llm/index.mjs +0 -0
  842. /package/src/{shared → runtime/shared}/llm/pid-cleanup.mjs +0 -0
  843. /package/src/{shared → runtime/shared}/llm/usage-log.mjs +0 -0
  844. /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
- }