mixdog 0.7.18 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (847) hide show
  1. package/README.md +37 -331
  2. package/package.json +67 -99
  3. package/scripts/boot-smoke.mjs +94 -0
  4. package/scripts/build-tui.mjs +52 -0
  5. package/scripts/compact-smoke.mjs +199 -0
  6. package/scripts/lead-workflow-smoke.mjs +598 -0
  7. package/scripts/live-worker-smoke.mjs +239 -0
  8. package/scripts/output-style-smoke.mjs +101 -0
  9. package/scripts/session-context-bench.mjs +172 -0
  10. package/scripts/smoke-loop-report.mjs +221 -0
  11. package/scripts/smoke-loop.mjs +201 -0
  12. package/scripts/smoke.mjs +113 -0
  13. package/scripts/tool-failures.mjs +143 -0
  14. package/scripts/tool-smoke.mjs +452 -0
  15. package/src/agents/debugger/AGENT.md +3 -0
  16. package/src/agents/debugger/agent.json +6 -0
  17. package/src/agents/explore/AGENT.md +4 -0
  18. package/src/agents/explore/agent.json +6 -0
  19. package/src/agents/heavy-worker/AGENT.md +3 -0
  20. package/src/agents/heavy-worker/agent.json +6 -0
  21. package/src/agents/maintainer/AGENT.md +3 -0
  22. package/src/agents/maintainer/agent.json +6 -0
  23. package/src/agents/reviewer/AGENT.md +3 -0
  24. package/src/agents/reviewer/agent.json +6 -0
  25. package/src/agents/scheduler-task.md +3 -0
  26. package/src/agents/web-researcher/AGENT.md +3 -0
  27. package/src/agents/web-researcher/agent.json +6 -0
  28. package/src/agents/webhook-handler.md +3 -0
  29. package/src/agents/worker/AGENT.md +3 -0
  30. package/src/agents/worker/agent.json +6 -0
  31. package/src/app.mjs +90 -0
  32. package/src/cli.mjs +11 -0
  33. package/src/defaults/hidden-roles.json +72 -0
  34. package/src/defaults/mixdog-config.template.json +15 -0
  35. package/src/hooks/lib/permission-evaluator.cjs +488 -0
  36. package/src/hooks/lib/settings-loader.cjs +112 -0
  37. package/src/lib/keychain-cjs.cjs +332 -0
  38. package/src/lib/plugin-paths.cjs +28 -0
  39. package/src/lib/rules-builder.cjs +315 -0
  40. package/src/mixdog-session-runtime.mjs +3813 -0
  41. package/src/output-styles/default.md +38 -0
  42. package/src/output-styles/extreme-simple.md +17 -0
  43. package/src/output-styles/simple.md +17 -0
  44. package/src/repl.mjs +330 -0
  45. package/src/rules/bridge/00-common.md +5 -0
  46. package/src/rules/bridge/20-skip-protocol.md +11 -0
  47. package/src/rules/bridge/30-explorer.md +4 -0
  48. package/src/rules/bridge/40-cycle1-agent.md +28 -0
  49. package/src/rules/bridge/41-cycle2-agent.md +59 -0
  50. package/src/rules/lead/00-tool-lead.md +5 -0
  51. package/src/rules/lead/01-general.md +5 -0
  52. package/src/rules/lead/02-channels.md +3 -0
  53. package/src/rules/lead/04-workflow.md +12 -0
  54. package/src/rules/shared/00-language.md +3 -0
  55. package/src/rules/shared/01-tool.md +3 -0
  56. package/src/runtime/agent/orchestrator/bridge-trace.mjs +814 -0
  57. package/src/runtime/agent/orchestrator/cache-mtime.mjs +60 -0
  58. package/src/runtime/agent/orchestrator/config.mjs +446 -0
  59. package/src/runtime/agent/orchestrator/context/collect.mjs +796 -0
  60. package/src/runtime/agent/orchestrator/dispatch-persist.mjs +417 -0
  61. package/src/runtime/agent/orchestrator/internal-roles.mjs +188 -0
  62. package/src/runtime/agent/orchestrator/internal-tools.mjs +88 -0
  63. package/src/runtime/agent/orchestrator/mcp/client.mjs +345 -0
  64. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +2104 -0
  65. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +784 -0
  66. package/src/runtime/agent/orchestrator/providers/api-usage.mjs +341 -0
  67. package/src/runtime/agent/orchestrator/providers/gemini.mjs +1679 -0
  68. package/src/runtime/agent/orchestrator/providers/grok-oauth.mjs +959 -0
  69. package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +213 -0
  70. package/src/runtime/agent/orchestrator/providers/model-cache.mjs +38 -0
  71. package/src/runtime/agent/orchestrator/providers/model-catalog.mjs +471 -0
  72. package/src/runtime/agent/orchestrator/providers/oauth-usage.mjs +615 -0
  73. package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +808 -0
  74. package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +1719 -0
  75. package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +2587 -0
  76. package/src/runtime/agent/orchestrator/providers/openai-oauth.mjs +1953 -0
  77. package/src/runtime/agent/orchestrator/providers/openai-ws.mjs +136 -0
  78. package/src/runtime/agent/orchestrator/providers/opencode-go-usage.mjs +317 -0
  79. package/src/runtime/agent/orchestrator/providers/opencode-go.mjs +109 -0
  80. package/src/runtime/agent/orchestrator/providers/registry.mjs +247 -0
  81. package/src/runtime/agent/orchestrator/providers/retry-classifier.mjs +332 -0
  82. package/src/runtime/agent/orchestrator/providers/statusline-route-meta.mjs +11 -0
  83. package/src/runtime/agent/orchestrator/providers/trace-utils.mjs +50 -0
  84. package/src/runtime/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
  85. package/src/runtime/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  86. package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +318 -0
  87. package/src/runtime/agent/orchestrator/session/cache/scoped-cache.mjs +367 -0
  88. package/src/runtime/agent/orchestrator/session/compact.mjs +882 -0
  89. package/src/runtime/agent/orchestrator/session/context-utils.mjs +233 -0
  90. package/src/runtime/agent/orchestrator/session/loop.mjs +2269 -0
  91. package/src/runtime/agent/orchestrator/session/manager.mjs +2972 -0
  92. package/src/runtime/agent/orchestrator/session/result-classification.mjs +65 -0
  93. package/src/runtime/agent/orchestrator/session/store.mjs +870 -0
  94. package/src/runtime/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  95. package/src/runtime/agent/orchestrator/smart-bridge/bridge-llm.mjs +339 -0
  96. package/src/runtime/agent/orchestrator/smart-bridge/cache-strategy.mjs +419 -0
  97. package/src/runtime/agent/orchestrator/stall-policy.mjs +227 -0
  98. package/src/runtime/agent/orchestrator/tool-loop-guard.mjs +235 -0
  99. package/src/runtime/agent/orchestrator/tools/bash-session.mjs +723 -0
  100. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
  101. package/src/runtime/agent/orchestrator/tools/builtin/arg-guard.mjs +389 -0
  102. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +637 -0
  103. package/src/runtime/agent/orchestrator/tools/builtin/builtin-tools.mjs +165 -0
  104. package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +104 -0
  105. package/src/runtime/agent/orchestrator/tools/builtin/glob-walk.mjs +194 -0
  106. package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +596 -0
  107. package/src/runtime/agent/orchestrator/tools/builtin/native-edit-runner.mjs +110 -0
  108. package/src/runtime/agent/orchestrator/tools/builtin/path-diagnostics.mjs +153 -0
  109. package/src/runtime/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  110. package/src/runtime/agent/orchestrator/tools/builtin/read-open.mjs +189 -0
  111. package/src/runtime/agent/orchestrator/tools/builtin/read-single-tool.mjs +731 -0
  112. package/src/runtime/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +168 -0
  113. package/src/runtime/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  114. package/src/runtime/agent/orchestrator/tools/builtin/rg-runner.mjs +465 -0
  115. package/src/runtime/agent/orchestrator/tools/builtin/search-builders.mjs +160 -0
  116. package/src/runtime/agent/orchestrator/tools/builtin/search-tool.mjs +982 -0
  117. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +1087 -0
  118. package/src/runtime/agent/orchestrator/tools/builtin/shell-runtime.mjs +231 -0
  119. package/src/runtime/agent/orchestrator/tools/builtin/snapshot-store.mjs +223 -0
  120. package/src/runtime/agent/orchestrator/tools/builtin.mjs +478 -0
  121. package/src/runtime/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  122. package/src/runtime/agent/orchestrator/tools/code-graph.mjs +4102 -0
  123. package/src/runtime/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  124. package/src/runtime/agent/orchestrator/tools/graph-binary-fetcher.mjs +154 -0
  125. package/src/runtime/agent/orchestrator/tools/graph-manifest.json +26 -0
  126. package/src/runtime/agent/orchestrator/tools/patch-binary-fetcher.mjs +143 -0
  127. package/src/runtime/agent/orchestrator/tools/patch-tool-defs.mjs +18 -0
  128. package/src/runtime/agent/orchestrator/tools/patch.mjs +2772 -0
  129. package/src/runtime/agent/orchestrator/tools/progress-message.mjs +114 -0
  130. package/src/runtime/agent/orchestrator/tools/shell-command.mjs +880 -0
  131. package/src/runtime/agent/orchestrator/tools/shell-snapshot.mjs +312 -0
  132. package/src/runtime/channels/backends/discord.mjs +781 -0
  133. package/src/runtime/channels/data/voice-runtime-manifest.json +138 -0
  134. package/src/runtime/channels/index.mjs +3309 -0
  135. package/src/runtime/channels/lib/config.mjs +285 -0
  136. package/src/runtime/channels/lib/drop-trace.mjs +71 -0
  137. package/src/runtime/channels/lib/event-pipeline.mjs +81 -0
  138. package/src/runtime/channels/lib/holidays.mjs +138 -0
  139. package/src/runtime/channels/lib/hook-pipe-server.mjs +671 -0
  140. package/src/runtime/channels/lib/output-forwarder.mjs +765 -0
  141. package/src/runtime/channels/lib/runtime-paths.mjs +497 -0
  142. package/src/runtime/channels/lib/scheduler.mjs +710 -0
  143. package/src/runtime/channels/lib/session-discovery.mjs +102 -0
  144. package/src/runtime/channels/lib/state-file.mjs +68 -0
  145. package/src/runtime/channels/lib/status-snapshot.mjs +224 -0
  146. package/src/runtime/channels/lib/tool-format.mjs +122 -0
  147. package/src/runtime/channels/lib/transcript-discovery.mjs +195 -0
  148. package/src/runtime/channels/lib/voice-runtime-fetcher.mjs +734 -0
  149. package/src/runtime/channels/lib/webhook.mjs +1288 -0
  150. package/src/runtime/channels/tool-defs.mjs +177 -0
  151. package/src/runtime/lib/keychain-cjs.cjs +289 -0
  152. package/src/runtime/memory/data/runtime-manifest.json +40 -0
  153. package/src/runtime/memory/index.mjs +3706 -0
  154. package/src/runtime/memory/lib/core-memory-store.mjs +336 -0
  155. package/src/runtime/memory/lib/embedding-provider.mjs +275 -0
  156. package/src/runtime/memory/lib/embedding-worker.mjs +331 -0
  157. package/src/runtime/memory/lib/memory-cycle-requests.mjs +276 -0
  158. package/src/runtime/memory/lib/memory-cycle1.mjs +783 -0
  159. package/src/runtime/memory/lib/memory-cycle2.mjs +1389 -0
  160. package/src/runtime/memory/lib/memory-cycle3.mjs +646 -0
  161. package/src/runtime/memory/lib/memory-embed.mjs +300 -0
  162. package/src/runtime/memory/lib/memory-ops-policy.mjs +149 -0
  163. package/src/runtime/memory/lib/memory-recall-store.mjs +644 -0
  164. package/src/runtime/memory/lib/memory.mjs +418 -0
  165. package/src/runtime/memory/lib/pg/adapter.mjs +328 -0
  166. package/src/runtime/memory/lib/pg/process.mjs +366 -0
  167. package/src/runtime/memory/lib/pg/supervisor.mjs +495 -0
  168. package/src/runtime/memory/lib/runtime-fetcher.mjs +464 -0
  169. package/src/runtime/memory/lib/trace-store.mjs +734 -0
  170. package/src/runtime/memory/tool-defs.mjs +79 -0
  171. package/src/runtime/search/index.mjs +925 -0
  172. package/src/runtime/search/lib/config.mjs +61 -0
  173. package/src/runtime/search/lib/web-tools.mjs +1278 -0
  174. package/src/runtime/search/tool-defs.mjs +64 -0
  175. package/src/runtime/shared/atomic-file.mjs +435 -0
  176. package/src/runtime/shared/background-tasks.mjs +376 -0
  177. package/src/runtime/shared/child-guardian.mjs +98 -0
  178. package/src/runtime/shared/config.mjs +393 -0
  179. package/src/runtime/shared/err-text.mjs +121 -0
  180. package/src/runtime/shared/launcher-control.mjs +259 -0
  181. package/src/runtime/shared/llm/http-agent.mjs +129 -0
  182. package/src/runtime/shared/open-url.mjs +37 -0
  183. package/src/runtime/shared/plugin-paths.mjs +25 -0
  184. package/src/runtime/shared/process-shutdown.mjs +147 -0
  185. package/src/runtime/shared/schedules-store.mjs +70 -0
  186. package/src/runtime/shared/tool-execution-contract.mjs +104 -0
  187. package/src/runtime/shared/tool-surface.mjs +947 -0
  188. package/src/runtime/shared/user-cwd.mjs +221 -0
  189. package/src/runtime/shared/user-data-guard.mjs +232 -0
  190. package/src/runtime/shared/workspace-router.mjs +259 -0
  191. package/src/standalone/bridge-tool.mjs +1414 -0
  192. package/src/standalone/channel-admin.mjs +366 -0
  193. package/src/standalone/channel-worker-preload.cjs +3 -0
  194. package/src/standalone/channel-worker.mjs +353 -0
  195. package/src/standalone/explore-tool.mjs +233 -0
  196. package/src/standalone/hook-bus.mjs +246 -0
  197. package/src/standalone/plugin-admin.mjs +247 -0
  198. package/src/standalone/provider-admin.mjs +338 -0
  199. package/src/standalone/seeds.mjs +94 -0
  200. package/src/standalone/usage-dashboard.mjs +510 -0
  201. package/src/tui/App.jsx +5446 -0
  202. package/src/tui/components/AnsiText.jsx +199 -0
  203. package/src/tui/components/ContextPanel.jsx +265 -0
  204. package/src/tui/components/Markdown.jsx +205 -0
  205. package/src/tui/components/MarkdownTable.jsx +204 -0
  206. package/src/tui/components/Message.jsx +103 -0
  207. package/src/tui/components/Picker.jsx +317 -0
  208. package/src/tui/components/PromptInput.jsx +584 -0
  209. package/src/tui/components/QueuedCommands.jsx +47 -0
  210. package/src/tui/components/SlashCommandPalette.jsx +114 -0
  211. package/src/tui/components/Spinner.jsx +317 -0
  212. package/src/tui/components/StatusLine.jsx +87 -0
  213. package/src/tui/components/TextEntryPanel.jsx +323 -0
  214. package/src/tui/components/ToolExecution.jsx +791 -0
  215. package/src/tui/components/TurnDone.jsx +78 -0
  216. package/src/tui/components/UsagePanel.jsx +331 -0
  217. package/src/tui/dist/index.mjs +12420 -0
  218. package/src/tui/engine.mjs +2410 -0
  219. package/src/tui/figures.mjs +50 -0
  220. package/src/tui/hooks/useEngine.mjs +16 -0
  221. package/src/tui/index.jsx +254 -0
  222. package/src/tui/input-editing.mjs +242 -0
  223. package/src/tui/markdown/format-token.mjs +194 -0
  224. package/src/tui/paste-attachments.mjs +198 -0
  225. package/src/tui/runtime/shared/process-shutdown.mjs +1 -0
  226. package/src/tui/spinner-verbs.mjs +45 -0
  227. package/src/tui/theme.mjs +67 -0
  228. package/src/tui/time-format.mjs +53 -0
  229. package/src/ui/ansi.mjs +115 -0
  230. package/src/ui/markdown.mjs +195 -0
  231. package/src/ui/statusline.mjs +730 -0
  232. package/src/ui/tool-card.mjs +99 -0
  233. package/src/vendor/statusline/bin/statusline-lib.mjs +805 -0
  234. package/src/vendor/statusline/bin/statusline-route.mjs +596 -0
  235. package/src/vendor/statusline/scripts/lib/gateway-settings.mjs +285 -0
  236. package/src/vendor/statusline/src/gateway/claude-current.mjs +320 -0
  237. package/src/vendor/statusline/src/gateway/route-meta.mjs +753 -0
  238. package/src/vendor/statusline/src/gateway/session-routes.mjs +244 -0
  239. package/src/workflows/default/WORKFLOW.md +7 -0
  240. package/src/workflows/default/workflow.json +14 -0
  241. package/vendor/ink/build/ansi-tokenizer.d.ts +38 -0
  242. package/vendor/ink/build/ansi-tokenizer.js +316 -0
  243. package/vendor/ink/build/ansi-tokenizer.js.map +1 -0
  244. package/vendor/ink/build/colorize.d.ts +3 -0
  245. package/vendor/ink/build/colorize.js +48 -0
  246. package/vendor/ink/build/colorize.js.map +1 -0
  247. package/vendor/ink/build/components/AccessibilityContext.d.ts +3 -0
  248. package/vendor/ink/build/components/AccessibilityContext.js +5 -0
  249. package/vendor/ink/build/components/AccessibilityContext.js.map +1 -0
  250. package/vendor/ink/build/components/AnimationContext.d.ts +9 -0
  251. package/vendor/ink/build/components/AnimationContext.js +13 -0
  252. package/vendor/ink/build/components/AnimationContext.js.map +1 -0
  253. package/vendor/ink/build/components/App.d.ts +24 -0
  254. package/vendor/ink/build/components/App.js +554 -0
  255. package/vendor/ink/build/components/App.js.map +1 -0
  256. package/vendor/ink/build/components/AppContext.d.ts +80 -0
  257. package/vendor/ink/build/components/AppContext.js +25 -0
  258. package/vendor/ink/build/components/AppContext.js.map +1 -0
  259. package/vendor/ink/build/components/BackgroundContext.d.ts +4 -0
  260. package/vendor/ink/build/components/BackgroundContext.js +3 -0
  261. package/vendor/ink/build/components/BackgroundContext.js.map +1 -0
  262. package/vendor/ink/build/components/Box.d.ts +130 -0
  263. package/vendor/ink/build/components/Box.js +34 -0
  264. package/vendor/ink/build/components/Box.js.map +1 -0
  265. package/vendor/ink/build/components/CursorContext.d.ts +11 -0
  266. package/vendor/ink/build/components/CursorContext.js +8 -0
  267. package/vendor/ink/build/components/CursorContext.js.map +1 -0
  268. package/vendor/ink/build/components/ErrorBoundary.d.ts +18 -0
  269. package/vendor/ink/build/components/ErrorBoundary.js +23 -0
  270. package/vendor/ink/build/components/ErrorBoundary.js.map +1 -0
  271. package/vendor/ink/build/components/ErrorOverview.d.ts +6 -0
  272. package/vendor/ink/build/components/ErrorOverview.js +90 -0
  273. package/vendor/ink/build/components/ErrorOverview.js.map +1 -0
  274. package/vendor/ink/build/components/FocusContext.d.ts +16 -0
  275. package/vendor/ink/build/components/FocusContext.js +17 -0
  276. package/vendor/ink/build/components/FocusContext.js.map +1 -0
  277. package/vendor/ink/build/components/Newline.d.ts +13 -0
  278. package/vendor/ink/build/components/Newline.js +8 -0
  279. package/vendor/ink/build/components/Newline.js.map +1 -0
  280. package/vendor/ink/build/components/Spacer.d.ts +7 -0
  281. package/vendor/ink/build/components/Spacer.js +11 -0
  282. package/vendor/ink/build/components/Spacer.js.map +1 -0
  283. package/vendor/ink/build/components/Static.d.ts +24 -0
  284. package/vendor/ink/build/components/Static.js +28 -0
  285. package/vendor/ink/build/components/Static.js.map +1 -0
  286. package/vendor/ink/build/components/StderrContext.d.ts +15 -0
  287. package/vendor/ink/build/components/StderrContext.js +13 -0
  288. package/vendor/ink/build/components/StderrContext.js.map +1 -0
  289. package/vendor/ink/build/components/StdinContext.d.ts +28 -0
  290. package/vendor/ink/build/components/StdinContext.js +20 -0
  291. package/vendor/ink/build/components/StdinContext.js.map +1 -0
  292. package/vendor/ink/build/components/StdoutContext.d.ts +15 -0
  293. package/vendor/ink/build/components/StdoutContext.js +13 -0
  294. package/vendor/ink/build/components/StdoutContext.js.map +1 -0
  295. package/vendor/ink/build/components/Text.d.ts +55 -0
  296. package/vendor/ink/build/components/Text.js +50 -0
  297. package/vendor/ink/build/components/Text.js.map +1 -0
  298. package/vendor/ink/build/components/Transform.d.ts +16 -0
  299. package/vendor/ink/build/components/Transform.js +15 -0
  300. package/vendor/ink/build/components/Transform.js.map +1 -0
  301. package/vendor/ink/build/cursor-helpers.d.ts +39 -0
  302. package/vendor/ink/build/cursor-helpers.js +62 -0
  303. package/vendor/ink/build/cursor-helpers.js.map +1 -0
  304. package/vendor/ink/build/devtools-window-polyfill.d.ts +1 -0
  305. package/vendor/ink/build/devtools-window-polyfill.js +68 -0
  306. package/vendor/ink/build/devtools-window-polyfill.js.map +1 -0
  307. package/vendor/ink/build/devtools.d.ts +1 -0
  308. package/vendor/ink/build/devtools.js +36 -0
  309. package/vendor/ink/build/devtools.js.map +1 -0
  310. package/vendor/ink/build/dom.d.ts +62 -0
  311. package/vendor/ink/build/dom.js +143 -0
  312. package/vendor/ink/build/dom.js.map +1 -0
  313. package/vendor/ink/build/get-max-width.d.ts +3 -0
  314. package/vendor/ink/build/get-max-width.js +10 -0
  315. package/vendor/ink/build/get-max-width.js.map +1 -0
  316. package/vendor/ink/build/hooks/use-animation.d.ts +49 -0
  317. package/vendor/ink/build/hooks/use-animation.js +87 -0
  318. package/vendor/ink/build/hooks/use-animation.js.map +1 -0
  319. package/vendor/ink/build/hooks/use-app.d.ts +5 -0
  320. package/vendor/ink/build/hooks/use-app.js +8 -0
  321. package/vendor/ink/build/hooks/use-app.js.map +1 -0
  322. package/vendor/ink/build/hooks/use-box-metrics.d.ts +59 -0
  323. package/vendor/ink/build/hooks/use-box-metrics.js +81 -0
  324. package/vendor/ink/build/hooks/use-box-metrics.js.map +1 -0
  325. package/vendor/ink/build/hooks/use-cursor.d.ts +12 -0
  326. package/vendor/ink/build/hooks/use-cursor.js +29 -0
  327. package/vendor/ink/build/hooks/use-cursor.js.map +1 -0
  328. package/vendor/ink/build/hooks/use-focus-manager.d.ts +43 -0
  329. package/vendor/ink/build/hooks/use-focus-manager.js +18 -0
  330. package/vendor/ink/build/hooks/use-focus-manager.js.map +1 -0
  331. package/vendor/ink/build/hooks/use-focus.d.ts +30 -0
  332. package/vendor/ink/build/hooks/use-focus.js +43 -0
  333. package/vendor/ink/build/hooks/use-focus.js.map +1 -0
  334. package/vendor/ink/build/hooks/use-input.d.ts +132 -0
  335. package/vendor/ink/build/hooks/use-input.js +126 -0
  336. package/vendor/ink/build/hooks/use-input.js.map +1 -0
  337. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.d.ts +6 -0
  338. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js +12 -0
  339. package/vendor/ink/build/hooks/use-is-screen-reader-enabled.js.map +1 -0
  340. package/vendor/ink/build/hooks/use-paste.d.ts +35 -0
  341. package/vendor/ink/build/hooks/use-paste.js +62 -0
  342. package/vendor/ink/build/hooks/use-paste.js.map +1 -0
  343. package/vendor/ink/build/hooks/use-stderr.d.ts +5 -0
  344. package/vendor/ink/build/hooks/use-stderr.js +8 -0
  345. package/vendor/ink/build/hooks/use-stderr.js.map +1 -0
  346. package/vendor/ink/build/hooks/use-stdin.d.ts +7 -0
  347. package/vendor/ink/build/hooks/use-stdin.js +9 -0
  348. package/vendor/ink/build/hooks/use-stdin.js.map +1 -0
  349. package/vendor/ink/build/hooks/use-stdout.d.ts +5 -0
  350. package/vendor/ink/build/hooks/use-stdout.js +8 -0
  351. package/vendor/ink/build/hooks/use-stdout.js.map +1 -0
  352. package/vendor/ink/build/hooks/use-window-size.d.ts +18 -0
  353. package/vendor/ink/build/hooks/use-window-size.js +22 -0
  354. package/vendor/ink/build/hooks/use-window-size.js.map +1 -0
  355. package/vendor/ink/build/index.d.ts +42 -0
  356. package/vendor/ink/build/index.js +24 -0
  357. package/vendor/ink/build/index.js.map +1 -0
  358. package/vendor/ink/build/ink.d.ts +146 -0
  359. package/vendor/ink/build/ink.js +1022 -0
  360. package/vendor/ink/build/ink.js.map +1 -0
  361. package/vendor/ink/build/input-parser.d.ts +10 -0
  362. package/vendor/ink/build/input-parser.js +194 -0
  363. package/vendor/ink/build/input-parser.js.map +1 -0
  364. package/vendor/ink/build/instances.d.ts +3 -0
  365. package/vendor/ink/build/instances.js +8 -0
  366. package/vendor/ink/build/instances.js.map +1 -0
  367. package/vendor/ink/build/kitty-keyboard.d.ts +23 -0
  368. package/vendor/ink/build/kitty-keyboard.js +32 -0
  369. package/vendor/ink/build/kitty-keyboard.js.map +1 -0
  370. package/vendor/ink/build/log-update.d.ts +20 -0
  371. package/vendor/ink/build/log-update.js +261 -0
  372. package/vendor/ink/build/log-update.js.map +1 -0
  373. package/vendor/ink/build/measure-element.d.ts +20 -0
  374. package/vendor/ink/build/measure-element.js +13 -0
  375. package/vendor/ink/build/measure-element.js.map +1 -0
  376. package/vendor/ink/build/measure-text.d.ts +6 -0
  377. package/vendor/ink/build/measure-text.js +21 -0
  378. package/vendor/ink/build/measure-text.js.map +1 -0
  379. package/vendor/ink/build/output.d.ts +35 -0
  380. package/vendor/ink/build/output.js +328 -0
  381. package/vendor/ink/build/output.js.map +1 -0
  382. package/vendor/ink/build/parse-keypress.d.ts +20 -0
  383. package/vendor/ink/build/parse-keypress.js +495 -0
  384. package/vendor/ink/build/parse-keypress.js.map +1 -0
  385. package/vendor/ink/build/reconciler.d.ts +4 -0
  386. package/vendor/ink/build/reconciler.js +306 -0
  387. package/vendor/ink/build/reconciler.js.map +1 -0
  388. package/vendor/ink/build/render-background.d.ts +4 -0
  389. package/vendor/ink/build/render-background.js +25 -0
  390. package/vendor/ink/build/render-background.js.map +1 -0
  391. package/vendor/ink/build/render-border.d.ts +4 -0
  392. package/vendor/ink/build/render-border.js +84 -0
  393. package/vendor/ink/build/render-border.js.map +1 -0
  394. package/vendor/ink/build/render-node-to-output.d.ts +14 -0
  395. package/vendor/ink/build/render-node-to-output.js +162 -0
  396. package/vendor/ink/build/render-node-to-output.js.map +1 -0
  397. package/vendor/ink/build/render-to-string.d.ts +38 -0
  398. package/vendor/ink/build/render-to-string.js +116 -0
  399. package/vendor/ink/build/render-to-string.js.map +1 -0
  400. package/vendor/ink/build/render.d.ts +176 -0
  401. package/vendor/ink/build/render.js +71 -0
  402. package/vendor/ink/build/render.js.map +1 -0
  403. package/vendor/ink/build/renderer.d.ts +8 -0
  404. package/vendor/ink/build/renderer.js +64 -0
  405. package/vendor/ink/build/renderer.js.map +1 -0
  406. package/vendor/ink/build/sanitize-ansi.d.ts +2 -0
  407. package/vendor/ink/build/sanitize-ansi.js +27 -0
  408. package/vendor/ink/build/sanitize-ansi.js.map +1 -0
  409. package/vendor/ink/build/squash-text-nodes.d.ts +3 -0
  410. package/vendor/ink/build/squash-text-nodes.js +36 -0
  411. package/vendor/ink/build/squash-text-nodes.js.map +1 -0
  412. package/vendor/ink/build/styles.d.ts +302 -0
  413. package/vendor/ink/build/styles.js +303 -0
  414. package/vendor/ink/build/styles.js.map +1 -0
  415. package/vendor/ink/build/utils.d.ts +9 -0
  416. package/vendor/ink/build/utils.js +19 -0
  417. package/vendor/ink/build/utils.js.map +1 -0
  418. package/vendor/ink/build/wrap-text.d.ts +3 -0
  419. package/vendor/ink/build/wrap-text.js +38 -0
  420. package/vendor/ink/build/wrap-text.js.map +1 -0
  421. package/vendor/ink/build/write-synchronized.d.ts +4 -0
  422. package/vendor/ink/build/write-synchronized.js +9 -0
  423. package/vendor/ink/build/write-synchronized.js.map +1 -0
  424. package/vendor/ink/license +10 -0
  425. package/vendor/ink/package.json +137 -0
  426. package/.claude-plugin/marketplace.json +0 -34
  427. package/.claude-plugin/plugin.json +0 -20
  428. package/.gitattributes +0 -34
  429. package/.mcp.json +0 -14
  430. package/ARCHITECTURE.md +0 -77
  431. package/CHANGELOG.md +0 -30
  432. package/CONTRIBUTING.md +0 -45
  433. package/DATA-FLOW.md +0 -79
  434. package/LICENSE +0 -21
  435. package/SECURITY.md +0 -138
  436. package/UNINSTALL.md +0 -115
  437. package/agents/maintenance.md +0 -5
  438. package/agents/memory-classification.md +0 -30
  439. package/agents/scheduler-task.md +0 -18
  440. package/agents/webhook-handler.md +0 -27
  441. package/agents/worker.md +0 -24
  442. package/bin/bridge +0 -133
  443. package/bin/statusline-launcher.mjs +0 -82
  444. package/bin/statusline-lib.mjs +0 -581
  445. package/bin/statusline-route.mjs +0 -273
  446. package/bin/statusline.mjs +0 -638
  447. package/bun.lock +0 -927
  448. package/commands/config.md +0 -16
  449. package/commands/doctor.md +0 -13
  450. package/commands/model.md +0 -61
  451. package/commands/setup.md +0 -17
  452. package/defaults/hidden-roles.json +0 -68
  453. package/defaults/memory-chunk-prompt.md +0 -63
  454. package/defaults/mixdog-config.template.json +0 -27
  455. package/defaults/user-workflow.json +0 -8
  456. package/defaults/user-workflow.md +0 -17
  457. package/hooks/hooks.json +0 -73
  458. package/hooks/lib/active-instance.cjs +0 -77
  459. package/hooks/lib/permission-evaluator.cjs +0 -411
  460. package/hooks/lib/permission-route.cjs +0 -63
  461. package/hooks/lib/settings-loader.cjs +0 -117
  462. package/hooks/post-tool-use.cjs +0 -84
  463. package/hooks/pre-mcp-sandbox.cjs +0 -158
  464. package/hooks/pre-tool-subagent.cjs +0 -258
  465. package/hooks/session-start.cjs +0 -1493
  466. package/hooks/shim-launcher.cjs +0 -65
  467. package/hooks/turn-timer.cjs +0 -82
  468. package/lib/claude-md-writer.cjs +0 -386
  469. package/lib/keychain-cjs.cjs +0 -290
  470. package/lib/plugin-paths.cjs +0 -69
  471. package/lib/rules-builder.cjs +0 -241
  472. package/native/README.md +0 -117
  473. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  474. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  475. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  476. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  477. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  478. package/prompts/code-review.txt +0 -16
  479. package/prompts/security-audit.txt +0 -17
  480. package/rules/bridge/00-common.md +0 -39
  481. package/rules/bridge/20-skip-protocol.md +0 -18
  482. package/rules/bridge/30-explorer.md +0 -33
  483. package/rules/bridge/40-cycle1-agent.md +0 -52
  484. package/rules/bridge/41-cycle2-agent.md +0 -62
  485. package/rules/lead/00-tool-lead.md +0 -61
  486. package/rules/lead/01-general.md +0 -26
  487. package/rules/lead/02-channels.md +0 -49
  488. package/rules/lead/03-team.md +0 -27
  489. package/rules/lead/04-workflow.md +0 -20
  490. package/rules/shared/00-language.md +0 -14
  491. package/rules/shared/01-tool.md +0 -138
  492. package/scripts/bootstrap.mjs +0 -130
  493. package/scripts/bridge-unify-smoke.mjs +0 -308
  494. package/scripts/build-runtime-linux.sh +0 -348
  495. package/scripts/build-runtime-macos.sh +0 -217
  496. package/scripts/build-runtime-windows.ps1 +0 -242
  497. package/scripts/builtin-utils-smoke.mjs +0 -398
  498. package/scripts/bump.mjs +0 -80
  499. package/scripts/check-json.mjs +0 -45
  500. package/scripts/check-syntax-changed.mjs +0 -102
  501. package/scripts/check-syntax.mjs +0 -58
  502. package/scripts/code-graph-batch.test.mjs +0 -33
  503. package/scripts/config-preserve-smoke.mjs +0 -180
  504. package/scripts/doctor.mjs +0 -489
  505. package/scripts/edit-normalize-fuzz.mjs +0 -130
  506. package/scripts/edit-normalize-smoke.mjs +0 -401
  507. package/scripts/edit-operation-smoke.mjs +0 -369
  508. package/scripts/edit2-smoke.mjs +0 -63
  509. package/scripts/ensure-deps.mjs +0 -259
  510. package/scripts/fuzzy-e2e.mjs +0 -28
  511. package/scripts/fuzzy-smoke.mjs +0 -26
  512. package/scripts/gateway-model.mjs +0 -596
  513. package/scripts/generate-runtime-manifest.mjs +0 -166
  514. package/scripts/guard-smoke.mjs +0 -66
  515. package/scripts/hidden-role-schema-smoke.mjs +0 -162
  516. package/scripts/hook-routing-smoke.mjs +0 -29
  517. package/scripts/inject-input.ps1 +0 -204
  518. package/scripts/io-complex-smoke.mjs +0 -667
  519. package/scripts/io-explore-bench.mjs +0 -424
  520. package/scripts/io-guardrails-smoke.mjs +0 -205
  521. package/scripts/io-mini-bench-baseline.json +0 -11
  522. package/scripts/io-mini-bench.mjs +0 -216
  523. package/scripts/io-route-harness.mjs +0 -933
  524. package/scripts/io-telemetry-report.mjs +0 -691
  525. package/scripts/lib/gateway-inventory.mjs +0 -178
  526. package/scripts/lib/gateway-settings.mjs +0 -78
  527. package/scripts/mutation-bench.mjs +0 -564
  528. package/scripts/mutation-io-smoke.mjs +0 -1097
  529. package/scripts/native-patch-bridge-smoke.mjs +0 -288
  530. package/scripts/native-patch-smoke.mjs +0 -304
  531. package/scripts/openai-oauth-catalog-smoke.mjs +0 -53
  532. package/scripts/patch-interior-context-smoke.mjs +0 -49
  533. package/scripts/patch-newline-utf8-smoke.mjs +0 -157
  534. package/scripts/perf-hook-smoke.mjs +0 -71
  535. package/scripts/permission-eval-smoke.mjs +0 -443
  536. package/scripts/prep-patch.mjs +0 -53
  537. package/scripts/prep-shim.mjs +0 -96
  538. package/scripts/provider-cache-smoke.mjs +0 -687
  539. package/scripts/report-runtime-health.mjs +0 -132
  540. package/scripts/resolve-bun.mjs +0 -60
  541. package/scripts/run-mcp.mjs +0 -1473
  542. package/scripts/salvage-v4a-shatter.test.mjs +0 -58
  543. package/scripts/scoped-cache-io-smoke.mjs +0 -103
  544. package/scripts/shell-policy-round3-smoke.mjs +0 -46
  545. package/scripts/smoke-runtime-negative.ps1 +0 -100
  546. package/scripts/smoke-runtime-negative.sh +0 -95
  547. package/scripts/stall-policy-smoke.mjs +0 -50
  548. package/scripts/start-memory-worker.mjs +0 -23
  549. package/scripts/statusline-launcher-smoke.mjs +0 -235
  550. package/scripts/stress-atomic-write.mjs +0 -1028
  551. package/scripts/test-fault-inject.mjs +0 -164
  552. package/scripts/test-large-file.mjs +0 -174
  553. package/scripts/tool-edge-smoke.mjs +0 -209
  554. package/scripts/uninstall.mjs +0 -238
  555. package/scripts/webhook-selfheal-smoke.mjs +0 -27
  556. package/scripts/write-overwrite-guard-smoke.mjs +0 -56
  557. package/server-main.mjs +0 -3350
  558. package/server.mjs +0 -468
  559. package/setup/config-merge.mjs +0 -246
  560. package/setup/install.mjs +0 -574
  561. package/setup/launch-core.mjs +0 -617
  562. package/setup/launch.mjs +0 -101
  563. package/setup/locate-claude.mjs +0 -56
  564. package/setup/mixdog-cli.mjs +0 -122
  565. package/setup/setup-server.mjs +0 -3305
  566. package/setup/setup.html +0 -3740
  567. package/setup/tui.mjs +0 -325
  568. package/skills/retro-skill-proposer/SKILL.md +0 -92
  569. package/skills/schedule-add/SKILL.md +0 -77
  570. package/skills/setup/SKILL.md +0 -356
  571. package/skills/webhook-add/SKILL.md +0 -81
  572. package/src/agent/bridge-stall-watchdog.mjs +0 -337
  573. package/src/agent/index.mjs +0 -2229
  574. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +0 -1010
  575. package/src/agent/orchestrator/bridge-retry.mjs +0 -220
  576. package/src/agent/orchestrator/bridge-trace.mjs +0 -601
  577. package/src/agent/orchestrator/cache-mtime.mjs +0 -58
  578. package/src/agent/orchestrator/config.mjs +0 -405
  579. package/src/agent/orchestrator/context/collect.mjs +0 -651
  580. package/src/agent/orchestrator/dispatch-persist.mjs +0 -549
  581. package/src/agent/orchestrator/drain-registry.mjs +0 -50
  582. package/src/agent/orchestrator/explore-validator.mjs +0 -8
  583. package/src/agent/orchestrator/internal-roles.mjs +0 -118
  584. package/src/agent/orchestrator/internal-tools.mjs +0 -88
  585. package/src/agent/orchestrator/jobs.mjs +0 -116
  586. package/src/agent/orchestrator/mcp/client.mjs +0 -364
  587. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +0 -1884
  588. package/src/agent/orchestrator/providers/anthropic.mjs +0 -598
  589. package/src/agent/orchestrator/providers/gemini.mjs +0 -1530
  590. package/src/agent/orchestrator/providers/grok-oauth.mjs +0 -779
  591. package/src/agent/orchestrator/providers/model-catalog.mjs +0 -374
  592. package/src/agent/orchestrator/providers/openai-compat-stream.mjs +0 -366
  593. package/src/agent/orchestrator/providers/openai-compat.mjs +0 -1511
  594. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +0 -1891
  595. package/src/agent/orchestrator/providers/openai-oauth.mjs +0 -1456
  596. package/src/agent/orchestrator/providers/openai-ws.mjs +0 -127
  597. package/src/agent/orchestrator/providers/registry.mjs +0 -192
  598. package/src/agent/orchestrator/providers/retry-classifier.mjs +0 -325
  599. package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +0 -42
  600. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +0 -142
  601. package/src/agent/orchestrator/session/cache/read-cache.mjs +0 -319
  602. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +0 -361
  603. package/src/agent/orchestrator/session/loop.mjs +0 -1619
  604. package/src/agent/orchestrator/session/manager.mjs +0 -1991
  605. package/src/agent/orchestrator/session/result-classification.mjs +0 -65
  606. package/src/agent/orchestrator/session/store.mjs +0 -632
  607. package/src/agent/orchestrator/session/stream-watchdog.mjs +0 -130
  608. package/src/agent/orchestrator/session/tool-result-offload.mjs +0 -166
  609. package/src/agent/orchestrator/session/trim.mjs +0 -491
  610. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +0 -115
  611. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +0 -331
  612. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +0 -150
  613. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +0 -228
  614. package/src/agent/orchestrator/smart-bridge/index.mjs +0 -215
  615. package/src/agent/orchestrator/smart-bridge/profiles.mjs +0 -37
  616. package/src/agent/orchestrator/smart-bridge/registry.mjs +0 -348
  617. package/src/agent/orchestrator/stall-policy.mjs +0 -201
  618. package/src/agent/orchestrator/tool-loop-guard.mjs +0 -75
  619. package/src/agent/orchestrator/tools/bash-session.mjs +0 -722
  620. package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +0 -171
  621. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +0 -511
  622. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +0 -480
  623. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +0 -256
  624. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +0 -58
  625. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +0 -240
  626. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +0 -113
  627. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +0 -74
  628. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +0 -242
  629. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +0 -211
  630. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +0 -1364
  631. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +0 -126
  632. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +0 -141
  633. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +0 -194
  634. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +0 -60
  635. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +0 -168
  636. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +0 -173
  637. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +0 -48
  638. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -99
  639. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +0 -193
  640. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +0 -597
  641. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +0 -110
  642. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +0 -300
  643. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +0 -152
  644. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +0 -118
  645. package/src/agent/orchestrator/tools/builtin/read-open.mjs +0 -190
  646. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +0 -728
  647. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +0 -173
  648. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +0 -602
  649. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +0 -196
  650. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +0 -422
  651. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +0 -158
  652. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +0 -869
  653. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +0 -962
  654. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +0 -223
  655. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +0 -206
  656. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +0 -401
  657. package/src/agent/orchestrator/tools/builtin.mjs +0 -503
  658. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +0 -24
  659. package/src/agent/orchestrator/tools/code-graph.mjs +0 -4095
  660. package/src/agent/orchestrator/tools/cwd-tool.mjs +0 -298
  661. package/src/agent/orchestrator/tools/destructive-warning.mjs +0 -323
  662. package/src/agent/orchestrator/tools/edit-normalize.mjs +0 -603
  663. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +0 -154
  664. package/src/agent/orchestrator/tools/graph-manifest.json +0 -26
  665. package/src/agent/orchestrator/tools/host-input.mjs +0 -204
  666. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +0 -143
  667. package/src/agent/orchestrator/tools/patch-manifest.json +0 -26
  668. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +0 -20
  669. package/src/agent/orchestrator/tools/patch.mjs +0 -2754
  670. package/src/agent/orchestrator/tools/progress-message.mjs +0 -118
  671. package/src/agent/orchestrator/tools/shell-command.mjs +0 -865
  672. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +0 -7
  673. package/src/agent/orchestrator/tools/shell-snapshot.mjs +0 -313
  674. package/src/agent/orchestrator/workflow-store.mjs +0 -93
  675. package/src/agent/tool-defs.mjs +0 -110
  676. package/src/channels/backends/discord.mjs +0 -784
  677. package/src/channels/data/voice-runtime-manifest.json +0 -138
  678. package/src/channels/index.mjs +0 -3268
  679. package/src/channels/lib/config.mjs +0 -292
  680. package/src/channels/lib/drop-trace.mjs +0 -71
  681. package/src/channels/lib/event-pipeline.mjs +0 -81
  682. package/src/channels/lib/holidays.mjs +0 -138
  683. package/src/channels/lib/hook-pipe-server.mjs +0 -822
  684. package/src/channels/lib/output-forwarder.mjs +0 -765
  685. package/src/channels/lib/runtime-paths.mjs +0 -552
  686. package/src/channels/lib/scheduler.mjs +0 -723
  687. package/src/channels/lib/session-discovery.mjs +0 -103
  688. package/src/channels/lib/state-file.mjs +0 -68
  689. package/src/channels/lib/status-snapshot.mjs +0 -219
  690. package/src/channels/lib/tool-format.mjs +0 -140
  691. package/src/channels/lib/transcript-discovery.mjs +0 -195
  692. package/src/channels/lib/voice-runtime-fetcher.mjs +0 -734
  693. package/src/channels/lib/webhook.mjs +0 -1318
  694. package/src/channels/tool-defs.mjs +0 -170
  695. package/src/daemon/host.mjs +0 -118
  696. package/src/daemon/mcp-transport.mjs +0 -47
  697. package/src/daemon/session.mjs +0 -100
  698. package/src/daemon/thin-client.mjs +0 -71
  699. package/src/daemon/transport.mjs +0 -163
  700. package/src/gateway/claude-current.mjs +0 -255
  701. package/src/gateway/oauth-usage.mjs +0 -598
  702. package/src/gateway/route-meta.mjs +0 -629
  703. package/src/gateway/server.mjs +0 -713
  704. package/src/memory/data/runtime-manifest.json +0 -40
  705. package/src/memory/index.mjs +0 -3332
  706. package/src/memory/lib/core-memory-store.mjs +0 -330
  707. package/src/memory/lib/embedding-provider.mjs +0 -269
  708. package/src/memory/lib/embedding-worker.mjs +0 -323
  709. package/src/memory/lib/memory-cycle1.mjs +0 -645
  710. package/src/memory/lib/memory-cycle2.mjs +0 -1284
  711. package/src/memory/lib/memory-cycle3.mjs +0 -540
  712. package/src/memory/lib/memory-embed.mjs +0 -299
  713. package/src/memory/lib/memory-ops-policy.mjs +0 -190
  714. package/src/memory/lib/memory-recall-store.mjs +0 -638
  715. package/src/memory/lib/memory.mjs +0 -412
  716. package/src/memory/lib/pg/adapter.mjs +0 -308
  717. package/src/memory/lib/pg/process.mjs +0 -360
  718. package/src/memory/lib/pg/supervisor.mjs +0 -396
  719. package/src/memory/lib/runtime-fetcher.mjs +0 -458
  720. package/src/memory/lib/trace-store.mjs +0 -728
  721. package/src/memory/tool-defs.mjs +0 -79
  722. package/src/search/index.mjs +0 -1173
  723. package/src/search/lib/backends/anthropic-oauth.mjs +0 -98
  724. package/src/search/lib/backends/exa.mjs +0 -50
  725. package/src/search/lib/backends/firecrawl.mjs +0 -61
  726. package/src/search/lib/backends/gemini-api.mjs +0 -83
  727. package/src/search/lib/backends/grok-oauth.mjs +0 -86
  728. package/src/search/lib/backends/index.mjs +0 -150
  729. package/src/search/lib/backends/openai-api.mjs +0 -144
  730. package/src/search/lib/backends/openai-oauth.mjs +0 -102
  731. package/src/search/lib/backends/openai-web-search.mjs +0 -76
  732. package/src/search/lib/backends/tavily.mjs +0 -55
  733. package/src/search/lib/backends/xai-api.mjs +0 -113
  734. package/src/search/lib/config.mjs +0 -192
  735. package/src/search/lib/provider-usage.mjs +0 -67
  736. package/src/search/lib/providers.mjs +0 -47
  737. package/src/search/lib/search-intent.mjs +0 -109
  738. package/src/search/lib/setup-handler.mjs +0 -261
  739. package/src/search/lib/web-tools.mjs +0 -1219
  740. package/src/search/tool-defs.mjs +0 -83
  741. package/src/setup/defender-exclusion.mjs +0 -183
  742. package/src/shared/atomic-file.mjs +0 -436
  743. package/src/shared/config.mjs +0 -372
  744. package/src/shared/daemon-recycle.mjs +0 -108
  745. package/src/shared/disable-claude-builtins.mjs +0 -91
  746. package/src/shared/err-text.mjs +0 -12
  747. package/src/shared/llm/http-agent.mjs +0 -123
  748. package/src/shared/open-url.mjs +0 -62
  749. package/src/shared/plugin-paths.mjs +0 -58
  750. package/src/shared/schedules-store.mjs +0 -70
  751. package/src/shared/seed.mjs +0 -161
  752. package/src/shared/user-cwd.mjs +0 -225
  753. package/src/shared/user-data-guard.mjs +0 -244
  754. package/src/status/aggregator.mjs +0 -584
  755. package/src/status/server.mjs +0 -413
  756. package/tools.json +0 -1671
  757. /package/{defaults → src/defaults}/cycle3-review-prompt.md +0 -0
  758. /package/{defaults → src/defaults}/memory-promote-prompt.md +0 -0
  759. /package/{hooks → src/hooks}/lib/permission-rules.cjs +0 -0
  760. /package/{lib → src/lib}/config-cjs.cjs +0 -0
  761. /package/{lib → src/lib}/hook-pipe-path.cjs +0 -0
  762. /package/{lib → src/lib}/mixdog-debug.cjs +0 -0
  763. /package/{lib → src/lib}/text-utils.cjs +0 -0
  764. /package/{rules → src/rules}/bridge/42-cycle3-agent.md +0 -0
  765. /package/src/{agent → runtime/agent}/orchestrator/activity-bus.mjs +0 -0
  766. /package/src/{agent → runtime/agent}/orchestrator/providers/anthropic-betas.mjs +0 -0
  767. /package/src/{agent → runtime/agent}/orchestrator/session/abort-lookup.mjs +0 -0
  768. /package/src/{agent → runtime/agent}/orchestrator/session/cache/scoped-cache-outcome.mjs +0 -0
  769. /package/src/{agent → runtime/agent}/orchestrator/session/cache/util.mjs +0 -0
  770. /package/src/{agent → runtime/agent}/orchestrator/session/read-dedup.mjs +0 -0
  771. /package/src/{agent → runtime/agent}/orchestrator/session/save-session-worker.mjs +0 -0
  772. /package/src/{agent → runtime/agent}/orchestrator/smart-bridge/session-builder.mjs +0 -0
  773. /package/src/{agent → runtime/agent}/orchestrator/tools/bash-policy-scan.mjs +0 -0
  774. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/atomic-write.mjs +0 -0
  775. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/binary-file.mjs +0 -0
  776. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cache-layers.mjs +0 -0
  777. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/cwd-utils.mjs +0 -0
  778. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/device-paths.mjs +0 -0
  779. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diagnostics-tool.mjs +0 -0
  780. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/diff-utils.mjs +0 -0
  781. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/fs-reachability.mjs +0 -0
  782. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/grep-formatting.mjs +0 -0
  783. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/hash-utils.mjs +0 -0
  784. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/list-formatting.mjs +0 -0
  785. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/open-config-tool.mjs +0 -0
  786. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-locks.mjs +0 -0
  787. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/path-utils.mjs +0 -0
  788. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-args.mjs +0 -0
  789. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-batch.mjs +0 -0
  790. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-constants.mjs +0 -0
  791. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image-resize.mjs +0 -0
  792. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-image.mjs +0 -0
  793. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-lines.mjs +0 -0
  794. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-mode-tool.mjs +0 -0
  795. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-range-index.mjs +0 -0
  796. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-ranges.mjs +0 -0
  797. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-special-files.mjs +0 -0
  798. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-tool.mjs +0 -0
  799. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/read-windows.mjs +0 -0
  800. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-analysis.mjs +0 -0
  801. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/shell-output.mjs +0 -0
  802. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-helpers.mjs +0 -0
  803. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/snapshot-validation.mjs +0 -0
  804. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/text-stats.mjs +0 -0
  805. /package/src/{agent → runtime/agent}/orchestrator/tools/builtin/windows-roots.mjs +0 -0
  806. /package/src/{agent → runtime/agent}/orchestrator/tools/code-graph-prewarm-worker.mjs +0 -0
  807. /package/src/{agent → runtime/agent}/orchestrator/tools/env-scrub.mjs +0 -0
  808. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-content-cache.mjs +0 -0
  809. /package/src/{agent → runtime/agent}/orchestrator/tools/mutation-planner.mjs +0 -0
  810. /package/src/{agent → runtime/agent}/orchestrator/tools/next-call-utils.mjs +0 -0
  811. /package/src/{agent → runtime/agent}/orchestrator/tools/result-compression.mjs +0 -0
  812. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-exec-policy.mjs +0 -0
  813. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy-danger-target.mjs +0 -0
  814. /package/src/{agent → runtime/agent}/orchestrator/tools/shell-policy.mjs +0 -0
  815. /package/src/{channels → runtime/channels}/lib/cli-worker-host.mjs +0 -0
  816. /package/src/{channels → runtime/channels}/lib/config-lock.mjs +0 -0
  817. /package/src/{channels → runtime/channels}/lib/event-queue.mjs +0 -0
  818. /package/src/{channels → runtime/channels}/lib/executor.mjs +0 -0
  819. /package/src/{channels → runtime/channels}/lib/format.mjs +0 -0
  820. /package/src/{channels → runtime/channels}/lib/interaction-workflows.mjs +0 -0
  821. /package/src/{channels → runtime/channels}/lib/memory-client.mjs +0 -0
  822. /package/src/{channels → runtime/channels}/lib/session-control.mjs +0 -0
  823. /package/src/{channels → runtime/channels}/lib/settings.mjs +0 -0
  824. /package/src/{channels → runtime/channels}/lib/whisper-server.mjs +0 -0
  825. /package/src/{memory → runtime/memory}/lib/agent-ipc.mjs +0 -0
  826. /package/src/{memory → runtime/memory}/lib/bridge-trace-queries.mjs +0 -0
  827. /package/src/{memory → runtime/memory}/lib/llm-worker-host.mjs +0 -0
  828. /package/src/{memory → runtime/memory}/lib/memory-cycle.mjs +0 -0
  829. /package/src/{memory → runtime/memory}/lib/memory-extraction.mjs +0 -0
  830. /package/src/{memory → runtime/memory}/lib/memory-maintenance-store.mjs +0 -0
  831. /package/src/{memory → runtime/memory}/lib/memory-recall-id-patch.mjs +0 -0
  832. /package/src/{memory → runtime/memory}/lib/memory-recall-read-query.mjs +0 -0
  833. /package/src/{memory → runtime/memory}/lib/memory-recall-scope-filter.mjs +0 -0
  834. /package/src/{memory → runtime/memory}/lib/memory-retrievers.mjs +0 -0
  835. /package/src/{memory → runtime/memory}/lib/memory-score.mjs +0 -0
  836. /package/src/{memory → runtime/memory}/lib/memory-text-utils.mjs +0 -0
  837. /package/src/{memory → runtime/memory}/lib/model-profile.mjs +0 -0
  838. /package/src/{memory → runtime/memory}/lib/project-id-resolver.mjs +0 -0
  839. /package/src/{search → runtime/search}/lib/cache.mjs +0 -0
  840. /package/src/{search → runtime/search}/lib/formatter.mjs +0 -0
  841. /package/src/{search → runtime/search}/lib/state.mjs +0 -0
  842. /package/src/{shared → runtime/shared}/abort-controller.mjs +0 -0
  843. /package/src/{shared → runtime/shared}/llm/cost.mjs +0 -0
  844. /package/src/{shared → runtime/shared}/llm/index.mjs +0 -0
  845. /package/src/{shared → runtime/shared}/llm/pid-cleanup.mjs +0 -0
  846. /package/src/{shared → runtime/shared}/llm/usage-log.mjs +0 -0
  847. /package/src/{shared → runtime/shared}/wsl.mjs +0 -0
@@ -0,0 +1,870 @@
1
+ /**
2
+ * File-based session store.
3
+ * Sessions are saved to disk so CLI and MCP server can share state,
4
+ * and sessions survive server restarts (resume).
5
+ */
6
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, readdirSync, unlinkSync, statSync } from 'fs';
7
+ import * as fsp from 'fs/promises';
8
+ import { randomBytes } from 'crypto';
9
+ import { join } from 'path';
10
+ import { Worker } from 'worker_threads';
11
+ import { getPluginData } from '../config.mjs';
12
+ import { renameWithRetrySync, updateJsonAtomicSync, writeJsonAtomicSync } from '../../../shared/atomic-file.mjs';
13
+
14
+ const _lastSaveError = new Map(); // id -> { message, at }
15
+ const SESSION_SUMMARY_INDEX_VERSION = 1;
16
+
17
+ function _renameWithRetrySync(tmp, target) {
18
+ return renameWithRetrySync(tmp, target);
19
+ }
20
+
21
+ function getStoreDir() {
22
+ const dir = join(getPluginData(), 'sessions');
23
+ if (!existsSync(dir))
24
+ mkdirSync(dir, { recursive: true });
25
+ return dir;
26
+ }
27
+ function sessionPath(id) {
28
+ // Enforce minted session-id shape before using it in a path to prevent
29
+ // `../` traversal. session IDs are generated by createSession as
30
+ // `sess_<timestamp>_<hex>` — reject anything that doesn't match.
31
+ if (!id || typeof id !== 'string' || !/^[A-Za-z0-9_-]+$/.test(id)) {
32
+ throw new Error(`[session-store] invalid session id: ${JSON.stringify(id)}`);
33
+ }
34
+ return join(getStoreDir(), `${id}.json`);
35
+ }
36
+ function summaryIndexPath() {
37
+ const dir = getPluginData();
38
+ mkdirSync(dir, { recursive: true });
39
+ return join(dir, 'session-summaries.json');
40
+ }
41
+ /**
42
+ * Ensure generation/closed defaults on every session object.
43
+ * Older persisted sessions predate these fields; we normalise at load and save.
44
+ */
45
+ function _ensureLifecycleFields(session) {
46
+ if (typeof session.generation !== 'number') session.generation = 0;
47
+ if (typeof session.closed !== 'boolean') session.closed = false;
48
+ if (!Array.isArray(session.messages)) session.messages = [];
49
+ if (!Array.isArray(session.tools)) session.tools = [];
50
+ return session;
51
+ }
52
+
53
+ function _messageText(content) {
54
+ if (typeof content === 'string') return content;
55
+ if (Array.isArray(content)) {
56
+ return content.map((part) => {
57
+ if (typeof part === 'string') return part;
58
+ if (part?.type === 'text') return part.text || '';
59
+ if (typeof part?.text === 'string') return part.text;
60
+ try { return JSON.stringify(part); } catch { return ''; }
61
+ }).filter(Boolean).join('\n');
62
+ }
63
+ if (content && typeof content === 'object') {
64
+ if (typeof content.text === 'string') return content.text;
65
+ try { return JSON.stringify(content); } catch { return ''; }
66
+ }
67
+ return '';
68
+ }
69
+
70
+ function _cleanPreview(text, max = 240) {
71
+ const value = String(text || '').replace(/\s+/g, ' ').trim();
72
+ return value.length > max ? value.slice(0, max).replace(/\s+\S*$/, '').trim() : value;
73
+ }
74
+
75
+ function _isPreviewNoise(text) {
76
+ const value = String(text || '').trim();
77
+ if (!value) return true;
78
+ if (value.startsWith('<system-reminder>')) return true;
79
+ if (/^Reference files:/i.test(value)) return true;
80
+ if (value.includes('<!-- bp3-sentinel -->')) return true;
81
+ return false;
82
+ }
83
+
84
+ function _sessionPreview(session) {
85
+ const messages = Array.isArray(session?.messages) ? session.messages : [];
86
+ let first = '';
87
+ for (const m of messages) {
88
+ if (m?.role !== 'user') continue;
89
+ const text = _cleanPreview(_messageText(m.content));
90
+ if (_isPreviewNoise(text)) continue;
91
+ if (!first) first = text;
92
+ }
93
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
94
+ const m = messages[i];
95
+ if (m?.role !== 'user') continue;
96
+ const text = _cleanPreview(_messageText(m.content));
97
+ if (_isPreviewNoise(text)) continue;
98
+ return text || first;
99
+ }
100
+ return first;
101
+ }
102
+
103
+ function _sessionMessageCount(session) {
104
+ const messages = Array.isArray(session?.messages) ? session.messages : [];
105
+ let count = 0;
106
+ for (const m of messages) {
107
+ if (m && (m.role === 'user' || m.role === 'assistant')) count++;
108
+ }
109
+ return count;
110
+ }
111
+
112
+ function _positiveNumber(value, fallback = 0) {
113
+ const n = Number(value);
114
+ return Number.isFinite(n) && n > 0 ? n : fallback;
115
+ }
116
+
117
+ function _sessionSummary(session) {
118
+ if (!session?.id) return null;
119
+ return {
120
+ id: String(session.id),
121
+ updatedAt: _positiveNumber(session.updatedAt, Date.now()),
122
+ createdAt: _positiveNumber(session.createdAt, 0),
123
+ lastHeartbeatAt: _positiveNumber(session.lastHeartbeatAt, 0),
124
+ closed: session.closed === true,
125
+ status: String(session.status || (session.closed === true ? 'closed' : 'idle')),
126
+ owner: session.owner || 'user',
127
+ role: session.role || null,
128
+ sourceType: session.sourceType || null,
129
+ sourceName: session.sourceName || null,
130
+ scopeKey: session.scopeKey || null,
131
+ ownerSessionId: session.ownerSessionId || null,
132
+ clientHostPid: _positiveNumber(session.clientHostPid, 0) || null,
133
+ cwd: session.cwd || '',
134
+ provider: session.provider || null,
135
+ model: session.model || null,
136
+ bridgeTag: session.bridgeTag || null,
137
+ task_id: session.task_id || session.taskId || null,
138
+ permission: session.permission || null,
139
+ toolPermission: session.toolPermission || null,
140
+ messageCount: _sessionMessageCount(session),
141
+ preview: _sessionPreview(session),
142
+ generation: typeof session.generation === 'number' ? session.generation : 0,
143
+ implicitBashSessionId: session.implicitBashSessionId || null,
144
+ };
145
+ }
146
+
147
+ function _normalizeSummaryRow(row) {
148
+ if (!row?.id || typeof row.id !== 'string' || !/^[A-Za-z0-9_-]+$/.test(row.id)) return null;
149
+ return {
150
+ id: row.id,
151
+ updatedAt: _positiveNumber(row.updatedAt, 0),
152
+ createdAt: _positiveNumber(row.createdAt, 0),
153
+ lastHeartbeatAt: _positiveNumber(row.lastHeartbeatAt, 0),
154
+ closed: row.closed === true,
155
+ status: String(row.status || (row.closed === true ? 'closed' : 'idle')),
156
+ owner: row.owner || 'user',
157
+ role: row.role || null,
158
+ sourceType: row.sourceType || null,
159
+ sourceName: row.sourceName || null,
160
+ scopeKey: row.scopeKey || null,
161
+ ownerSessionId: row.ownerSessionId || null,
162
+ clientHostPid: _positiveNumber(row.clientHostPid, 0) || null,
163
+ cwd: row.cwd || '',
164
+ provider: row.provider || null,
165
+ model: row.model || null,
166
+ bridgeTag: row.bridgeTag || null,
167
+ task_id: row.task_id || null,
168
+ permission: row.permission || null,
169
+ toolPermission: row.toolPermission || null,
170
+ messageCount: Math.max(0, Math.floor(Number(row.messageCount) || 0)),
171
+ preview: _cleanPreview(row.preview || ''),
172
+ generation: typeof row.generation === 'number' ? row.generation : 0,
173
+ implicitBashSessionId: row.implicitBashSessionId || null,
174
+ };
175
+ }
176
+
177
+ function _normalizeSummaryIndex(raw) {
178
+ const rows = Array.isArray(raw?.rows) ? raw.rows.map(_normalizeSummaryRow).filter(Boolean) : [];
179
+ rows.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
180
+ return { version: SESSION_SUMMARY_INDEX_VERSION, updatedAt: _positiveNumber(raw?.updatedAt, 0), rows };
181
+ }
182
+
183
+ function _writeSummaryIndex(rows) {
184
+ const cleanRows = (rows || []).map(_normalizeSummaryRow).filter(Boolean)
185
+ .sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
186
+ writeJsonAtomicSync(summaryIndexPath(), {
187
+ version: SESSION_SUMMARY_INDEX_VERSION,
188
+ updatedAt: Date.now(),
189
+ rows: cleanRows,
190
+ }, { compact: true, lock: true });
191
+ return cleanRows;
192
+ }
193
+
194
+ function _upsertSessionSummary(session) {
195
+ const row = _sessionSummary(session);
196
+ if (!row) return;
197
+ try {
198
+ updateJsonAtomicSync(summaryIndexPath(), (cur) => {
199
+ const index = _normalizeSummaryIndex(cur);
200
+ const rows = index.rows.filter((r) => r.id !== row.id);
201
+ const cleanRow = _normalizeSummaryRow(row);
202
+ if (!cleanRow) return undefined;
203
+ const existing = index.rows.find((r) => r.id === row.id) || null;
204
+ if (existing && JSON.stringify(existing) === JSON.stringify(cleanRow)) return undefined;
205
+ rows.push(cleanRow);
206
+ rows.sort((a, b) => (b.updatedAt || 0) - (a.updatedAt || 0));
207
+ return { version: SESSION_SUMMARY_INDEX_VERSION, updatedAt: Date.now(), rows };
208
+ }, { compact: true, lock: true });
209
+ } catch { /* summary index is best-effort */ }
210
+ }
211
+
212
+ function _removeSessionSummary(id) {
213
+ if (!id) return;
214
+ try {
215
+ updateJsonAtomicSync(summaryIndexPath(), (cur) => {
216
+ const index = _normalizeSummaryIndex(cur);
217
+ const rows = index.rows.filter((r) => r.id !== id);
218
+ if (rows.length === index.rows.length) return undefined;
219
+ return { version: SESSION_SUMMARY_INDEX_VERSION, updatedAt: Date.now(), rows };
220
+ }, { compact: true, lock: true });
221
+ } catch { /* summary index is best-effort */ }
222
+ }
223
+
224
+ /** Module-level map tracking in-flight saves per session ID to prevent concurrent write corruption. */
225
+ const _savePending = new Map();
226
+
227
+ /** Same-process authoritative session snapshots (createSession → loadSession / askSession). */
228
+ const _liveSessions = new Map();
229
+
230
+ export function setLiveSession(session) {
231
+ if (!session?.id) return;
232
+ _liveSessions.set(session.id, session);
233
+ }
234
+
235
+ function _clearLiveSession(id) {
236
+ if (id) _liveSessions.delete(id);
237
+ }
238
+
239
+ // ── Heartbeat publish ─────────────────────────────────────
240
+ // Lightweight per-session timestamp file (`<id>.hb`) consumed by the
241
+ // status aggregator for fresh-session detection. Decoupled from the
242
+ // full session JSON save so it can fire at a tight cadence (≤5s)
243
+ // without serialising the whole payload. The .hb file holds a single
244
+ // ASCII line: `<msTimestamp>\n`. Aggregator scans the same sessions/
245
+ // directory and matches `<id>.hb` to `<id>.json`.
246
+ const _HEARTBEAT_THROTTLE_MS = 5_000;
247
+ const _hbLastAt = new Map();
248
+
249
+ function _heartbeatPath(id) {
250
+ if (!id || typeof id !== 'string' || !/^[A-Za-z0-9_-]+$/.test(id)) {
251
+ throw new Error(`[session-store] invalid session id: ${JSON.stringify(id)}`);
252
+ }
253
+ return join(getStoreDir(), `${id}.hb`);
254
+ }
255
+
256
+ export function publishHeartbeat(id, ts) {
257
+ if (!id) return;
258
+ const now = ts || Date.now();
259
+ const last = _hbLastAt.get(id) || 0;
260
+ if (now - last < _HEARTBEAT_THROTTLE_MS) return;
261
+ const target = _heartbeatPath(id);
262
+ _hbLastAt.set(id, now);
263
+ void fsp.writeFile(target, `${now}\n`, 'utf8').catch(() => {});
264
+ }
265
+
266
+ export function deleteHeartbeat(id) {
267
+ try { unlinkSync(_heartbeatPath(id)); } catch { /* ignore */ }
268
+ _hbLastAt.delete(id);
269
+ }
270
+ const _deleteHeartbeat = deleteHeartbeat;
271
+
272
+ // ── 150 ms debounce window ────────────────────────────────────────────────────
273
+ // Multiple tool-result writes within a turn collapse to one tmp+rename per
274
+ // session. The timer is unref'd so it never keeps the process alive.
275
+ const _debounceTimers = new Map(); // id → NodeJS.Timeout
276
+ function _clearDebounce(id) {
277
+ const t = _debounceTimers.get(id);
278
+ if (t) { clearTimeout(t); _debounceTimers.delete(id); }
279
+ }
280
+
281
+ // Flush all debounced sessions synchronously on process exit / SIGTERM.
282
+ // This prevents losing the last turn's tool-result writes.
283
+ function _drainAllDebounced() {
284
+ for (const [id, t] of _debounceTimers) {
285
+ clearTimeout(t);
286
+ _debounceTimers.delete(id);
287
+ const cur = _savePending.get(id);
288
+ if (cur && cur.debouncing && cur.payload) {
289
+ try { _doSaveSync(cur.payload); } catch { /* best-effort */ }
290
+ _savePending.delete(id);
291
+ }
292
+ }
293
+ }
294
+ // Self-registered exit drain; bare 'exit' hook stays as idempotent backup. Use the more comprehensive
295
+ // drainSessionStore so debounce + scheduled + writing payloads all flush.
296
+ process.on('exit', drainSessionStore);
297
+
298
+ /**
299
+ * Persist a session. `opts.expectedGeneration` guards against resurrecting a
300
+ * session that was closed mid-flight: before the rename, we re-read the file
301
+ * on disk and, if it's already marked closed with a >= generation, drop the
302
+ * write. `opts.allowClosed=true` is used by `markSessionClosed` itself when
303
+ * writing the tombstone.
304
+ */
305
+ export function saveSession(session, opts) {
306
+ _ensureLifecycleFields(session);
307
+ const id = session.id;
308
+ setLiveSession(session);
309
+ const payload = { session, opts: opts || null };
310
+ // Synchronous durability path — explicit flush (tombstones, drain hooks).
311
+ // createSession uses async debounced save + _liveSessions for same-process
312
+ // read-your-writes; sync remains for callers that require immediate disk.
313
+ if (opts?.sync) {
314
+ _doSaveSync(payload);
315
+ return;
316
+ }
317
+ // Immediate-flush override: tombstone plants and explicit flushes skip the
318
+ // debounce so close-session writes are always durable.
319
+ if (opts?.immediate) {
320
+ _clearDebounce(id);
321
+ const pending = _savePending.get(id);
322
+ if (pending) {
323
+ if (pending.writing) {
324
+ _savePending.set(id, { ...pending, queued: payload });
325
+ } else {
326
+ _savePending.set(id, { ...pending, payload });
327
+ _flushScheduled(id);
328
+ }
329
+ } else {
330
+ _savePending.set(id, { writing: true });
331
+ _doSave(payload).catch(err => {
332
+ process.stderr.write(`[session-store] save failed: ${err?.message}\n`);
333
+ _lastSaveError.set(id, { message: err?.message ?? String(err), at: Date.now() });
334
+ });
335
+ }
336
+ return;
337
+ }
338
+ const pending = _savePending.get(id);
339
+ if (pending) {
340
+ if (pending.writing) {
341
+ // Write in flight — overwrite the queued slot. Multiple async
342
+ // saves for the same id while one is on disk collapse into a
343
+ // single follow-up write.
344
+ _savePending.set(id, { ...pending, queued: payload });
345
+ } else if (pending.scheduled) {
346
+ // setImmediate already scheduled — coalesce into the same tick
347
+ // by overwriting the pending payload with the latest state.
348
+ _savePending.set(id, { scheduled: true, payload });
349
+ } else if (pending.debouncing) {
350
+ // 150 ms debounce window active — overwrite payload, timer keeps running.
351
+ _savePending.set(id, { debouncing: true, payload });
352
+ }
353
+ return;
354
+ }
355
+ // First save for this id — open a 150 ms debounce window. Any additional
356
+ // calls within the window overwrite the payload; only one tmp+rename fires.
357
+ // The setImmediate inside the timeout body provides the original coalescing
358
+ // guarantee within the same event-loop tick at the moment the timer fires.
359
+ _savePending.set(id, { debouncing: true, payload });
360
+ const t = setTimeout(() => {
361
+ _debounceTimers.delete(id);
362
+ const cur = _savePending.get(id);
363
+ if (!cur || !cur.debouncing) return; // already handled (writing/queued)
364
+ _savePending.set(id, { scheduled: true, payload: cur.payload });
365
+ setImmediate(() => _flushScheduled(id));
366
+ }, 150);
367
+ if (t.unref) t.unref();
368
+ _debounceTimers.set(id, t);
369
+ }
370
+
371
+ function _flushScheduled(id) {
372
+ const cur = _savePending.get(id);
373
+ if (!cur || !cur.scheduled) return;
374
+ _savePending.set(id, { writing: true, payload: cur.payload });
375
+ _doSave(cur.payload).catch(err => {
376
+ process.stderr.write(`[session-store] save failed: ${err?.message}\n`);
377
+ _lastSaveError.set(id, { message: err?.message ?? String(err), at: Date.now() });
378
+ });
379
+ }
380
+
381
+ // ── Worker-thread async save ──────────────────────────────────────────────────
382
+ // Single long-lived Worker serializes all saveSessionAsync calls.
383
+ // The worker's message queue preserves generation-race ordering.
384
+ let _saveWorker = null;
385
+ let _saveWorkerPending = new Map(); // reqId → { resolve, reject, session, opts }
386
+ let _saveWorkerReqId = 0;
387
+ let _saveWorkerRefCount = 0;
388
+
389
+ function _getOrSpawnWorker() {
390
+ if (_saveWorker) return _saveWorker;
391
+ _saveWorker = new Worker(new URL('./save-session-worker.mjs', import.meta.url), {
392
+ execArgv: [],
393
+ });
394
+ _saveWorker.on('message', ({ ok, error, reqId }) => {
395
+ const p = _saveWorkerPending.get(reqId);
396
+ if (!p) return;
397
+ _saveWorkerPending.delete(reqId);
398
+ // Drop the ref AFTER pending was registered ref-up'd so the worker
399
+ // becomes unref'd again once all in-flight writes settle. _saveWorker
400
+ // null-check covers the error/exit race where the worker died first.
401
+ if (--_saveWorkerRefCount === 0 && _saveWorker) _saveWorker.unref();
402
+ if (ok) p.resolve();
403
+ else p.reject(new Error(`[session-store] worker save failed: ${error}`));
404
+ });
405
+ _saveWorker.on('error', (err) => {
406
+ for (const [, p] of _saveWorkerPending) p.reject(err);
407
+ _saveWorkerPending.clear();
408
+ _saveWorkerRefCount = 0;
409
+ _saveWorker = null;
410
+ });
411
+ _saveWorker.on('exit', (code) => {
412
+ // Reject pending resolvers on ANY exit (code 0 included) so an idle
413
+ // worker that races a pending postMessage cannot leak resolvers. The
414
+ // map is empty on the normal idle-exit path so the loop is a no-op,
415
+ // but it remains safe for the race window where exit fires after
416
+ // saveSessionAsync registered a resolver but before the worker
417
+ // received the message.
418
+ const err = new Error(`[session-store] save worker exited with code ${code}`);
419
+ for (const [, p] of _saveWorkerPending) p.reject(err);
420
+ _saveWorkerPending.clear();
421
+ _saveWorkerRefCount = 0;
422
+ _saveWorker = null;
423
+ });
424
+ _saveWorker.unref(); // don't keep process alive
425
+ return _saveWorker;
426
+ }
427
+
428
+ /**
429
+ * Async save via a dedicated Worker thread.
430
+ * Errors surface as thrown Errors — callers must not silently swallow them.
431
+ */
432
+ export function saveSessionAsync(session, opts) {
433
+ _ensureLifecycleFields(session);
434
+ setLiveSession(session);
435
+ const reqId = ++_saveWorkerReqId;
436
+ const safeOpts = opts || null;
437
+ return new Promise((resolve, reject) => {
438
+ // Persist {session, opts} so drainSessionStore can sync-flush
439
+ // outstanding writes if process exit interrupts the worker queue.
440
+ _saveWorkerPending.set(reqId, { resolve, reject, session, opts: safeOpts });
441
+ try {
442
+ const w = _getOrSpawnWorker();
443
+ w.postMessage({ session, opts: safeOpts, reqId });
444
+ // Ref AFTER successful postMessage so a queue/throw failure path
445
+ // does not leave the worker held alive with no pending message.
446
+ // Paired with the unref in the message handler when count hits 0.
447
+ if (++_saveWorkerRefCount === 1) w.ref();
448
+ } catch (err) {
449
+ _saveWorkerPending.delete(reqId);
450
+ reject(err);
451
+ }
452
+ });
453
+ }
454
+
455
+ /**
456
+ * Exported for save-session-worker — not part of the public API.
457
+ * External callers should use saveSession / saveSessionAsync.
458
+ */
459
+ export function _saveSessionSync(session, opts) {
460
+ _ensureLifecycleFields(session);
461
+ _doSaveSync({ session, opts: opts || null });
462
+ }
463
+
464
+ function _doSaveSync(payload) {
465
+ const { session, opts } = payload;
466
+ const id = session.id;
467
+ if (_shouldDrop(id, opts)) return;
468
+ const target = sessionPath(id);
469
+ const tmp = target + '.' + randomBytes(6).toString('hex') + '.tmp';
470
+ try {
471
+ writeFileSync(tmp, JSON.stringify(session), 'utf-8');
472
+ if (_shouldDrop(id, opts)) {
473
+ try { unlinkSync(tmp); } catch { /* ignore cleanup failure */ }
474
+ return;
475
+ }
476
+ _renameWithRetrySync(tmp, target);
477
+ _upsertSessionSummary(session);
478
+ } catch (err) {
479
+ try { unlinkSync(tmp); } catch { /* ignore cleanup failure */ }
480
+ throw err;
481
+ }
482
+ }
483
+
484
+ function _shouldDrop(id, opts) {
485
+ if (!opts || opts.allowClosed) return false;
486
+ const expected = typeof opts.expectedGeneration === 'number' ? opts.expectedGeneration : null;
487
+ if (expected === null) return false;
488
+ // Re-read current tombstone state from disk. If the session is closed with
489
+ // a generation >= expected, our write is stale — drop it.
490
+ const target = sessionPath(id);
491
+ if (!existsSync(target)) return false;
492
+ try {
493
+ const onDisk = JSON.parse(readFileSync(target, 'utf-8'));
494
+ const diskGen = typeof onDisk.generation === 'number' ? onDisk.generation : 0;
495
+ return onDisk.closed === true && diskGen >= expected;
496
+ } catch {
497
+ return false;
498
+ }
499
+ }
500
+
501
+ /** Sync-flush every pending save on exit; per-entry catch matches _flushScheduled. */
502
+ export function drainSessionStore() {
503
+ for (const t of _debounceTimers.values()) clearTimeout(t);
504
+ _debounceTimers.clear();
505
+ for (const [, pending] of _savePending) {
506
+ if (!pending.payload) continue;
507
+ try {
508
+ _doSaveSync(pending.payload);
509
+ } catch (err) {
510
+ process.stderr.write(`[session-store] drain save failed: ${err?.message}\n`);
511
+ }
512
+ }
513
+ _savePending.clear();
514
+ // Outstanding worker-queue writes: process exit may interrupt the worker
515
+ // thread before it processes its message queue, so each pending payload
516
+ // is sync-flushed directly here. The Promise is then rejected so the
517
+ // caller's await site does not leak unresolved (caller is at process
518
+ // exit so the rejection is informational, not actionable).
519
+ for (const [, pending] of _saveWorkerPending) {
520
+ if (!pending.session) continue;
521
+ try {
522
+ _saveSessionSync(pending.session, pending.opts);
523
+ } catch (err) {
524
+ process.stderr.write(`[session-store] drain worker-queue save failed: ${err?.message}\n`);
525
+ }
526
+ try {
527
+ pending.reject(new Error('[session-store] drain: worker-queue interrupted by process exit'));
528
+ } catch { /* best-effort */ }
529
+ }
530
+ _saveWorkerPending.clear();
531
+ _saveWorkerRefCount = 0;
532
+ }
533
+
534
+ function _drainQueue(id) {
535
+ const pending = _savePending.get(id);
536
+ if (pending && pending.queued) {
537
+ const next = pending.queued;
538
+ _savePending.set(id, { writing: true, payload: next });
539
+ _doSave(next).catch(err => {
540
+ process.stderr.write(`[session-store] save failed: ${err?.message}\n`);
541
+ _lastSaveError.set(id, { message: err?.message ?? String(err), at: Date.now() });
542
+ });
543
+ } else {
544
+ _savePending.delete(id);
545
+ }
546
+ }
547
+
548
+ async function _doSave(payload) {
549
+ const { session, opts } = payload;
550
+ const id = session.id;
551
+ // First check: upfront, before any disk I/O. Cheap short-circuit when a
552
+ // tombstone is already on disk when the caller arrives.
553
+ if (_shouldDrop(id, opts)) {
554
+ _drainQueue(id);
555
+ return;
556
+ }
557
+ const target = sessionPath(id);
558
+ const tmp = target + '.' + randomBytes(6).toString('hex') + '.tmp';
559
+ try {
560
+ await fsp.writeFile(tmp, JSON.stringify(session), 'utf-8');
561
+ // Second check: between the temp write and the rename, closeSession()
562
+ // may have planted a tombstone. Re-check on disk; if a newer tombstone
563
+ // now exists, discard our temp file rather than let rename clobber it.
564
+ if (_shouldDrop(id, opts)) {
565
+ try { unlinkSync(tmp); } catch { /* ignore cleanup failure */ }
566
+ process.stderr.write(`[session-store] ${id}: dropped stale save (tombstone planted during write)\n`);
567
+ _drainQueue(id);
568
+ return;
569
+ }
570
+ _renameWithRetrySync(tmp, target);
571
+ _upsertSessionSummary(session);
572
+ } catch (err) {
573
+ try { unlinkSync(tmp); } catch { /* ignore cleanup failure */ }
574
+ _savePending.delete(id);
575
+ throw err;
576
+ }
577
+ _drainQueue(id);
578
+ }
579
+
580
+ /**
581
+ * Atomically mark a session closed on disk with a bumped generation.
582
+ * Returns the new generation, or null if the session file doesn't exist.
583
+ * Used by closeSession() to plant a tombstone that races against in-flight
584
+ * saveSession() calls.
585
+ */
586
+ export function markSessionClosed(id, reason = 'manual') {
587
+ // Cancel any pending debounced save so it cannot overwrite the tombstone
588
+ // that we are about to plant. The _shouldDrop() guard inside _doSave()
589
+ // provides a second line of defence, but cancelling here is cheaper.
590
+ _clearDebounce(id);
591
+ const existing = loadSession(id);
592
+ if (!existing) return null;
593
+ const newGen = (typeof existing.generation === 'number' ? existing.generation : 0) + 1;
594
+ const tombstone = { ...existing, closed: true, closedReason: reason, status: 'closed', generation: newGen, updatedAt: Date.now() };
595
+ // Bypass the queue + guard — this IS the tombstone write.
596
+ const target = sessionPath(id);
597
+ const tmp = target + '.' + randomBytes(6).toString('hex') + '.tmp';
598
+ try {
599
+ writeFileSync(tmp, JSON.stringify(tombstone), 'utf-8');
600
+ _renameWithRetrySync(tmp, target);
601
+ } catch {
602
+ try { unlinkSync(tmp); } catch { /* ignore */ }
603
+ return null;
604
+ }
605
+ _savePending.delete(id);
606
+ _clearLiveSession(id);
607
+ _deleteHeartbeat(id);
608
+ _upsertSessionSummary(tombstone);
609
+ // Structured close metric. Single emission point because every close
610
+ // path funnels through markSessionClosed. lifeMs = updatedAt-createdAt
611
+ // straddles the tombstone (updatedAt was just set to Date.now()), so
612
+ // it reflects the session's full lifetime including the close turn.
613
+ try {
614
+ const _dataDir = getPluginData();
615
+ if (_dataDir) {
616
+ const _ts = new Date().toISOString();
617
+ const _lifeMs = (typeof existing.createdAt === 'number' && existing.createdAt > 0)
618
+ ? (tombstone.updatedAt - existing.createdAt)
619
+ : 0;
620
+ const _role = existing.role || '-';
621
+ const _owner = existing.owner || '-';
622
+ void fsp.appendFile(
623
+ join(_dataDir, 'tool-events.log'),
624
+ `[${_ts}] [session-close] owner=${_owner} role=${_role} reason=${reason} lifeMs=${_lifeMs} id=${id}\n`,
625
+ ).catch(() => {});
626
+ }
627
+ } catch { /* logger never breaks the close path */ }
628
+ return newGen;
629
+ }
630
+
631
+ export function loadSession(id) {
632
+ const path = sessionPath(id);
633
+ // Read-your-writes: if a save is pending (debouncing, scheduled, or queued
634
+ // behind an in-flight write) return that payload instead of stale disk state.
635
+ // The most-recently-queued slot is checked first (queued > payload).
636
+ const pending = _savePending.get(id);
637
+ if (pending) {
638
+ const inMemory = (pending.queued || pending.payload)?.session;
639
+ if (inMemory) return _ensureLifecycleFields(inMemory);
640
+ }
641
+ const live = _liveSessions.get(id);
642
+ if (live) return _ensureLifecycleFields(live);
643
+ if (!existsSync(path)) return null;
644
+ try { return _ensureLifecycleFields(JSON.parse(readFileSync(path, 'utf-8'))); }
645
+ catch { return null; }
646
+ }
647
+
648
+ /**
649
+ * Returns the last save error for a session id, or null if no error has occurred.
650
+ * Shape: { message: string, at: number } | null
651
+ */
652
+ export function getSessionSaveError(id) {
653
+ return _lastSaveError.get(id) ?? null;
654
+ }
655
+
656
+ export function clearSessionSaveError(id) {
657
+ _lastSaveError.delete(id);
658
+ }
659
+
660
+ export function deleteSession(id) {
661
+ const path = sessionPath(id);
662
+ let removed = false;
663
+ if (existsSync(path)) {
664
+ try {
665
+ unlinkSync(path);
666
+ removed = true;
667
+ }
668
+ catch { /* fall through to .hb cleanup */ }
669
+ }
670
+ _deleteHeartbeat(id);
671
+ if (removed) _removeSessionSummary(id);
672
+ return removed;
673
+ }
674
+ const DEFAULT_SESSION_TTL_MS = 5 * 60 * 1000; // 5 minutes idle — aligned with Anthropic 5m messages tier and OpenAI in-memory cache window
675
+ // Completed bridge agents (idle/done/error) live until terminal reap — must
676
+ // match TERMINAL_REAP_MS / _scheduleBridgeReap (3_600_000) in index.mjs and
677
+ // bridge-stall-watchdog.mjs so the store sweep is the durable 1h reaper.
678
+ const BRIDGE_TERMINAL_TTL_MS = 60 * 60 * 1000;
679
+ const BRIDGE_TERMINAL_STATUSES = new Set(['idle', 'done', 'error']);
680
+ // Hard wall-clock ceiling for sessions stuck in status='running'. The
681
+ // stream-watchdog should abort stalled streams within ~120s, but if it misses
682
+ // one (process crash, watchdog not started, provider never returned), this
683
+ // backstop reclaims the file so the sweep doesn't leak zombies indefinitely.
684
+ const RUNNING_STALL_MS = 10 * 60 * 1000;
685
+
686
+ export function listStoredSessions() {
687
+ const dir = getStoreDir();
688
+ if (!existsSync(dir))
689
+ return [];
690
+ const files = readdirSync(dir).filter(f => f.endsWith('.json'));
691
+ const sessions = [];
692
+ for (const f of files) {
693
+ try {
694
+ const session = _ensureLifecycleFields(JSON.parse(readFileSync(join(dir, f), 'utf-8')));
695
+ sessions.push(session);
696
+ }
697
+ catch { /* skip corrupt */ }
698
+ }
699
+ return sessions.sort((a, b) => b.updatedAt - a.updatedAt);
700
+ }
701
+
702
+ export function rebuildSessionSummaryIndex() {
703
+ const rows = listStoredSessions().map(_sessionSummary).filter(Boolean);
704
+ return _writeSummaryIndex(rows);
705
+ }
706
+
707
+ export function listStoredSessionSummaries(options = {}) {
708
+ const rebuildIfMissing = options.rebuildIfMissing !== false;
709
+ const p = summaryIndexPath();
710
+ if (!existsSync(p)) {
711
+ return rebuildIfMissing ? rebuildSessionSummaryIndex() : [];
712
+ }
713
+ try {
714
+ const index = _normalizeSummaryIndex(JSON.parse(readFileSync(p, 'utf-8')));
715
+ if (index.rows.length > 0) return index.rows;
716
+ const dir = getStoreDir();
717
+ const hasSessionFiles = existsSync(dir) && readdirSync(dir).some((f) => f.endsWith('.json'));
718
+ return hasSessionFiles && rebuildIfMissing ? rebuildSessionSummaryIndex() : index.rows;
719
+ } catch {
720
+ return rebuildIfMissing ? rebuildSessionSummaryIndex() : [];
721
+ }
722
+ }
723
+
724
+ /**
725
+ * Raw directory scan — returns every parseable session file without any
726
+ * TTL-based inline deletion. Callers (e.g. sweepTombstones) need to own the
727
+ * unlink decision and log it themselves.
728
+ */
729
+ export function getStoredSessionsRaw() {
730
+ const dir = getStoreDir();
731
+ if (!existsSync(dir)) return [];
732
+ const files = readdirSync(dir).filter(f => f.endsWith('.json'));
733
+ const sessions = [];
734
+ for (const f of files) {
735
+ try {
736
+ sessions.push(JSON.parse(readFileSync(join(dir, f), 'utf-8')));
737
+ } catch { /* skip corrupt */ }
738
+ }
739
+ return sessions;
740
+ }
741
+
742
+ /**
743
+ * Background sweep: delete session files idle longer than ttlMs.
744
+ * Returns { cleaned, remaining, details } for logging.
745
+ */
746
+ export function sweepStaleSessions(ttlMs, options = {}) {
747
+ if (ttlMs && typeof ttlMs === 'object') {
748
+ options = ttlMs;
749
+ ttlMs = options.ttlMs;
750
+ }
751
+ const maxAge = ttlMs || DEFAULT_SESSION_TTL_MS;
752
+ const sweepIdle = options.sweepIdle !== false;
753
+ const tombstoneMaxAgeMs = Number(options.tombstoneMaxAgeMs);
754
+ const sweepTombstones = Number.isFinite(tombstoneMaxAgeMs) && tombstoneMaxAgeMs > 0;
755
+ const dir = getStoreDir();
756
+ if (!existsSync(dir))
757
+ return { cleaned: 0, remaining: 0, details: [], tombstonesCleaned: 0, tombstoneDetails: [], tombstoneErrors: [] };
758
+ const summaries = listStoredSessionSummaries();
759
+ const now = Date.now();
760
+ let cleaned = 0;
761
+ let remaining = 0;
762
+ let tombstonesCleaned = 0;
763
+ const details = [];
764
+ const tombstoneDetails = [];
765
+ const tombstoneErrors = [];
766
+ for (const row of summaries) {
767
+ try {
768
+ if (!row?.id) continue;
769
+ const jsonPath = sessionPath(row.id);
770
+ if (!existsSync(jsonPath)) {
771
+ _removeSessionSummary(row.id);
772
+ continue;
773
+ }
774
+ let jsonMtime = 0;
775
+ let heartbeatMtime = 0;
776
+ try { jsonMtime = statSync(jsonPath).mtimeMs || 0; } catch {}
777
+ try {
778
+ const hbPath = join(dir, `${row.id}.hb`);
779
+ if (existsSync(hbPath)) heartbeatMtime = statSync(hbPath).mtimeMs || 0;
780
+ } catch { /* .hb unavailable — fall back to JSON fields */ }
781
+ const freshnessGateMs = sweepIdle ? maxAge : (sweepTombstones ? tombstoneMaxAgeMs : 0);
782
+ const newestKnown = Math.max(row.updatedAt || 0, row.lastHeartbeatAt || 0, row.createdAt || 0, jsonMtime, heartbeatMtime);
783
+ if (freshnessGateMs > 0 && newestKnown > 0 && now - newestKnown <= freshnessGateMs) {
784
+ remaining++;
785
+ continue;
786
+ }
787
+ // Already-closed tombstones are handled here before heartbeat
788
+ // sidecar checks; they do not need liveness probing.
789
+ if (row.closed === true || row.status === 'closed') {
790
+ if (sweepTombstones) {
791
+ const updated = Number(row.updatedAt);
792
+ const age = now - updated;
793
+ if (Number.isFinite(updated) && age >= tombstoneMaxAgeMs) {
794
+ try {
795
+ if (deleteSession(row.id)) {
796
+ tombstonesCleaned++;
797
+ tombstoneDetails.push({ id: row.id, ageSeconds: Math.floor(age / 1000) });
798
+ continue;
799
+ }
800
+ } catch (err) {
801
+ tombstoneErrors.push({ id: row.id, message: err?.message || String(err) });
802
+ remaining++;
803
+ continue;
804
+ }
805
+ }
806
+ }
807
+ remaining++;
808
+ continue;
809
+ }
810
+ // Sweep bridge-owned and ownerless (legacy) sessions; skip explicit
811
+ // user sessions before touching heartbeat sidecars.
812
+ if (typeof row.owner === 'string' && row.owner.length > 0 && row.owner !== 'bridge') {
813
+ remaining++;
814
+ continue;
815
+ }
816
+ if (!sweepIdle) {
817
+ remaining++;
818
+ continue;
819
+ }
820
+ // Prefer .hb sidecar mtime — updated at tight cadence (≤5s) without
821
+ // serialising the full JSON, so it reflects true liveness more
822
+ // accurately than the JSON timestamp fields.
823
+ let lastActive = row.lastHeartbeatAt || row.updatedAt || row.createdAt || 0;
824
+ if (heartbeatMtime) lastActive = Math.max(lastActive, heartbeatMtime);
825
+ // Running sessions are normally reaped by the stream-watchdog
826
+ // within ~120s. Skip them here unless they've been silent past
827
+ // RUNNING_STALL_MS, at which point they are treated as zombies.
828
+ if (row.status === 'running' && now - lastActive <= RUNNING_STALL_MS) {
829
+ remaining++;
830
+ continue;
831
+ }
832
+ const isCompletedBridge = row.owner === 'bridge'
833
+ && BRIDGE_TERMINAL_STATUSES.has(row.status);
834
+ const sessionMaxAge = isCompletedBridge ? BRIDGE_TERMINAL_TTL_MS : maxAge;
835
+ if (now - lastActive > sessionMaxAge) {
836
+ try { markSessionClosed(row.id, 'idle-sweep'); }
837
+ catch (err) {
838
+ process.stderr.write(`[session-store] idle-sweep close failed for ${row.id}: ${err?.message}\n`);
839
+ continue;
840
+ }
841
+ cleaned++;
842
+ details.push({
843
+ id: row.id,
844
+ owner: row.owner || 'unknown',
845
+ idleMinutes: Math.round((now - lastActive) / 60000),
846
+ bashSessionId: row.implicitBashSessionId || null,
847
+ });
848
+ } else {
849
+ remaining++;
850
+ }
851
+ }
852
+ catch { /* skip corrupt */ }
853
+ }
854
+ // Orphan .hb reap: a heartbeat sidecar whose .json no longer exists is dead
855
+ // weight once it is also stale (older than maxAge) — the session JSON was
856
+ // swept/closed but the .hb lingered (a pre-fix orphaned heartbeat). The
857
+ // staleness gate avoids nuking the .hb of a session mid-create whose .json
858
+ // write has not landed yet.
859
+ try {
860
+ for (const h of readdirSync(dir).filter(f => f.endsWith('.hb'))) {
861
+ if (existsSync(join(dir, h.replace(/\.hb$/, '.json')))) continue;
862
+ let hbMtime = 0;
863
+ try { hbMtime = statSync(join(dir, h)).mtimeMs; } catch { continue; }
864
+ if (now - hbMtime > maxAge) {
865
+ try { unlinkSync(join(dir, h)); cleaned++; } catch { /* ignore */ }
866
+ }
867
+ }
868
+ } catch { /* dir scan failure — non-fatal */ }
869
+ return { cleaned, remaining, details, tombstonesCleaned, tombstoneDetails, tombstoneErrors };
870
+ }