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,369 @@
1
+ // Smoke test: consolidated `edit` tool operation ROUTING.
2
+ //
3
+ // The `edit` builtin now multiplexes three operations behind one tool:
4
+ // operation: 'replace' (default) -> executeEditTool (text edit engine)
5
+ // operation: 'notebook' -> executeNotebookEditTool (.ipynb cells)
6
+ // operation: 'rename' -> executeRenameTool (graph-based rename)
7
+ //
8
+ // We drive every case through the real dispatch entry `executeBuiltinTool`
9
+ // (src/agent/orchestrator/tools/builtin.mjs), so what gets exercised is the
10
+ // `case 'edit'` routing on args.operation — not the handlers in isolation.
11
+ // Each operation has a handler-EXCLUSIVE output signature, so matching it
12
+ // proves the dispatch routed operation -> handler correctly:
13
+ // • text edit -> "Edited: ..." (only edit-engine emits this)
14
+ // • notebook -> "Updated/Inserted/Deleted cell ..." (only notebook handler)
15
+ // • rename -> JSON { mode:'preview'|'apply', warning:'APPROXIMATE…' }
16
+ //
17
+ // Invariants asserted (not just smoke-imported):
18
+ // 1. operation omitted defaults to replace and edits succeed.
19
+ // 2. operation:'replace' explicit, single + batch edits[].
20
+ // 3. notebook replace resets a code cell's execution_count -> null and
21
+ // clears THAT cell's outputs; insert adds a cell; delete removes one.
22
+ // 4. rename PREVIEW (apply omitted/false) returns change list + APPROXIMATE
23
+ // warning AND writes NO file (temp file byte-identical before/after).
24
+ // 5. rename apply:true renames only find_references-sanctioned code spans;
25
+ // a same-line string/comment occurrence is left untouched.
26
+ // 6. invalid operation 'bogus' -> guard error, nothing mutated.
27
+ // 7. routing: notebook/rename reach their handlers; replace/omitted reach
28
+ // the text-edit path (handler-exclusive output signatures).
29
+
30
+ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
31
+ import { tmpdir } from 'node:os';
32
+ import { dirname, join } from 'node:path';
33
+ import { fileURLToPath, pathToFileURL } from 'node:url';
34
+
35
+ const ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
36
+ // Derive CLAUDE_PLUGIN_DATA from the repo root so the rename case finds the
37
+ // already-cached mixdog-graph binary instead of attempting a network fetch.
38
+ process.env.CLAUDE_PLUGIN_ROOT ||= ROOT;
39
+ process.env.MIXDOG_HINT_LEVEL ||= 'normal';
40
+
41
+ const { executeBuiltinTool } = await import(
42
+ pathToFileURL(join(ROOT, 'src/agent/orchestrator/tools/builtin.mjs')).href
43
+ );
44
+
45
+ const SCOPE = 'edit-op-smoke';
46
+
47
+ let failures = 0;
48
+ function check(label, cond, detail = '') {
49
+ if (!cond) {
50
+ failures++;
51
+ console.error(` FAIL ${label}${detail ? `: ${detail}` : ''}`);
52
+ }
53
+ return cond;
54
+ }
55
+ function caseResult(name, ok) {
56
+ process.stdout.write(`Case ${name}: ${ok ? 'PASS' : 'FAIL'}\n`);
57
+ }
58
+ function isErr(out) {
59
+ return typeof out === 'string' && out.startsWith('Error');
60
+ }
61
+
62
+ // Warm a read snapshot so edit/notebook read-before-write guards are satisfied
63
+ // deterministically (text edits also auto-snapshot, but notebook does not).
64
+ async function warmRead(dir, path, opts = {}) {
65
+ return executeBuiltinTool('read', { path, ...opts }, dir, {
66
+ readStateScope: SCOPE,
67
+ mediaTextOnly: true,
68
+ });
69
+ }
70
+
71
+ function makeNotebook() {
72
+ return {
73
+ cells: [
74
+ {
75
+ cell_type: 'code',
76
+ id: 'cellA',
77
+ metadata: {},
78
+ execution_count: 7,
79
+ outputs: [{ output_type: 'stream', name: 'stdout', text: ['old output\n'] }],
80
+ source: ['print("old")\n'],
81
+ },
82
+ {
83
+ cell_type: 'markdown',
84
+ id: 'cellB',
85
+ metadata: {},
86
+ source: ['# heading\n'],
87
+ },
88
+ {
89
+ cell_type: 'code',
90
+ id: 'cellC',
91
+ metadata: {},
92
+ execution_count: 3,
93
+ outputs: [],
94
+ source: ['x = 1\n'],
95
+ },
96
+ ],
97
+ metadata: {},
98
+ nbformat: 4,
99
+ nbformat_minor: 5,
100
+ };
101
+ }
102
+
103
+ const RENAME_SOURCE = [
104
+ 'const widget = 1;',
105
+ 'export function getWidget() {',
106
+ ' return widget; // widget label retained',
107
+ '}',
108
+ 'const note = "widget literal stays";',
109
+ '',
110
+ ].join('\n');
111
+
112
+ const dir = await mkdtemp(join(tmpdir(), 'mixdog-edit-op-smoke-'));
113
+ const renameDir = await mkdtemp(join(tmpdir(), 'mixdog-edit-op-rename-'));
114
+
115
+ async function rmTree(p) {
116
+ await rm(p, { recursive: true, force: true, maxRetries: 5, retryDelay: 50 });
117
+ }
118
+
119
+ try {
120
+ // ── Case 1: operation omitted -> defaults to replace ────────────────────
121
+ {
122
+ const file = 'c1.txt';
123
+ await writeFile(join(dir, file), 'const a = 1;\n', 'utf8');
124
+ await warmRead(dir, file);
125
+ const out = await executeBuiltinTool('edit', {
126
+ path: file,
127
+ old_string: 'const a = 1;',
128
+ new_string: 'const a = 2;',
129
+ }, dir, { readStateScope: SCOPE });
130
+ const ok =
131
+ check('1.no-error', !isErr(out), String(out).slice(0, 160)) &
132
+ check('1.edit-signature', /^Edited:/.test(String(out)), String(out).slice(0, 80)) &
133
+ check('1.file-content', (await readFile(join(dir, file), 'utf8')) === 'const a = 2;\n');
134
+ caseResult('1 (omitted -> replace)', !!ok);
135
+ }
136
+
137
+ // ── Case 2: operation:'replace' explicit + batch edits[] ────────────────
138
+ {
139
+ const single = 'c2-single.txt';
140
+ await writeFile(join(dir, single), 'value = old;\n', 'utf8');
141
+ await warmRead(dir, single);
142
+ const sOut = await executeBuiltinTool('edit', {
143
+ operation: 'replace',
144
+ path: single,
145
+ old_string: 'value = old;',
146
+ new_string: 'value = NEW;',
147
+ }, dir, { readStateScope: SCOPE });
148
+
149
+ const batch = 'c2-batch.txt';
150
+ await writeFile(join(dir, batch), 'alpha\nbeta\ngamma\n', 'utf8');
151
+ await warmRead(dir, batch);
152
+ const bOut = await executeBuiltinTool('edit', {
153
+ operation: 'replace',
154
+ path: batch,
155
+ edits: [
156
+ { old_string: 'alpha', new_string: 'ALPHA' },
157
+ { old_string: 'gamma', new_string: 'GAMMA' },
158
+ ],
159
+ }, dir, { readStateScope: SCOPE });
160
+
161
+ const ok =
162
+ check('2.single-no-error', !isErr(sOut), String(sOut).slice(0, 160)) &
163
+ check('2.single-signature', /^Edited:/.test(String(sOut))) &
164
+ check('2.single-content', (await readFile(join(dir, single), 'utf8')) === 'value = NEW;\n') &
165
+ check('2.batch-no-error', !isErr(bOut), String(bOut).slice(0, 160)) &
166
+ check('2.batch-signature', /^Edited:/.test(String(bOut))) &
167
+ check('2.batch-content', (await readFile(join(dir, batch), 'utf8')) === 'ALPHA\nbeta\nGAMMA\n');
168
+ caseResult('2 (replace explicit + batch)', !!ok);
169
+ }
170
+
171
+ // ── Case 3: operation:'notebook' replace / insert / delete ──────────────
172
+ {
173
+ const nb = 'c3.ipynb';
174
+ await writeFile(join(dir, nb), JSON.stringify(makeNotebook(), null, 1), 'utf8');
175
+ await warmRead(dir, nb);
176
+
177
+ // replace a code cell's source -> execution_count reset, outputs cleared.
178
+ const repOut = await executeBuiltinTool('edit', {
179
+ operation: 'notebook',
180
+ notebook_path: nb,
181
+ edit_mode: 'replace',
182
+ cell_id: 'cellA',
183
+ new_source: 'print("brand new")\n',
184
+ }, dir, { readStateScope: SCOPE });
185
+ let afterRep = JSON.parse(await readFile(join(dir, nb), 'utf8'));
186
+ const cellA = afterRep.cells.find((c) => c.id === 'cellA');
187
+ const repOk =
188
+ check('3.replace-no-error', !isErr(repOut), String(repOut).slice(0, 160)) &
189
+ check('3.replace-signature', /^Updated cell/.test(String(repOut)), String(repOut).slice(0, 80)) &
190
+ check('3.replace-source', cellA && String(cellA.source) === 'print("brand new")\n') &
191
+ check('3.replace-exec-count-null', cellA && cellA.execution_count === null, JSON.stringify(cellA?.execution_count)) &
192
+ check('3.replace-outputs-cleared', cellA && Array.isArray(cellA.outputs) && cellA.outputs.length === 0, JSON.stringify(cellA?.outputs)) &
193
+ // sibling code cell C must keep its own outputs/exec_count untouched.
194
+ check('3.replace-sibling-untouched', (() => {
195
+ const c = afterRep.cells.find((x) => x.id === 'cellC');
196
+ return c && c.execution_count === 3;
197
+ })());
198
+
199
+ const countBeforeInsert = afterRep.cells.length;
200
+ const insOut = await executeBuiltinTool('edit', {
201
+ operation: 'notebook',
202
+ notebook_path: nb,
203
+ edit_mode: 'insert',
204
+ cell_id: 'cellA',
205
+ cell_type: 'code',
206
+ new_source: 'inserted = True\n',
207
+ }, dir, { readStateScope: SCOPE });
208
+ let afterIns = JSON.parse(await readFile(join(dir, nb), 'utf8'));
209
+ const insOk =
210
+ check('3.insert-no-error', !isErr(insOut), String(insOut).slice(0, 160)) &
211
+ check('3.insert-signature', /^Inserted/.test(String(insOut)), String(insOut).slice(0, 80)) &
212
+ check('3.insert-count', afterIns.cells.length === countBeforeInsert + 1,
213
+ `${countBeforeInsert} -> ${afterIns.cells.length}`) &
214
+ check('3.insert-source-present', afterIns.cells.some((c) => String(c.source) === 'inserted = True\n'));
215
+
216
+ const countBeforeDelete = afterIns.cells.length;
217
+ const delOut = await executeBuiltinTool('edit', {
218
+ operation: 'notebook',
219
+ notebook_path: nb,
220
+ edit_mode: 'delete',
221
+ cell_id: 'cellB',
222
+ }, dir, { readStateScope: SCOPE });
223
+ let afterDel = JSON.parse(await readFile(join(dir, nb), 'utf8'));
224
+ const delOk =
225
+ check('3.delete-no-error', !isErr(delOut), String(delOut).slice(0, 160)) &
226
+ check('3.delete-signature', /^Deleted/.test(String(delOut)), String(delOut).slice(0, 80)) &
227
+ check('3.delete-count', afterDel.cells.length === countBeforeDelete - 1,
228
+ `${countBeforeDelete} -> ${afterDel.cells.length}`) &
229
+ check('3.delete-gone', !afterDel.cells.some((c) => c.id === 'cellB'));
230
+
231
+ caseResult('3 (notebook replace/insert/delete)', !!(repOk & insOk & delOk));
232
+ }
233
+
234
+ // ── Case 4: rename PREVIEW writes NO file ───────────────────────────────
235
+ {
236
+ await writeFile(join(renameDir, 'package.json'), '{"name":"rename-fixture","private":true}\n', 'utf8');
237
+ await writeFile(join(renameDir, 'mod.mjs'), RENAME_SOURCE, 'utf8');
238
+ const before = await readFile(join(renameDir, 'mod.mjs'));
239
+
240
+ const out = await executeBuiltinTool('edit', {
241
+ operation: 'rename',
242
+ symbol: 'widget',
243
+ new_name: 'gadget',
244
+ // apply omitted -> preview only.
245
+ }, renameDir, { readStateScope: SCOPE });
246
+
247
+ let parsed = null;
248
+ try { parsed = JSON.parse(out); } catch { /* keep null */ }
249
+ const after = await readFile(join(renameDir, 'mod.mjs'));
250
+
251
+ const ok =
252
+ check('4.json-parse', parsed && typeof parsed === 'object', String(out).slice(0, 160)) &
253
+ check('4.mode-preview', parsed && parsed.mode === 'preview', parsed && parsed.mode) &
254
+ check('4.approx-warning', parsed && /APPROXIMATE/.test(String(parsed.warning))) &
255
+ check('4.changes-list', parsed && Array.isArray(parsed.changes) && parsed.changes.length > 0,
256
+ parsed && JSON.stringify(parsed.count)) &
257
+ check('4.no-write-byte-identical', before.equals(after), 'preview mutated the file');
258
+ caseResult('4 (rename preview no-write)', !!ok);
259
+ }
260
+
261
+ // ── Case 5: rename apply:true renames only sanctioned spans ─────────────
262
+ {
263
+ const out = await executeBuiltinTool('edit', {
264
+ operation: 'rename',
265
+ symbol: 'widget',
266
+ new_name: 'gadget',
267
+ apply: true,
268
+ }, renameDir, { readStateScope: SCOPE });
269
+
270
+ let parsed = null;
271
+ try { parsed = JSON.parse(out); } catch { /* keep null */ }
272
+ const text = await readFile(join(renameDir, 'mod.mjs'), 'utf8');
273
+
274
+ const ok =
275
+ check('5.json-parse', parsed && typeof parsed === 'object', String(out).slice(0, 160)) &
276
+ check('5.mode-apply', parsed && parsed.mode === 'apply', parsed && parsed.mode) &
277
+ check('5.replacements', parsed && parsed.replacements > 0, parsed && JSON.stringify(parsed.replacements)) &
278
+ // Code declaration + use renamed.
279
+ check('5.decl-renamed', text.includes('const gadget = 1;'), text) &
280
+ check('5.use-renamed', /return gadget;/.test(text), text) &
281
+ // Same-line comment occurrence left untouched.
282
+ check('5.comment-untouched', text.includes('// widget label retained'), text) &
283
+ // String literal occurrence left untouched.
284
+ check('5.string-untouched', text.includes('"widget literal stays"'), text);
285
+ caseResult('5 (rename apply, masked spans skipped)', !!ok);
286
+ }
287
+
288
+ // ── Case 6: invalid operation 'bogus' -> guard error, no mutation ───────
289
+ {
290
+ const file = 'c6.txt';
291
+ const original = 'do not touch\n';
292
+ await writeFile(join(dir, file), original, 'utf8');
293
+ await warmRead(dir, file);
294
+ const before = await readFile(join(dir, file));
295
+ const out = await executeBuiltinTool('edit', {
296
+ operation: 'bogus',
297
+ path: file,
298
+ old_string: 'do not touch',
299
+ new_string: 'mutated',
300
+ }, dir, { readStateScope: SCOPE });
301
+ const after = await readFile(join(dir, file));
302
+ const ok =
303
+ check('6.is-error', isErr(out), String(out).slice(0, 160)) &
304
+ check('6.error-mentions-operation', /operation/.test(String(out))) &
305
+ check('6.error-lists-valid', /replace\|notebook\|rename/.test(String(out)), String(out)) &
306
+ check('6.no-mutation', before.equals(after), 'guard error still mutated the file');
307
+ caseResult('6 (invalid operation guarded)', !!ok);
308
+ }
309
+
310
+ // ── Case 7: routing — operation -> handler (exclusive signatures) ───────
311
+ {
312
+ // omitted/replace -> text edit engine ("Edited:")
313
+ const r1 = 'c7-omit.txt';
314
+ await writeFile(join(dir, r1), 'route a\n', 'utf8');
315
+ await warmRead(dir, r1);
316
+ const omit = await executeBuiltinTool('edit', {
317
+ path: r1, old_string: 'route a', new_string: 'route A',
318
+ }, dir, { readStateScope: SCOPE });
319
+
320
+ const r2 = 'c7-replace.txt';
321
+ await writeFile(join(dir, r2), 'route b\n', 'utf8');
322
+ await warmRead(dir, r2);
323
+ const replace = await executeBuiltinTool('edit', {
324
+ operation: 'replace', path: r2, old_string: 'route b', new_string: 'route B',
325
+ }, dir, { readStateScope: SCOPE });
326
+
327
+ // notebook -> notebook handler ("Updated cell")
328
+ const r3 = 'c7.ipynb';
329
+ await writeFile(join(dir, r3), JSON.stringify(makeNotebook(), null, 1), 'utf8');
330
+ await warmRead(dir, r3);
331
+ const notebook = await executeBuiltinTool('edit', {
332
+ operation: 'notebook', notebook_path: r3, edit_mode: 'replace',
333
+ cell_id: 'cellC', new_source: 'y = 2\n',
334
+ }, dir, { readStateScope: SCOPE });
335
+
336
+ // rename -> rename handler (JSON preview, never reaches text engine)
337
+ const rename = await executeBuiltinTool('edit', {
338
+ operation: 'rename', symbol: 'getWidget', new_name: 'getGadget',
339
+ }, renameDir, { readStateScope: SCOPE });
340
+ let renameParsed = null;
341
+ try { renameParsed = JSON.parse(rename); } catch { /* keep null */ }
342
+
343
+ const ok =
344
+ // text-edit path exclusive signature
345
+ check('7.omitted->text-edit', /^Edited:/.test(String(omit)), String(omit).slice(0, 80)) &
346
+ check('7.replace->text-edit', /^Edited:/.test(String(replace)), String(replace).slice(0, 80)) &
347
+ // notebook handler exclusive signature (text engine never emits "Updated cell")
348
+ check('7.notebook->notebook-handler', /^Updated cell/.test(String(notebook)), String(notebook).slice(0, 80)) &
349
+ check('7.notebook-not-text-edit', !/^Edited:/.test(String(notebook))) &
350
+ // rename handler exclusive signature (text engine never emits this JSON shape)
351
+ check('7.rename->rename-handler',
352
+ renameParsed && (renameParsed.mode === 'preview' || renameParsed.mode === 'apply')
353
+ && /APPROXIMATE/.test(String(renameParsed.warning)),
354
+ String(rename).slice(0, 120)) &
355
+ check('7.rename-not-text-edit', !/^Edited:/.test(String(rename)));
356
+ caseResult('7 (operation -> handler routing)', !!ok);
357
+ }
358
+ } finally {
359
+ await rmTree(dir);
360
+ await rmTree(renameDir);
361
+ }
362
+
363
+ if (failures > 0) {
364
+ console.error(`\n${failures} smoke check(s) failed.`);
365
+ process.stdout.write('ALL_FAIL\n');
366
+ process.exit(1);
367
+ }
368
+ process.stdout.write('edit-operation-smoke: all cases passed.\nALL_PASS\n');
369
+ process.exit(0);
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ // edit2-smoke.mjs — end-to-end check of the native --edit2 (persistent server)
3
+ // path through runNativeExactEdit: exact / curly / nfc / crlf tiers +
4
+ // replace_all. Exercises B1 (server EDIT2 handler) + B2 (server client).
5
+ import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs';
6
+ import { tmpdir } from 'node:os';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { fileURLToPath, pathToFileURL } from 'node:url';
9
+
10
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
11
+ process.env.CLAUDE_PLUGIN_ROOT ||= ROOT;
12
+ // Pin the freshly built local binary: the runtime CLAUDE_PLUGIN_ROOT may point
13
+ // at the installed plugin copy, whose cached prebuilt predates --edit2.
14
+ process.env.MIXDOG_PATCH_NATIVE_BIN ||= join(
15
+ ROOT,
16
+ 'native/mixdog-patch/target/release',
17
+ process.platform === 'win32' ? 'mixdog-patch.exe' : 'mixdog-patch',
18
+ );
19
+
20
+ const { runNativeExactEdit } = await import(
21
+ pathToFileURL(join(ROOT, 'src/agent/orchestrator/tools/builtin/native-edit-runner.mjs')).href
22
+ );
23
+ const { closeNativePatchServerForTests } = await import(
24
+ pathToFileURL(join(ROOT, 'src/agent/orchestrator/tools/patch.mjs')).href
25
+ );
26
+
27
+ const dir = mkdtempSync(join(tmpdir(), 'edit2-smoke-'));
28
+ let failures = 0;
29
+
30
+ function check(name, cond, detail) {
31
+ if (cond) {
32
+ console.log(`ok ${name}`);
33
+ } else {
34
+ console.log(`FAIL ${name}${detail ? ' :: ' + detail : ''}`);
35
+ failures++;
36
+ }
37
+ }
38
+
39
+ async function run(name, content, args, expectFile, expectTier) {
40
+ const f = join(dir, name + '.txt');
41
+ writeFileSync(f, content);
42
+ const r = await runNativeExactEdit({ fullPath: f, ...args });
43
+ const got = r.ok ? readFileSync(f, 'utf8') : null;
44
+ check(name, r.ok && got === expectFile && r.stage === expectTier, JSON.stringify({ r, got }));
45
+ }
46
+
47
+ try {
48
+ await run('exact', 'hello world', { oldStr: 'world', newStr: 'earth', replaceAll: false }, 'hello earth', 'exact');
49
+ await run('curly', 'say “hi”', { oldStr: '"hi"', newStr: 'BYE', replaceAll: false }, 'say BYE', 'curly');
50
+ await run('nfc', 'café bar', { oldStr: 'café', newStr: 'CAFE', replaceAll: false }, 'CAFE bar', 'nfc');
51
+ await run('crlf', 'a\r\nb\r\nc', { oldStr: 'a\nb', newStr: 'X', replaceAll: false }, 'X\r\nc', 'crlf');
52
+ await run('replace_all', 'x x x', { oldStr: 'x', newStr: 'y', replaceAll: true }, 'y y y', 'exact');
53
+ // EOL preservation: a CRLF file keeps CRLF even when new text is LF-style.
54
+ await run('crlf-eol', 'a\r\nold\r\nc', { oldStr: 'old', newStr: 'NEW', replaceAll: false }, 'a\r\nNEW\r\nc', 'exact');
55
+ // pure-deletion: empty new removes the line including its trailing newline.
56
+ await run('pure-del', 'keep1\ndrop\nkeep2', { oldStr: 'drop', newStr: '', replaceAll: false }, 'keep1\nkeep2', 'exact');
57
+ } finally {
58
+ await closeNativePatchServerForTests().catch(() => {});
59
+ rmSync(dir, { recursive: true, force: true });
60
+ }
61
+
62
+ console.log(failures === 0 ? '\nedit2-smoke: PASS' : `\nedit2-smoke: FAIL (${failures})`);
63
+ process.exit(failures === 0 ? 0 : 1);
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ // fuzzy-e2e.mjs — end-to-end check of `list` fuzzy mode against the real repo:
3
+ // a partial name should surface the matching file via rg --files + ranking.
4
+ import { dirname, join, resolve } from 'node:path';
5
+ import { fileURLToPath, pathToFileURL } from 'node:url';
6
+
7
+ const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..');
8
+ process.env.CLAUDE_PLUGIN_ROOT ||= ROOT;
9
+
10
+ const { executeListTool } = await import(
11
+ pathToFileURL(join(ROOT, 'src/agent/orchestrator/tools/builtin/list-tool.mjs')).href
12
+ );
13
+
14
+ let fail = 0;
15
+ const check = (name, cond, detail) => {
16
+ console.log(`${cond ? 'ok ' : 'FAIL'} ${name}${cond ? '' : ' :: ' + detail}`);
17
+ if (!cond) fail++;
18
+ };
19
+
20
+ const out = await executeListTool({ fuzzy: 'edeng', path: 'src' }, ROOT);
21
+ console.log('--- top results ---\n' + String(out).split('\n').slice(0, 5).join('\n') + '\n---');
22
+ check('edeng surfaces edit-engine.mjs', typeof out === 'string' && out.includes('edit-engine.mjs'), String(out).slice(0, 120));
23
+
24
+ const miss = await executeListTool({ fuzzy: 'zzqqxx', path: 'src' }, ROOT);
25
+ check('no-match returns a clean message', typeof miss === 'string' && /no fuzzy match/.test(miss), String(miss).slice(0, 120));
26
+
27
+ console.log(fail === 0 ? '\nfuzzy-e2e: PASS' : `\nfuzzy-e2e: FAIL (${fail})`);
28
+ process.exit(fail === 0 ? 0 : 1);
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+ // fuzzy-smoke.mjs — unit check for the fuzzy filename scorer.
3
+ import { fuzzyScore, fuzzyRank } from '../src/agent/orchestrator/tools/builtin/fuzzy-match.mjs';
4
+
5
+ let fail = 0;
6
+ const check = (name, cond) => { console.log(`${cond ? 'ok ' : 'FAIL'} ${name}`); if (!cond) fail++; };
7
+
8
+ const items = [
9
+ { path: 'src/agent/orchestrator/tools/builtin/edit-engine.mjs' },
10
+ { path: 'src/agent/orchestrator/tools/builtin/edit-normalize.mjs' },
11
+ { path: 'docs/readme.md' },
12
+ { path: 'src/agent/index.mjs' },
13
+ ];
14
+
15
+ const ranked = fuzzyRank('edeng', items);
16
+ check('edeng -> edit-engine ranks first', ranked.length > 0 && ranked[0].item.path.includes('edit-engine.mjs'));
17
+
18
+ const idx = fuzzyRank('agidx', items);
19
+ check('agidx -> agent/index ranks first', idx.length > 0 && idx[0].item.path.endsWith('agent/index.mjs'));
20
+
21
+ check('non-subsequence returns null', fuzzyScore('zzz', 'abc') === null);
22
+ check('empty query scores 0', fuzzyScore('', 'whatever') === 0);
23
+ check('basename beats dir match', fuzzyScore('readme', 'docs/readme.md') > fuzzyScore('readme', 'readme/other.txt'));
24
+
25
+ console.log(fail === 0 ? '\nfuzzy-smoke: PASS' : `\nfuzzy-smoke: FAIL (${fail})`);
26
+ process.exit(fail === 0 ? 0 : 1);
@@ -0,0 +1,166 @@
1
+ #!/usr/bin/env node
2
+ // generate-runtime-manifest.mjs
3
+ // Aggregator step run after all matrix build jobs succeed.
4
+ // Reads release assets via gh CLI, filters mixdog-runtime-*.tar.gz,
5
+ // fetches sha256 from .sha256 sidecar files, and emits runtime-manifest.json
6
+ // to both dist/ and src/memory/data/ (for the auto-PR).
7
+ //
8
+ // Environment:
9
+ // GITHUB_TOKEN — PAT or GITHUB_TOKEN secret with contents:read
10
+ // RELEASE_TAG — e.g. "runtime-v0.4.0" (falls back to process.argv[2])
11
+ // GITHUB_REPOSITORY — auto-set by Actions (e.g. "owner/repo")
12
+
13
+ import { execSync } from 'node:child_process';
14
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
15
+ import { createHash } from 'node:crypto';
16
+ import { dirname, resolve } from 'node:path';
17
+ import { fileURLToPath } from 'node:url';
18
+ import { tmpdir } from 'node:os';
19
+
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const ROOT = resolve(__dirname, '..');
22
+
23
+ const RELEASE_TAG = process.env.RELEASE_TAG ?? process.argv[2];
24
+ const GITHUB_REPOSITORY = process.env.GITHUB_REPOSITORY ?? '';
25
+
26
+ if (!RELEASE_TAG) {
27
+ console.error('ERROR: RELEASE_TAG env var or argv[2] required');
28
+ process.exit(1);
29
+ }
30
+
31
+ // ---------------------------------------------------------------------------
32
+ // 1. List release assets via gh CLI
33
+ // ---------------------------------------------------------------------------
34
+ console.log(`Listing assets for release: ${RELEASE_TAG}`);
35
+
36
+ let assetsJson;
37
+ try {
38
+ assetsJson = execSync(
39
+ `gh release view ${RELEASE_TAG} --repo ${GITHUB_REPOSITORY} --json assets`,
40
+ { encoding: 'utf8', env: process.env }
41
+ );
42
+ } catch (err) {
43
+ console.error('gh release view failed:', err.message);
44
+ process.exit(1);
45
+ }
46
+
47
+ const { assets } = JSON.parse(assetsJson);
48
+
49
+ // Filter tarball assets
50
+ const tarballs = assets.filter(a => /^mixdog-runtime-.+\.tar\.gz$/.test(a.name));
51
+ console.log(`Found ${tarballs.length} tarball(s):`, tarballs.map(a => a.name));
52
+
53
+ if (tarballs.length === 0) {
54
+ console.error('No mixdog-runtime-*.tar.gz assets found on release.');
55
+ process.exit(1);
56
+ }
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // 2. Parse version strings from a filename
60
+ // Format: mixdog-runtime-{os}-{arch}-pg{major}.{minor}-pgvector{vec}.tar.gz
61
+ // ---------------------------------------------------------------------------
62
+ const PG_RE = /pg(\d+)\.(\d+)/;
63
+ const VEC_RE = /pgvector(\d+(?:\.\d+)+)/;
64
+
65
+ let pgMajor = 16, pgMinor = 4, pgvectorVersion = '0.7.4';
66
+ for (const t of tarballs) {
67
+ const pgM = PG_RE.exec(t.name);
68
+ const vM = VEC_RE.exec(t.name);
69
+ if (pgM) { pgMajor = parseInt(pgM[1], 10); pgMinor = parseInt(pgM[2], 10); }
70
+ if (vM) { pgvectorVersion = vM[1]; }
71
+ break; // all tarballs share the same version; just read the first
72
+ }
73
+
74
+ // ---------------------------------------------------------------------------
75
+ // 3. Fetch sha256 sidecar content for each tarball
76
+ // ---------------------------------------------------------------------------
77
+ async function fetchSha256(sha256AssetName, downloadUrl) {
78
+ // Try matching .sha256 sidecar from the asset list first
79
+ const sidecar = assets.find(a => a.name === sha256AssetName);
80
+ if (sidecar) {
81
+ // Download the sidecar file text
82
+ try {
83
+ const tmpDir = resolve(tmpdir(), 'mixdog-manifest-sha256');
84
+ mkdirSync(tmpDir, { recursive: true });
85
+ execSync(
86
+ `gh release download ${RELEASE_TAG} --repo ${GITHUB_REPOSITORY} --pattern ${sha256AssetName} --dir "${tmpDir}" --clobber`,
87
+ { encoding: 'utf8', env: process.env }
88
+ );
89
+ const content = readFileSync(resolve(tmpDir, sha256AssetName), 'utf8').trim();
90
+ // Format: "<hex> <filename>"
91
+ return content.split(/\s+/)[0];
92
+ } catch (e) {
93
+ console.warn(`Could not download sidecar ${sha256AssetName}: ${e.message}`);
94
+ }
95
+ }
96
+ return 'TBD'; // fallback if sidecar not present
97
+ }
98
+
99
+ // ---------------------------------------------------------------------------
100
+ // 4. Build asset map
101
+ // ---------------------------------------------------------------------------
102
+ const PLATFORM_RE = /mixdog-runtime-([a-z0-9]+)-([a-z0-9]+)-/;
103
+
104
+ const assetsMap = {};
105
+
106
+ for (const tarball of tarballs) {
107
+ const m = PLATFORM_RE.exec(tarball.name);
108
+ if (!m) { console.warn(`Skipping unrecognised tarball: ${tarball.name}`); continue; }
109
+ const key = `${m[1]}-${m[2]}`; // e.g. "linux-x64"
110
+
111
+ const sha256Key = `${tarball.name}.sha256`;
112
+ const sha256 = await fetchSha256(sha256Key, tarball.url);
113
+
114
+ assetsMap[key] = {
115
+ url: tarball.url,
116
+ sha256,
117
+ size: tarball.size ?? 0,
118
+ };
119
+ }
120
+
121
+ // Ensure all expected platforms are present (fill missing with TBD)
122
+ const EXPECTED = ['linux-x64', 'linux-arm64', 'darwin-x64', 'darwin-arm64', 'win32-x64'];
123
+ for (const p of EXPECTED) {
124
+ if (!assetsMap[p]) {
125
+ console.warn(`WARNING: No asset found for platform ${p} — filling with TBD`);
126
+ assetsMap[p] = { url: 'TBD', sha256: 'TBD', size: 0 };
127
+ }
128
+ }
129
+
130
+ // ---------------------------------------------------------------------------
131
+ // 5. Assemble manifest
132
+ // ---------------------------------------------------------------------------
133
+ const manifest = {
134
+ schema_version: 1,
135
+ generated_at: new Date().toISOString(),
136
+ release_tag: RELEASE_TAG,
137
+ pg: {
138
+ major: pgMajor,
139
+ minor: pgMinor,
140
+ },
141
+ pgvector: {
142
+ version: pgvectorVersion,
143
+ },
144
+ assets: assetsMap,
145
+ };
146
+
147
+ const manifestJson = JSON.stringify(manifest, null, 2) + '\n';
148
+ console.log('Manifest:', manifestJson);
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // 6. Write outputs
152
+ // ---------------------------------------------------------------------------
153
+ const distDir = resolve(ROOT, 'dist');
154
+ mkdirSync(distDir, { recursive: true });
155
+
156
+ const distPath = resolve(distDir, 'runtime-manifest.json');
157
+ const bundledPath = resolve(ROOT, 'src', 'memory', 'data', 'runtime-manifest.json');
158
+
159
+ writeFileSync(distPath, manifestJson);
160
+ console.log(`Written: ${distPath}`);
161
+
162
+ mkdirSync(dirname(bundledPath), { recursive: true });
163
+ writeFileSync(bundledPath, manifestJson);
164
+ console.log(`Written: ${bundledPath}`);
165
+
166
+ console.log('generate-runtime-manifest.mjs complete.');