mixdog 0.7.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 (404) hide show
  1. package/.claude-plugin/marketplace.json +31 -0
  2. package/.claude-plugin/plugin.json +20 -0
  3. package/.gitattributes +34 -0
  4. package/.mcp.json +14 -0
  5. package/ARCHITECTURE.md +77 -0
  6. package/CHANGELOG.md +7 -0
  7. package/CONTRIBUTING.md +45 -0
  8. package/DATA-FLOW.md +79 -0
  9. package/LICENSE +21 -0
  10. package/README.md +389 -0
  11. package/SECURITY.md +138 -0
  12. package/UNINSTALL.md +112 -0
  13. package/agents/maintenance.md +5 -0
  14. package/agents/memory-classification.md +30 -0
  15. package/agents/scheduler-task.md +18 -0
  16. package/agents/webhook-handler.md +27 -0
  17. package/agents/worker.md +24 -0
  18. package/bin/bridge +133 -0
  19. package/bin/statusline-launcher.mjs +78 -0
  20. package/bin/statusline-lib.mjs +550 -0
  21. package/bin/statusline.mjs +607 -0
  22. package/bun.lock +802 -0
  23. package/commands/config.md +16 -0
  24. package/commands/doctor.md +13 -0
  25. package/commands/setup.md +17 -0
  26. package/defaults/cycle3-review-prompt.md +90 -0
  27. package/defaults/hidden-roles.json +65 -0
  28. package/defaults/memory-chunk-prompt.md +63 -0
  29. package/defaults/memory-promote-prompt.md +135 -0
  30. package/defaults/mixdog-config.template.json +27 -0
  31. package/defaults/user-workflow.json +8 -0
  32. package/defaults/user-workflow.md +12 -0
  33. package/hooks/hooks.json +73 -0
  34. package/hooks/lib/active-instance.cjs +77 -0
  35. package/hooks/lib/permission-evaluator.cjs +411 -0
  36. package/hooks/lib/permission-route.cjs +63 -0
  37. package/hooks/lib/permission-rules.cjs +170 -0
  38. package/hooks/lib/settings-loader.cjs +116 -0
  39. package/hooks/post-tool-use.cjs +84 -0
  40. package/hooks/pre-mcp-sandbox.cjs +158 -0
  41. package/hooks/pre-tool-subagent.cjs +253 -0
  42. package/hooks/session-start.cjs +1372 -0
  43. package/hooks/turn-timer.cjs +82 -0
  44. package/lib/claude-md-writer.cjs +386 -0
  45. package/lib/config-cjs.cjs +61 -0
  46. package/lib/hook-pipe-path.cjs +10 -0
  47. package/lib/keychain-cjs.cjs +263 -0
  48. package/lib/plugin-paths.cjs +61 -0
  49. package/lib/rules-builder.cjs +241 -0
  50. package/lib/text-utils.cjs +61 -0
  51. package/native/README.md +117 -0
  52. package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
  53. package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
  54. package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
  55. package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
  56. package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
  57. package/package.json +107 -0
  58. package/prompts/code-review.txt +16 -0
  59. package/prompts/security-audit.txt +17 -0
  60. package/rules/bridge/00-common.md +39 -0
  61. package/rules/bridge/20-skip-protocol.md +18 -0
  62. package/rules/bridge/30-explorer.md +33 -0
  63. package/rules/bridge/40-cycle1-agent.md +52 -0
  64. package/rules/bridge/41-cycle2-agent.md +62 -0
  65. package/rules/bridge/42-cycle3-agent.md +44 -0
  66. package/rules/lead/00-tool-lead.md +61 -0
  67. package/rules/lead/01-general.md +23 -0
  68. package/rules/lead/02-channels.md +49 -0
  69. package/rules/lead/03-team.md +27 -0
  70. package/rules/lead/04-workflow.md +20 -0
  71. package/rules/shared/00-language.md +14 -0
  72. package/rules/shared/01-tool.md +138 -0
  73. package/scripts/bootstrap.mjs +184 -0
  74. package/scripts/bridge-unify-smoke.mjs +308 -0
  75. package/scripts/build-runtime-linux.sh +348 -0
  76. package/scripts/build-runtime-macos.sh +217 -0
  77. package/scripts/build-runtime-windows.ps1 +242 -0
  78. package/scripts/builtin-utils-smoke.mjs +392 -0
  79. package/scripts/check-json.mjs +45 -0
  80. package/scripts/check-syntax-changed.mjs +102 -0
  81. package/scripts/check-syntax.mjs +58 -0
  82. package/scripts/code-graph-batch.test.mjs +33 -0
  83. package/scripts/config-preserve-smoke.mjs +180 -0
  84. package/scripts/doctor.mjs +484 -0
  85. package/scripts/edit-normalize-fuzz.mjs +130 -0
  86. package/scripts/edit-normalize-smoke.mjs +401 -0
  87. package/scripts/edit-operation-smoke.mjs +369 -0
  88. package/scripts/edit2-smoke.mjs +63 -0
  89. package/scripts/fuzzy-e2e.mjs +28 -0
  90. package/scripts/fuzzy-smoke.mjs +26 -0
  91. package/scripts/generate-runtime-manifest.mjs +166 -0
  92. package/scripts/guard-smoke.mjs +66 -0
  93. package/scripts/hidden-role-schema-smoke.mjs +162 -0
  94. package/scripts/hook-routing-smoke.mjs +29 -0
  95. package/scripts/inject-input.ps1 +204 -0
  96. package/scripts/io-complex-smoke.mjs +667 -0
  97. package/scripts/io-explore-bench.mjs +424 -0
  98. package/scripts/io-guardrails-smoke.mjs +205 -0
  99. package/scripts/io-mini-bench-baseline.json +11 -0
  100. package/scripts/io-mini-bench.mjs +216 -0
  101. package/scripts/io-route-harness.mjs +933 -0
  102. package/scripts/io-telemetry-report.mjs +691 -0
  103. package/scripts/mutation-bench.mjs +564 -0
  104. package/scripts/mutation-io-smoke.mjs +1081 -0
  105. package/scripts/native-patch-bridge-smoke.mjs +288 -0
  106. package/scripts/native-patch-smoke.mjs +304 -0
  107. package/scripts/patch-interior-context-smoke.mjs +49 -0
  108. package/scripts/patch-newline-utf8-smoke.mjs +157 -0
  109. package/scripts/perf-hook-smoke.mjs +71 -0
  110. package/scripts/permission-eval-smoke.mjs +426 -0
  111. package/scripts/prep-patch.mjs +53 -0
  112. package/scripts/prep-shim.mjs +96 -0
  113. package/scripts/provider-cache-smoke.mjs +687 -0
  114. package/scripts/report-runtime-health.mjs +132 -0
  115. package/scripts/run-mcp.mjs +1547 -0
  116. package/scripts/salvage-v4a-shatter.test.mjs +58 -0
  117. package/scripts/scoped-cache-io-smoke.mjs +103 -0
  118. package/scripts/shell-policy-round3-smoke.mjs +46 -0
  119. package/scripts/smoke-runtime-negative.ps1 +100 -0
  120. package/scripts/smoke-runtime-negative.sh +95 -0
  121. package/scripts/stall-policy-smoke.mjs +50 -0
  122. package/scripts/start-memory-worker.mjs +23 -0
  123. package/scripts/statusline-launcher-smoke.mjs +82 -0
  124. package/scripts/stress-atomic-write.mjs +1028 -0
  125. package/scripts/test-config-rmw-restore.mjs +122 -0
  126. package/scripts/test-fault-inject.mjs +164 -0
  127. package/scripts/test-large-file.mjs +174 -0
  128. package/scripts/tool-edge-smoke.mjs +209 -0
  129. package/scripts/uninstall.mjs +201 -0
  130. package/scripts/webhook-selfheal-smoke.mjs +29 -0
  131. package/scripts/write-overwrite-guard-smoke.mjs +56 -0
  132. package/server-main.mjs +3055 -0
  133. package/server.mjs +468 -0
  134. package/setup/config-merge.mjs +254 -0
  135. package/setup/install.mjs +120 -0
  136. package/setup/launch-core.mjs +507 -0
  137. package/setup/launch.mjs +101 -0
  138. package/setup/setup-server.mjs +3206 -0
  139. package/setup/setup.html +3693 -0
  140. package/skills/retro-skill-proposer/SKILL.md +92 -0
  141. package/skills/schedule-add/SKILL.md +77 -0
  142. package/skills/setup/SKILL.md +346 -0
  143. package/skills/webhook-add/SKILL.md +81 -0
  144. package/src/agent/bridge-stall-watchdog.mjs +337 -0
  145. package/src/agent/index.mjs +2138 -0
  146. package/src/agent/orchestrator/activity-bus.mjs +38 -0
  147. package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
  148. package/src/agent/orchestrator/bridge-retry.mjs +220 -0
  149. package/src/agent/orchestrator/bridge-trace.mjs +583 -0
  150. package/src/agent/orchestrator/cache-mtime.mjs +58 -0
  151. package/src/agent/orchestrator/config.mjs +358 -0
  152. package/src/agent/orchestrator/context/collect.mjs +651 -0
  153. package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
  154. package/src/agent/orchestrator/drain-registry.mjs +50 -0
  155. package/src/agent/orchestrator/explore-validator.mjs +8 -0
  156. package/src/agent/orchestrator/internal-roles.mjs +118 -0
  157. package/src/agent/orchestrator/internal-tools.mjs +88 -0
  158. package/src/agent/orchestrator/jobs.mjs +116 -0
  159. package/src/agent/orchestrator/mcp/client.mjs +364 -0
  160. package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
  161. package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
  162. package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
  163. package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
  164. package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
  165. package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
  166. package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
  167. package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
  168. package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
  169. package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
  170. package/src/agent/orchestrator/providers/registry.mjs +192 -0
  171. package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
  172. package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
  173. package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
  174. package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
  175. package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
  176. package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
  177. package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
  178. package/src/agent/orchestrator/session/cache/util.mjs +49 -0
  179. package/src/agent/orchestrator/session/loop.mjs +1478 -0
  180. package/src/agent/orchestrator/session/manager.mjs +1975 -0
  181. package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
  182. package/src/agent/orchestrator/session/result-classification.mjs +65 -0
  183. package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
  184. package/src/agent/orchestrator/session/store.mjs +624 -0
  185. package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
  186. package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
  187. package/src/agent/orchestrator/session/trim.mjs +491 -0
  188. package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
  189. package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
  190. package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
  191. package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
  192. package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
  193. package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
  194. package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
  195. package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
  196. package/src/agent/orchestrator/stall-policy.mjs +195 -0
  197. package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
  198. package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
  199. package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
  200. package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
  201. package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
  202. package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
  203. package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
  204. package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
  205. package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
  206. package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
  207. package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
  208. package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
  209. package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
  210. package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
  211. package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
  212. package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
  213. package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
  214. package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
  215. package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
  216. package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
  217. package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
  218. package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
  219. package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
  220. package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
  221. package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
  222. package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
  223. package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
  224. package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
  225. package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
  226. package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
  227. package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
  228. package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
  229. package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
  230. package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
  231. package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
  232. package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
  233. package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
  234. package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
  235. package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
  236. package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
  237. package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
  238. package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
  239. package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
  240. package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
  241. package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
  242. package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
  243. package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
  244. package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
  245. package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
  246. package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
  247. package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
  248. package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
  249. package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
  250. package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
  251. package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
  252. package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
  253. package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
  254. package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
  255. package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
  256. package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
  257. package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
  258. package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
  259. package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
  260. package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
  261. package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
  262. package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
  263. package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
  264. package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
  265. package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
  266. package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
  267. package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
  268. package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
  269. package/src/agent/orchestrator/tools/builtin.mjs +500 -0
  270. package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
  271. package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
  272. package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
  273. package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
  274. package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
  275. package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
  276. package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
  277. package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
  278. package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
  279. package/src/agent/orchestrator/tools/host-input.mjs +204 -0
  280. package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
  281. package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
  282. package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
  283. package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
  284. package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
  285. package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
  286. package/src/agent/orchestrator/tools/patch.mjs +2754 -0
  287. package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
  288. package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
  289. package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
  290. package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
  291. package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
  292. package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
  293. package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
  294. package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
  295. package/src/agent/orchestrator/workflow-store.mjs +93 -0
  296. package/src/agent/tool-defs.mjs +103 -0
  297. package/src/channels/backends/discord.mjs +784 -0
  298. package/src/channels/data/voice-runtime-manifest.json +138 -0
  299. package/src/channels/index.mjs +3229 -0
  300. package/src/channels/lib/cli-worker-host.mjs +12 -0
  301. package/src/channels/lib/config-lock.mjs +13 -0
  302. package/src/channels/lib/config.mjs +292 -0
  303. package/src/channels/lib/drop-trace.mjs +71 -0
  304. package/src/channels/lib/event-pipeline.mjs +81 -0
  305. package/src/channels/lib/event-queue.mjs +345 -0
  306. package/src/channels/lib/executor.mjs +168 -0
  307. package/src/channels/lib/format.mjs +188 -0
  308. package/src/channels/lib/holidays.mjs +138 -0
  309. package/src/channels/lib/hook-pipe-server.mjs +802 -0
  310. package/src/channels/lib/interaction-workflows.mjs +184 -0
  311. package/src/channels/lib/memory-client.mjs +149 -0
  312. package/src/channels/lib/output-forwarder.mjs +765 -0
  313. package/src/channels/lib/runtime-paths.mjs +479 -0
  314. package/src/channels/lib/scheduler.mjs +723 -0
  315. package/src/channels/lib/session-control.mjs +36 -0
  316. package/src/channels/lib/session-discovery.mjs +103 -0
  317. package/src/channels/lib/settings.mjs +11 -0
  318. package/src/channels/lib/state-file.mjs +68 -0
  319. package/src/channels/lib/status-snapshot.mjs +219 -0
  320. package/src/channels/lib/tool-format.mjs +140 -0
  321. package/src/channels/lib/transcript-discovery.mjs +195 -0
  322. package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
  323. package/src/channels/lib/webhook.mjs +1179 -0
  324. package/src/channels/lib/whisper-server.mjs +477 -0
  325. package/src/channels/tool-defs.mjs +170 -0
  326. package/src/daemon/host.mjs +118 -0
  327. package/src/daemon/mcp-transport.mjs +47 -0
  328. package/src/daemon/session.mjs +100 -0
  329. package/src/daemon/thin-client.mjs +71 -0
  330. package/src/daemon/transport.mjs +163 -0
  331. package/src/memory/data/runtime-manifest.json +40 -0
  332. package/src/memory/index.mjs +3305 -0
  333. package/src/memory/lib/agent-ipc.mjs +93 -0
  334. package/src/memory/lib/bridge-trace-queries.mjs +120 -0
  335. package/src/memory/lib/core-memory-store.mjs +330 -0
  336. package/src/memory/lib/embedding-provider.mjs +269 -0
  337. package/src/memory/lib/embedding-worker.mjs +323 -0
  338. package/src/memory/lib/llm-worker-host.mjs +17 -0
  339. package/src/memory/lib/memory-cycle.mjs +11 -0
  340. package/src/memory/lib/memory-cycle1.mjs +641 -0
  341. package/src/memory/lib/memory-cycle2.mjs +1284 -0
  342. package/src/memory/lib/memory-cycle3.mjs +540 -0
  343. package/src/memory/lib/memory-embed.mjs +299 -0
  344. package/src/memory/lib/memory-extraction.mjs +5 -0
  345. package/src/memory/lib/memory-maintenance-store.mjs +32 -0
  346. package/src/memory/lib/memory-ops-policy.mjs +190 -0
  347. package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
  348. package/src/memory/lib/memory-recall-read-query.mjs +7 -0
  349. package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
  350. package/src/memory/lib/memory-recall-store.mjs +621 -0
  351. package/src/memory/lib/memory-retrievers.mjs +112 -0
  352. package/src/memory/lib/memory-score.mjs +71 -0
  353. package/src/memory/lib/memory-text-utils.mjs +58 -0
  354. package/src/memory/lib/memory.mjs +412 -0
  355. package/src/memory/lib/model-profile.mjs +85 -0
  356. package/src/memory/lib/pg/adapter.mjs +308 -0
  357. package/src/memory/lib/pg/process.mjs +360 -0
  358. package/src/memory/lib/pg/supervisor.mjs +396 -0
  359. package/src/memory/lib/project-id-resolver.mjs +86 -0
  360. package/src/memory/lib/runtime-fetcher.mjs +442 -0
  361. package/src/memory/lib/trace-store.mjs +728 -0
  362. package/src/memory/tool-defs.mjs +79 -0
  363. package/src/search/index.mjs +1173 -0
  364. package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
  365. package/src/search/lib/backends/exa.mjs +50 -0
  366. package/src/search/lib/backends/firecrawl.mjs +61 -0
  367. package/src/search/lib/backends/gemini-api.mjs +83 -0
  368. package/src/search/lib/backends/grok-oauth.mjs +86 -0
  369. package/src/search/lib/backends/index.mjs +150 -0
  370. package/src/search/lib/backends/openai-api.mjs +144 -0
  371. package/src/search/lib/backends/openai-oauth.mjs +98 -0
  372. package/src/search/lib/backends/openai-web-search.mjs +76 -0
  373. package/src/search/lib/backends/tavily.mjs +55 -0
  374. package/src/search/lib/backends/xai-api.mjs +113 -0
  375. package/src/search/lib/cache.mjs +131 -0
  376. package/src/search/lib/config.mjs +192 -0
  377. package/src/search/lib/formatter.mjs +115 -0
  378. package/src/search/lib/provider-usage.mjs +67 -0
  379. package/src/search/lib/providers.mjs +47 -0
  380. package/src/search/lib/search-intent.mjs +109 -0
  381. package/src/search/lib/setup-handler.mjs +261 -0
  382. package/src/search/lib/state.mjs +201 -0
  383. package/src/search/lib/web-tools.mjs +1207 -0
  384. package/src/search/tool-defs.mjs +83 -0
  385. package/src/setup/defender-exclusion.mjs +183 -0
  386. package/src/shared/abort-controller.mjs +15 -0
  387. package/src/shared/atomic-file.mjs +420 -0
  388. package/src/shared/config.mjs +350 -0
  389. package/src/shared/daemon-recycle.mjs +108 -0
  390. package/src/shared/disable-claude-builtins.mjs +88 -0
  391. package/src/shared/err-text.mjs +12 -0
  392. package/src/shared/llm/cost.mjs +66 -0
  393. package/src/shared/llm/http-agent.mjs +123 -0
  394. package/src/shared/llm/index.mjs +41 -0
  395. package/src/shared/llm/pid-cleanup.mjs +27 -0
  396. package/src/shared/llm/usage-log.mjs +47 -0
  397. package/src/shared/plugin-paths.mjs +58 -0
  398. package/src/shared/schedules-store.mjs +70 -0
  399. package/src/shared/seed.mjs +119 -0
  400. package/src/shared/user-cwd.mjs +213 -0
  401. package/src/shared/user-data-guard.mjs +238 -0
  402. package/src/status/aggregator.mjs +584 -0
  403. package/src/status/server.mjs +413 -0
  404. package/tools.json +1653 -0
@@ -0,0 +1,583 @@
1
+ import { readFileSync, existsSync, mkdirSync, appendFileSync, statSync, renameSync } from 'fs';
2
+ import { dirname, join } from 'path';
3
+ import { createHash } from 'crypto';
4
+ import os from 'os';
5
+ import { getPluginData } from './config.mjs';
6
+ import { normalizeUsage } from './smart-bridge/cache-obs.mjs';
7
+ import { isInclusiveProvider } from '../../shared/llm/cost.mjs';
8
+ import { countJsonNextCalls } from './tools/next-call-utils.mjs';
9
+
10
+ const WARNED_KEYS = new Set();
11
+
12
+ // ---------------------------------------------------------------------------
13
+ // In-memory buffer + HTTP flush to memory-service /admin/trace-record
14
+ // ---------------------------------------------------------------------------
15
+ let _buffer = [];
16
+ const _BUFFER_MAX = 2000;
17
+ const _FLUSH_INTERVAL_MS = 5000;
18
+ const _FLUSH_BATCH_SIZE = 500;
19
+ let _flushTimer = null;
20
+ let _serviceUrl = null;
21
+ let _flushInFlight = false;
22
+ let _localTracePath = null;
23
+ let _localTraceBuffer = [];
24
+ let _localTraceTimer = null;
25
+ const _LOCAL_TRACE_FLUSH_LINES = 100;
26
+ const _LOCAL_TRACE_FLUSH_MS = 1000;
27
+ const _LOCAL_TRACE_MAX_BYTES = 10 * 1024 * 1024; // 10 MB — rotate to .1 above this.
28
+
29
+ function _rotateLocalTraceIfNeeded(path) {
30
+ try {
31
+ const stat = statSync(path);
32
+ if (stat && stat.size > _LOCAL_TRACE_MAX_BYTES) {
33
+ try { renameSync(path, `${path}.1`); }
34
+ catch (err) {
35
+ warnBridgeOnce('bridge-trace:local-rotate', `[bridge-trace] local rotate failed (${err?.message})`);
36
+ }
37
+ }
38
+ } catch {
39
+ // File missing or unstattable — nothing to rotate.
40
+ }
41
+ }
42
+
43
+ function _resolveLocalTracePath() {
44
+ if (process.env.MIXDOG_BRIDGE_TRACE_LOCAL_DISABLE === '1') return null;
45
+ if (_localTracePath) return _localTracePath;
46
+ try {
47
+ _localTracePath = process.env.MIXDOG_BRIDGE_TRACE_PATH
48
+ || join(getPluginData(), 'history', 'bridge-trace.jsonl');
49
+ // R4 data-at-rest: trace rows may carry tool payloads / prompts;
50
+ // clamp dir to owner-only on POSIX (advisory on Windows).
51
+ mkdirSync(dirname(_localTracePath), { recursive: true, mode: 0o700 });
52
+ return _localTracePath;
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+
58
+ function _appendLocalTrace(row) {
59
+ if (!_resolveLocalTracePath()) return;
60
+ try {
61
+ _localTraceBuffer.push(`${JSON.stringify(row)}\n`);
62
+ if (_localTraceBuffer.length >= _LOCAL_TRACE_FLUSH_LINES) {
63
+ _flushLocalTrace();
64
+ } else if (!_localTraceTimer) {
65
+ _localTraceTimer = setTimeout(_flushLocalTrace, _LOCAL_TRACE_FLUSH_MS);
66
+ _localTraceTimer.unref?.();
67
+ }
68
+ } catch (err) {
69
+ warnBridgeOnce('bridge-trace:local-spool', `[bridge-trace] local spool failed (${err?.message})`);
70
+ }
71
+ }
72
+
73
+ function _flushLocalTrace() {
74
+ if (_localTraceTimer) {
75
+ clearTimeout(_localTraceTimer);
76
+ _localTraceTimer = null;
77
+ }
78
+ if (_localTraceBuffer.length === 0) return;
79
+ const path = _resolveLocalTracePath();
80
+ if (!path) return;
81
+ const chunk = _localTraceBuffer.join('');
82
+ _localTraceBuffer = [];
83
+ try {
84
+ _rotateLocalTraceIfNeeded(path);
85
+ // mode only applies on file creation; existing files keep their mode.
86
+ // Windows ignores POSIX bits — ACL governs there.
87
+ appendFileSync(path, chunk, { encoding: 'utf8', mode: 0o600 });
88
+ } catch (err) {
89
+ warnBridgeOnce('bridge-trace:local-spool', `[bridge-trace] local spool failed (${err?.message})`);
90
+ }
91
+ }
92
+
93
+ try {
94
+ process.on('beforeExit', _flushLocalTrace);
95
+ process.on('exit', _flushLocalTrace);
96
+ } catch {
97
+ // Ignore lifecycle hook failures in embedded runtimes.
98
+ }
99
+
100
+ function _resolveServiceUrl() {
101
+ if (_serviceUrl) return _serviceUrl;
102
+ try {
103
+ const runtimeRoot = process.env.MIXDOG_RUNTIME_ROOT
104
+ ? join(process.env.MIXDOG_RUNTIME_ROOT)
105
+ : join(os.tmpdir(), 'mixdog');
106
+ const activeFile = join(runtimeRoot, 'active-instance.json');
107
+ if (!existsSync(activeFile)) return null;
108
+ const active = JSON.parse(readFileSync(activeFile, 'utf-8'));
109
+ const port = Number(active && active.memory_port);
110
+ if (!Number.isFinite(port) || port <= 0) return null;
111
+ _serviceUrl = `http://127.0.0.1:${port}`;
112
+ return _serviceUrl;
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ async function _flush() {
119
+ _flushTimer = null;
120
+ if (_buffer.length === 0) return;
121
+ if (_flushInFlight) {
122
+ if (!_flushTimer) _flushTimer = setTimeout(_flush, _FLUSH_INTERVAL_MS);
123
+ return;
124
+ }
125
+ _flushInFlight = true;
126
+ try {
127
+ const url = _resolveServiceUrl();
128
+ if (!url) {
129
+ // Service not up yet — keep buffer, retry next timer tick
130
+ if (!_flushTimer) _flushTimer = setTimeout(_flush, _FLUSH_INTERVAL_MS);
131
+ return;
132
+ }
133
+ const batch = _buffer.splice(0, _FLUSH_BATCH_SIZE);
134
+ try {
135
+ const resp = await fetch(`${url}/admin/trace-record`, {
136
+ method: 'POST',
137
+ headers: { 'Content-Type': 'application/json' },
138
+ body: JSON.stringify({ events: batch }),
139
+ signal: AbortSignal.timeout(5000),
140
+ });
141
+ if (!resp.ok) {
142
+ warnBridgeOnce('bridge-trace:flush-error', `[bridge-trace] /admin/trace-record returned ${resp.status} — dropping batch`);
143
+ }
144
+ } catch (err) {
145
+ _serviceUrl = null;
146
+ warnBridgeOnce('bridge-trace:flush-fetch', `[bridge-trace] flush fetch failed (${err?.message}) — dropping batch`);
147
+ }
148
+ if (_buffer.length >= _FLUSH_BATCH_SIZE) {
149
+ // More pending — schedule another flush immediately
150
+ setImmediate(_flush);
151
+ }
152
+ } finally {
153
+ _flushInFlight = false;
154
+ }
155
+ }
156
+
157
+ function _scheduleFlush(immediate = false) {
158
+ if (immediate) {
159
+ if (_flushTimer) { clearTimeout(_flushTimer); _flushTimer = null; }
160
+ setImmediate(_flush);
161
+ } else if (!_flushTimer) {
162
+ _flushTimer = setTimeout(_flush, _FLUSH_INTERVAL_MS);
163
+ }
164
+ }
165
+
166
+ async function drainBridgeTrace() {
167
+ if (!_resolveServiceUrl()) return;
168
+ if (_flushTimer) { clearTimeout(_flushTimer); _flushTimer = null; }
169
+ for (let i = 0; i < 10 && _buffer.length > 0; i++) {
170
+ await _flush();
171
+ }
172
+ }
173
+
174
+ function normalizeSessionId(sessionId) {
175
+ return sessionId ? String(sessionId) : 'no-session';
176
+ }
177
+
178
+ function appendBridgeTrace(record = {}) {
179
+ // Test isolation — when run-all-tests.mjs sets this env, skip entirely.
180
+ if (process.env.MIXDOG_BRIDGE_TRACE_DISABLE === '1') return;
181
+ try {
182
+ // Coerce ts to epoch ms integer at enqueue time
183
+ let ts = record.ts || Date.now();
184
+ if (typeof ts === 'string') ts = Date.parse(ts);
185
+ ts = Number(ts);
186
+ if (!Number.isFinite(ts)) ts = Date.now();
187
+
188
+ const row = {
189
+ ...record,
190
+ ts,
191
+ session_id: record.session_id ?? normalizeSessionId(record.sessionId),
192
+ payload: record.payload ?? {},
193
+ };
194
+ // Drop actor-facing alias to keep schema tidy
195
+ delete row.sessionId;
196
+
197
+ if (_buffer.length >= _BUFFER_MAX) {
198
+ _buffer.shift(); // drop oldest
199
+ warnBridgeOnce('bridge-trace:buffer-full', '[bridge-trace] buffer full (2000) — dropping oldest event');
200
+ }
201
+ _appendLocalTrace(row);
202
+ _buffer.push(row);
203
+ _scheduleFlush(_buffer.length >= _FLUSH_BATCH_SIZE);
204
+ }
205
+ catch {
206
+ // Never break bridge execution for telemetry
207
+ }
208
+ }
209
+
210
+ function estimateProviderPayloadBytes(messages, model, tools) {
211
+ try {
212
+ return Buffer.byteLength(JSON.stringify({ model, messages, tools: tools || [] }), 'utf8');
213
+ }
214
+ catch {
215
+ return null;
216
+ }
217
+ }
218
+
219
+ function extractCachedTokens(usage) {
220
+ const candidates = [
221
+ usage?.input_tokens_details?.cached_tokens,
222
+ usage?.prompt_tokens_details?.cached_tokens,
223
+ usage?.inputTokensDetails?.cachedTokens,
224
+ usage?.promptTokensDetails?.cachedTokens,
225
+ ];
226
+ for (const value of candidates) {
227
+ const n = Number(value);
228
+ if (Number.isFinite(n)) return n;
229
+ }
230
+ return 0;
231
+ }
232
+
233
+ function warnBridgeOnce(key, message) {
234
+ if (!key || WARNED_KEYS.has(key)) return;
235
+ WARNED_KEYS.add(key);
236
+ try {
237
+ process.stderr.write(`${message}\n`);
238
+ }
239
+ catch {
240
+ // Ignore logging failures.
241
+ }
242
+ }
243
+
244
+ function traceBridgeLoop({ sessionId, iteration, sendMs, messageCount, bodyBytesEst }) {
245
+ if (process.env.MIXDOG_BRIDGE_TRACE_VERBOSE !== '1') return;
246
+ appendBridgeTrace({
247
+ sessionId,
248
+ iteration,
249
+ kind: 'loop',
250
+ send_ms: sendMs,
251
+ message_count: messageCount,
252
+ body_bytes_est: bodyBytesEst,
253
+ });
254
+ }
255
+
256
+ // Lightweight fingerprint of the conversation prefix. Hashes the first 4096
257
+ // characters of JSON.stringify(messages) — enough to detect prefix mutation
258
+ // across iterations (which invalidates the provider prompt cache) without
259
+ // hashing megabytes per turn. Truncated SHA1 keeps the trace row compact.
260
+ function messagePrefixHash(messages) {
261
+ try {
262
+ const json = JSON.stringify(messages || []);
263
+ const slice = json.length > 4096 ? json.slice(0, 4096) : json;
264
+ return createHash('sha1').update(slice).digest('hex').slice(0, 12);
265
+ } catch {
266
+ return null;
267
+ }
268
+ }
269
+
270
+ function traceBridgeTrim({
271
+ sessionId,
272
+ iteration,
273
+ prune_count,
274
+ trim_changed,
275
+ input_prefix_hash,
276
+ before_count,
277
+ after_count,
278
+ before_bytes,
279
+ after_bytes,
280
+ }) {
281
+ if (process.env.MIXDOG_BRIDGE_TRACE_VERBOSE !== '1') return;
282
+ appendBridgeTrace({
283
+ sessionId,
284
+ iteration,
285
+ kind: 'trim_meta',
286
+ prune_count: prune_count ?? 0,
287
+ trim_changed: !!trim_changed,
288
+ input_prefix_hash: input_prefix_hash || null,
289
+ before_count: before_count ?? null,
290
+ after_count: after_count ?? null,
291
+ before_bytes: before_bytes ?? null,
292
+ after_bytes: after_bytes ?? null,
293
+ });
294
+ }
295
+
296
+ const TOOL_ARG_KEYS = {
297
+ read: ['path', 'mode', 'n', 'offset', 'limit', 'full'],
298
+ grep: ['pattern', 'path', 'glob', 'output_mode', 'head_limit', 'offset', 'type', '-i', '-n', '-A', '-B', '-C', 'context', 'multiline'],
299
+ glob: ['pattern', 'path', 'head_limit', 'offset'],
300
+ list: ['path', 'mode', 'depth', 'hidden', 'sort', 'type', 'head_limit', 'offset', 'name', 'min_size', 'max_size', 'modified_after', 'modified_before'],
301
+ code_graph: ['mode', 'file', 'symbol', 'language', 'limit'],
302
+ bash: ['command', 'cwd', 'timeout', 'run_in_background', 'persistent', 'session_id'],
303
+ job_wait: ['job_id', 'timeout_ms', 'poll_ms'],
304
+ edit: ['path', 'replace_all', 'edits'],
305
+ edit_many: ['edits'],
306
+ write: ['path', 'writes'],
307
+ apply_patch: ['base_path', 'dry_run', 'reject_partial'],
308
+ };
309
+
310
+ const REDACT_KEY_RE = /token|secret|password|passwd|credential|authorization|api[_-]?key/i;
311
+ const BODY_KEY_RE = /content|old_string|new_string|patch|rewrite/i;
312
+ // Redact bash `command` values that look like they carry secrets. Covers
313
+ // assignment forms, Authorization headers, --password / -p flags, and
314
+ // secrets embedded in URLs (userinfo + query string).
315
+ const SHELL_SECRET_RE = /(?:(?:^|\s)(?:export\s+\w+=\S+|PASSWORD=|SECRET=|TOKEN=|API_KEY=)|Authorization:\s*Bearer\s+\S+|--(?:password|token|secret|api[-_]?key)(?:\s+|=)\S+|(?:^|\s)-p\s+\S+|:\/\/[^:\/\s@]+:[^@\s]+@|[?&](?:token|api[-_]?key|access[-_]?token|auth|password|secret)=[^&\s#]+)/i;
316
+
317
+ function _redactShellCommand(cmd) {
318
+ if (typeof cmd !== 'string') return cmd;
319
+ let out = cmd;
320
+ // Assignment RHS: PASSWORD=, SECRET=, TOKEN=, API_KEY=/APIKEY=.
321
+ out = out.replace(/((?:PASSWORD|SECRET|TOKEN|API_KEY|APIKEY)\s*=\s*)\S+/gi, '$1[redacted]');
322
+ // Authorization: Bearer <token>.
323
+ out = out.replace(/(Authorization:\s*Bearer\s+)\S+/gi, '$1[redacted]');
324
+ // Long flags: --password <v> / --password=<v> (also --token, --secret, --api-key).
325
+ out = out.replace(/(--(?:password|token|secret|api[-_]?key)(?:\s+|=))\S+/gi, '$1[redacted]');
326
+ // Short -p <v> flag (mysql/psql/curl style).
327
+ out = out.replace(/((?:^|\s)-p(?:\s+|=))\S+/g, '$1[redacted]');
328
+ // URL userinfo: scheme://user:secret@host -> scheme://user:[redacted]@host.
329
+ out = out.replace(/(:\/\/[^:\/\s@]+:)[^@\s]+(@)/g, '$1[redacted]$2');
330
+ // URL query params carrying tokens/keys.
331
+ out = out.replace(/([?&](?:token|api[-_]?key|access[-_]?token|auth|password|secret)=)[^&\s#]+/gi, '$1[redacted]');
332
+ return out;
333
+ }
334
+
335
+ function compactTraceArgValue(value, key = '', depth = 0) {
336
+ if (REDACT_KEY_RE.test(key)) return '[redacted]';
337
+ if (value === null || value === undefined) return value;
338
+ if (typeof value === 'string') {
339
+ // Redact shell commands that embed secrets before length-truncating.
340
+ if (key === 'command') {
341
+ value = _redactShellCommand(value);
342
+ }
343
+ const limit = BODY_KEY_RE.test(key) ? 60 : 180;
344
+ return value.length > limit ? `${value.slice(0, limit)}...` : value;
345
+ }
346
+ if (typeof value === 'number' || typeof value === 'boolean') return value;
347
+ if (Array.isArray(value)) {
348
+ if (depth >= 2) return `[${value.length} items]`;
349
+ return value.slice(0, 6).map((v) => compactTraceArgValue(v, key, depth + 1));
350
+ }
351
+ if (typeof value === 'object') {
352
+ if (depth >= 2) return '{...}';
353
+ const out = {};
354
+ for (const [k, v] of Object.entries(value).slice(0, 12)) {
355
+ out[k] = compactTraceArgValue(v, k, depth + 1);
356
+ }
357
+ return out;
358
+ }
359
+ return String(value);
360
+ }
361
+
362
+ function summarizeToolArgs(toolName, args) {
363
+ if (!args || typeof args !== 'object') return null;
364
+ const keys = TOOL_ARG_KEYS[String(toolName || '')] || Object.keys(args).slice(0, 8);
365
+ const out = {};
366
+ for (const key of keys) {
367
+ if (Object.prototype.hasOwnProperty.call(args, key)) out[key] = compactTraceArgValue(args[key], key);
368
+ }
369
+ for (const countKey of ['edits', 'writes']) {
370
+ if (Array.isArray(args[countKey])) out[`${countKey}_count`] = args[countKey].length;
371
+ }
372
+ if (toolName === 'read' && Array.isArray(args.path)) {
373
+ out.path_count = args.path.length;
374
+ }
375
+ return Object.keys(out).length ? out : null;
376
+ }
377
+
378
+ function traceBridgeTool({ sessionId, iteration, toolName, toolKind, toolMs, toolArgs, role, resultKind, model, resultText }) {
379
+ const nextCallCount = countJsonNextCalls(resultText);
380
+ // Flat shape — fields named exactly as the bridge_calls PG columns so
381
+ // insertBridgeCalls can pick them up by direct property access without
382
+ // a payload-unwrap step. result_kind has no column and rides as plain
383
+ // sibling metadata for downstream consumers.
384
+ appendBridgeTrace({
385
+ sessionId,
386
+ iteration,
387
+ kind: 'tool',
388
+ role: role || null,
389
+ model: model || null,
390
+ tool_name: toolName,
391
+ tool_kind: toolKind,
392
+ tool_ms: toolMs,
393
+ tool_args: summarizeToolArgs(toolName, toolArgs),
394
+ result_kind: resultKind || null,
395
+ result_has_next_call: nextCallCount > 0,
396
+ result_next_call_count: nextCallCount,
397
+ result_bytes_est: typeof resultText === 'string' ? Buffer.byteLength(resultText, 'utf8') : 0,
398
+ result_lines_est: typeof resultText === 'string' && resultText.length > 0 ? resultText.split('\n').length : 0,
399
+ });
400
+ }
401
+
402
+ // Compression layer trace (result-compression.mjs). One row per tool call
403
+ // where compression actually changed the byte count, so `gain` analytics
404
+ // can sum savings_pct over a window (mirrors RTK's `rtk gain` model
405
+ // without an external binary). No-op rows are dropped at the call site.
406
+ export function traceBridgeCompress({ sessionId, toolName, before, after }) {
407
+ // bytes_before/after/savings_pct moved into payload because the
408
+ // trace_events table only carries known top-level columns (id, ts,
409
+ // session_id, kind, tool_name, payload, ...) — fields outside that
410
+ // set are silently dropped at insert time. payload is jsonb so any
411
+ // shape survives. Aggregation: SELECT (payload->>'bytes_before')::int.
412
+ appendBridgeTrace({
413
+ sessionId,
414
+ kind: 'compress',
415
+ tool_name: toolName,
416
+ payload: {
417
+ bytes_before: before,
418
+ bytes_after: after,
419
+ savings_pct: before > 0 ? Math.round((1 - after / before) * 100) : 0,
420
+ },
421
+ });
422
+ }
423
+
424
+ // Per-turn batch shape — one row per assistant turn with the number of
425
+ // tool calls observed. Lets a consumer compute Lead-side multi-tool
426
+ // adoption ratio (calls > 1 / total turns) directly from trace rows
427
+ // instead of re-parsing every assistant message body.
428
+ export function traceBridgeBatch({ sessionId, toolCallCount }) {
429
+ appendBridgeTrace({
430
+ sessionId,
431
+ kind: 'batch',
432
+ tool_call_count: toolCallCount,
433
+ });
434
+ }
435
+
436
+ function _sanitizeSample(sample) {
437
+ if (sample == null) return sample;
438
+ if (typeof sample === 'string' || typeof sample === 'object') {
439
+ return compactTraceArgValue(sample, '', 0);
440
+ }
441
+ return sample;
442
+ }
443
+
444
+ function traceStreamStalled({ sessionId, info }) {
445
+ appendBridgeTrace({
446
+ sessionId,
447
+ kind: 'stream_stalled',
448
+ stale_seconds: info.staleSeconds,
449
+ last_tool_call: info.lastToolCall,
450
+ stage: info.stage,
451
+ });
452
+ }
453
+
454
+ function traceStreamAborted({ sessionId, info }) {
455
+ appendBridgeTrace({
456
+ sessionId,
457
+ kind: 'stream_aborted',
458
+ stale_seconds: info.staleSeconds,
459
+ last_tool_call: info.lastToolCall,
460
+ stage: info.stage,
461
+ });
462
+ }
463
+
464
+ function traceBridgePreset({ sessionId, role, presetName, model, provider, parentSessionId }) {
465
+ // Fires once per dispatch right after the preset has been resolved and
466
+ // its runtime spec (provider/model) assembled. Useful for after-the-fact
467
+ // routing analysis: "which role landed on which preset / provider / model
468
+ // on this request?"
469
+ appendBridgeTrace({
470
+ sessionId,
471
+ kind: 'preset_assign',
472
+ role: role || null,
473
+ preset_name: presetName || null,
474
+ model: model || null,
475
+ provider: provider || null,
476
+ parent_session_id: parentSessionId || null,
477
+ });
478
+ }
479
+
480
+ function traceBridgeFetch({ sessionId, headersMs, httpStatus, handshakeRetries, handshakeRetryClassifiers, provider, model, transport }) {
481
+ const payload = {
482
+ headers_ms: headersMs,
483
+ http_status: httpStatus,
484
+ provider: provider || null,
485
+ model: model || null,
486
+ transport: transport || null,
487
+ };
488
+ if (Number.isFinite(Number(handshakeRetries))) {
489
+ payload.handshake_retries = Number(handshakeRetries);
490
+ }
491
+ if (Array.isArray(handshakeRetryClassifiers) && handshakeRetryClassifiers.length > 0) {
492
+ payload.handshake_retry_classifiers = handshakeRetryClassifiers;
493
+ }
494
+ appendBridgeTrace({
495
+ sessionId,
496
+ kind: 'fetch',
497
+ headers_ms: headersMs,
498
+ http_status: httpStatus,
499
+ provider: provider || null,
500
+ model: model || null,
501
+ transport: transport || null,
502
+ handshake_retries: payload.handshake_retries,
503
+ handshake_retry_classifiers: payload.handshake_retry_classifiers,
504
+ payload,
505
+ });
506
+ }
507
+
508
+ function traceBridgeSse({ sessionId, sseParseMs, ttftMs, provider, model, transport }) {
509
+ appendBridgeTrace({
510
+ sessionId,
511
+ kind: 'sse',
512
+ sse_parse_ms: sseParseMs,
513
+ ttft_ms: ttftMs,
514
+ provider: provider || null,
515
+ model: model || null,
516
+ transport: transport || null,
517
+ payload: {
518
+ sse_parse_ms: sseParseMs,
519
+ ttft_ms: ttftMs,
520
+ provider: provider || null,
521
+ model: model || null,
522
+ transport: transport || null,
523
+ },
524
+ });
525
+ }
526
+
527
+ function traceBridgeUsage({ sessionId, iteration, inputTokens, outputTokens, cachedTokens, cacheWriteTokens, promptTokens, model, modelDisplay, responseId, rawUsage, provider, serviceTier }) {
528
+ const inclusive = isInclusiveProvider(provider);
529
+ const inTok = inputTokens || 0;
530
+ const cacheRead = cachedTokens || 0;
531
+ const cacheWrite = cacheWriteTokens || 0;
532
+ const uncachedInputTokens = inclusive ? Math.max(inTok - cacheRead - cacheWrite, 0) : inTok;
533
+ const promptTotal = typeof promptTokens === 'number'
534
+ ? promptTokens
535
+ : (inclusive
536
+ ? Math.max(inTok, cacheRead + cacheWrite)
537
+ : inTok + cacheRead + cacheWrite);
538
+ const resolvedServiceTier = serviceTier || rawUsage?.service_tier || rawUsage?.serviceTier || null;
539
+ appendBridgeTrace({
540
+ sessionId,
541
+ iteration,
542
+ kind: 'usage_raw',
543
+ input_tokens: inputTokens,
544
+ output_tokens: outputTokens,
545
+ cached_tokens: cachedTokens,
546
+ cache_write_tokens: cacheWrite,
547
+ uncached_input_tokens: uncachedInputTokens,
548
+ // Unified total-prompt field. Anthropic = input+cache_read+cache_write,
549
+ // OpenAI/Gemini = input_tokens (cached is already a subset).
550
+ prompt_tokens: promptTotal,
551
+ model: model || null,
552
+ model_display: modelDisplay || null,
553
+ response_id: responseId || null,
554
+ service_tier: resolvedServiceTier,
555
+ payload: {
556
+ provider: provider || null,
557
+ prompt_tokens: promptTotal,
558
+ uncached_input_tokens: uncachedInputTokens,
559
+ model_display: modelDisplay || null,
560
+ response_id: responseId || null,
561
+ service_tier: resolvedServiceTier,
562
+ raw_usage: rawUsage || null,
563
+ },
564
+ });
565
+ }
566
+
567
+ export {
568
+ appendBridgeTrace,
569
+ drainBridgeTrace,
570
+ estimateProviderPayloadBytes,
571
+ extractCachedTokens,
572
+ messagePrefixHash,
573
+ traceBridgeFetch,
574
+ traceBridgeLoop,
575
+ traceBridgePreset,
576
+ traceBridgeSse,
577
+ traceBridgeTool,
578
+ traceBridgeTrim,
579
+ traceBridgeUsage,
580
+ traceStreamAborted,
581
+ traceStreamStalled,
582
+ warnBridgeOnce,
583
+ };
@@ -0,0 +1,58 @@
1
+ import { statSync, readdirSync } from 'fs';
2
+
3
+ /**
4
+ * Return the maximum mtimeMs across all given paths.
5
+ * Missing / unreadable paths are silently skipped (treated as mtime 0).
6
+ * Pass file paths or directory paths; statSync on a directory returns the
7
+ * mtime of the directory entry itself (updated when children are
8
+ * added/removed), while file mtime covers content changes.
9
+ * Use maxMtimeRecursive for cases where file-content edits within a
10
+ * directory must also invalidate the cache (parent dir mtime is unchanged
11
+ * on Linux/macOS when only a file's content changes).
12
+ *
13
+ * @param {string[]} paths
14
+ * @returns {number}
15
+ */
16
+ export function maxMtime(paths) {
17
+ let max = 0;
18
+ for (const p of paths) {
19
+ try { const m = statSync(p).mtimeMs; if (m > max) max = m; } catch { /* missing — skip */ }
20
+ }
21
+ return max;
22
+ }
23
+
24
+ /**
25
+ * Return the maximum mtimeMs across all given paths, recursing into
26
+ * directories up to `depth` levels. Only .md and .json files inside
27
+ * directories contribute their own mtime (not the parent dir entry).
28
+ * Plain file paths are stat'd directly regardless of extension.
29
+ * Missing / unreadable paths are silently skipped.
30
+ *
31
+ * @param {string[]} paths
32
+ * @param {number} [depth=3]
33
+ * @returns {number}
34
+ */
35
+ export function maxMtimeRecursive(paths, depth = 3) {
36
+ let max = 0;
37
+ function walk(p, d) {
38
+ let st;
39
+ try { st = statSync(p); } catch { return; }
40
+ if (st.isDirectory()) {
41
+ if (d <= 0) return;
42
+ let entries;
43
+ try { entries = readdirSync(p, { withFileTypes: true }); } catch { return; }
44
+ for (const e of entries) {
45
+ const child = p + '/' + e.name;
46
+ if (e.isDirectory()) {
47
+ walk(child, d - 1);
48
+ } else if (e.isFile() && (e.name.endsWith('.md') || e.name.endsWith('.json'))) {
49
+ try { const m = statSync(child).mtimeMs; if (m > max) max = m; } catch {}
50
+ }
51
+ }
52
+ } else {
53
+ if (st.mtimeMs > max) max = st.mtimeMs;
54
+ }
55
+ }
56
+ for (const p of paths) walk(p, depth);
57
+ return max;
58
+ }