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,123 @@
1
+ /**
2
+ * Shared HTTP connection pool for outbound LLM provider API calls.
3
+ *
4
+ * The provider modules (anthropic-oauth, openai-oauth, grok-oauth, gemini)
5
+ * call the global `fetch()` with no dispatcher, so they ride Node's default
6
+ * undici agent. That agent keeps connections alive only briefly, so after an
7
+ * idle gap the first request to a provider pays a fresh TLS handshake — a
8
+ * 100-300ms first-byte penalty observed on cold calls.
9
+ *
10
+ * This module exports ONE lazily-created singleton undici `Agent` with a long
11
+ * keep-alive window and a sane connection cap, passed as the `dispatcher`
12
+ * option on those providers' `fetch()` calls so warm sockets survive idle
13
+ * gaps. `preconnect(origin)` opens a socket ahead of the first real request
14
+ * (best-effort, errors swallowed) and is called once at provider construction.
15
+ *
16
+ * Scope note: this is deliberately NOT used by src/search/lib/web-tools.mjs,
17
+ * whose per-request Agent pins a pre-validated DNS address for SSRF safety and
18
+ * must own its own short-lived pool. LLM API origins are fixed, trusted hosts,
19
+ * so a shared long-lived pool is appropriate here.
20
+ */
21
+
22
+ import { Agent, getGlobalDispatcher, request as undiciRequest } from 'undici'
23
+
24
+ let _agent = null
25
+
26
+ function envInt(name, fallback) {
27
+ const raw = process.env[name]
28
+ if (!raw) return fallback
29
+ const n = Number(raw)
30
+ return Number.isFinite(n) && n > 0 ? Math.trunc(n) : fallback
31
+ }
32
+
33
+ /**
34
+ * Detect whether outbound HTTP is meant to flow through a proxy or any custom
35
+ * global dispatcher. When so, pinning our own bare keep-alive `Agent` as the
36
+ * per-request `dispatcher` would silently bypass `setGlobalDispatcher(...)` and
37
+ * env-proxy wiring — so callers must fall back to the global dispatcher.
38
+ *
39
+ * What is preserved (we step aside): explicit proxy env vars, undici's built-in
40
+ * `ProxyAgent`, and ANY non-default global dispatcher — i.e. any installed
41
+ * global whose constructor name is not `Agent` (undici's default global is a
42
+ * plain `Agent`). Our own singleton is never installed via
43
+ * `setGlobalDispatcher`, so this never self-detects.
44
+ *
45
+ * Accepted gap: a custom dispatcher deliberately constructed AS a plain undici
46
+ * `Agent` and set as the global is indistinguishable from the default here, so
47
+ * we'd keep using our shared pool. That's tolerable — such a dispatcher is
48
+ * itself a direct-connection pool (no proxy hop), so the bypass risk is minimal.
49
+ */
50
+ function proxyConfigured() {
51
+ const env = process.env
52
+ if (env.HTTP_PROXY || env.HTTPS_PROXY || env.http_proxy || env.https_proxy) return true
53
+ if (env.NODE_USE_ENV_PROXY) return true
54
+ try {
55
+ const g = getGlobalDispatcher?.()
56
+ // Any non-default global dispatcher (constructor name other than the plain
57
+ // `Agent` undici installs by default) is treated as custom — ProxyAgent,
58
+ // EnvHttpProxyAgent, MockAgent, or a user subclass — and we step aside.
59
+ if (g && g.constructor && g.constructor.name !== 'Agent') return true
60
+ } catch { /* getGlobalDispatcher unavailable — treat as no proxy */ }
61
+ return false
62
+ }
63
+
64
+ /**
65
+ * The shared singleton dispatcher for LLM API requests. Created on first use.
66
+ *
67
+ * keepAliveTimeout (~60s) keeps a socket warm across the typical idle gap
68
+ * between bridge turns; connections caps concurrent sockets per origin so a
69
+ * burst of parallel calls can't open an unbounded number of handshakes.
70
+ *
71
+ * Returns `undefined` when a proxy / any custom (non-default) global dispatcher
72
+ * is configured, so `fetch({ dispatcher: undefined })` falls back to that
73
+ * global dispatcher instead of bypassing it. `dispatcher: undefined` is a
74
+ * harmless fetch option, so call sites need no change.
75
+ */
76
+ export function getLlmDispatcher() {
77
+ if (proxyConfigured()) return undefined
78
+ if (_agent) return _agent
79
+ _agent = new Agent({
80
+ keepAliveTimeout: envInt('MIXDOG_LLM_KEEPALIVE_MS', 60_000),
81
+ // Cap the idle keep-alive bump the server may request, so a generous
82
+ // upstream Keep-Alive header can't pin sockets open far longer than us.
83
+ keepAliveMaxTimeout: envInt('MIXDOG_LLM_KEEPALIVE_MAX_MS', 90_000),
84
+ connections: envInt('MIXDOG_LLM_CONNECTIONS', 16),
85
+ })
86
+ return _agent
87
+ }
88
+
89
+ // Origins already warmed (or warming) this process, so repeated provider
90
+ // construction or multiple providers on the same host don't spam handshakes.
91
+ const _preconnected = new Set()
92
+
93
+ /**
94
+ * Best-effort warm a kept-alive socket to `origin` so the first real request
95
+ * skips the TLS handshake. Fire-and-forget: never throws, never returns a
96
+ * pending promise the caller must await.
97
+ *
98
+ * @param {string} origin e.g. 'https://api.anthropic.com'
99
+ */
100
+ export function preconnect(origin) {
101
+ try {
102
+ // With a proxy / custom global dispatcher in play we deliberately don't own
103
+ // the connection pool, so there's no warm socket to seed — no-op.
104
+ if (proxyConfigured()) return
105
+ if (!origin || typeof origin !== 'string') return
106
+ let url
107
+ try { url = new URL(origin) } catch { return }
108
+ if (url.protocol !== 'https:' && url.protocol !== 'http:') return
109
+ const key = url.origin
110
+ if (_preconnected.has(key)) return
111
+ _preconnected.add(key)
112
+ // A throwaway HEAD lands a pooled socket without fetching a body. Any
113
+ // failure (offline, DNS, 4xx/5xx) is irrelevant — the handshake is the
114
+ // point, and the real request will surface genuine errors.
115
+ undiciRequest(key, {
116
+ method: 'HEAD',
117
+ dispatcher: getLlmDispatcher(),
118
+ signal: AbortSignal.timeout(10_000),
119
+ })
120
+ .then((res) => res.body?.dump?.())
121
+ .catch(() => { /* best-effort warmup; ignore */ })
122
+ } catch { /* never let warmup break construction */ }
123
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared LLM helpers (post v0.6.46).
3
+ *
4
+ * The legacy `callLLM` dispatcher and direct CLI/HTTP runners have been
5
+ * removed — every LLM call now flows through `bridge-llm.mjs`
6
+ * (`makeBridgeLlm({ taskType })`) and, for memory maintenance specifically,
7
+ * through `maintenance-llm.mjs`'s thin wrapper.
8
+ *
9
+ * Only preset resolution remains here: memory-cycle and future backend
10
+ * callers still need a consistent way to map `(task, agent-config)` to a
11
+ * preset id.
12
+ */
13
+
14
+ import { DEFAULT_MAINTENANCE } from '../../agent/orchestrator/config.mjs'
15
+ import { readSection } from '../config.mjs'
16
+
17
+ function loadAgentConfig() {
18
+ try {
19
+ return readSection('agent')
20
+ } catch (e) {
21
+ console.error(`[llm] agent-config load error: ${e.message}`)
22
+ return {}
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Resolve maintenance preset ID for a given task from agent-config.
28
+ * Falls back to canonical defaults (DEFAULT_MAINTENANCE from config.mjs).
29
+ * Returns null if no matching preset is registered (lets callers skip the call).
30
+ */
31
+ export function resolveMaintenancePreset(task, agentConfig) {
32
+ const cfg = agentConfig || loadAgentConfig()
33
+ const maint = cfg?.maintenance || {}
34
+ const presetId = maint[task] || DEFAULT_MAINTENANCE[task]
35
+ const presets = cfg?.presets || []
36
+ if (presets.some(p => p.id === presetId || p.name === presetId)) return presetId
37
+ // No registered preset found — return the first available preset id so callers
38
+ // always receive a real id, or null if the presets list is empty.
39
+ const first = presets.find(p => p?.id || p?.name)
40
+ return first ? (first.id || first.name) : null
41
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * pid-cleanup.mjs — Orphaned bridge CLI process cleanup.
3
+ * Used by server.mjs on startup and shutdown.
4
+ */
5
+ import fs from 'fs'
6
+ import path from 'path'
7
+ import os from 'os'
8
+
9
+ const PID_DIR = path.join(os.tmpdir(), 'mixdog-bridge')
10
+ const PID_FILE = path.join(PID_DIR, 'bridge-pids.json')
11
+
12
+ export function cleanupOrphanedPids() {
13
+ let killed = 0
14
+ try {
15
+ const pids = JSON.parse(fs.readFileSync(PID_FILE, 'utf8'))
16
+ for (const pid of pids) {
17
+ try {
18
+ process.kill(pid, 0)
19
+ process.kill(pid, 'SIGTERM')
20
+ process.stderr.write(`[bridge-cleanup] killed orphaned PID ${pid}\n`)
21
+ killed++
22
+ } catch {}
23
+ }
24
+ fs.writeFileSync(PID_FILE, JSON.stringify([]))
25
+ } catch {}
26
+ return killed
27
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Unified LLM usage logger.
3
+ *
4
+ * Phase 2: Routes via appendBridgeTrace (HTTP buffer to memory-service)
5
+ * instead of writing directly to bridge-trace.jsonl.
6
+ *
7
+ * Signature unchanged — callers are unaffected.
8
+ */
9
+
10
+ import { appendBridgeTrace } from '../../agent/orchestrator/bridge-trace.mjs';
11
+
12
+ /**
13
+ * Append a usage entry to the trace store.
14
+ *
15
+ * @param {object} entry — usage record
16
+ * @param {object} opts
17
+ * @param {boolean} [opts.maintenance=false] — flag record as maintenance-origin
18
+ *
19
+ * Entry schema:
20
+ * ts, preset, model, provider, mode, duration,
21
+ * profileId, sessionId,
22
+ * inputTokens, outputTokens, cacheReadTokens, cacheWriteTokens,
23
+ * prefixHash, costUsd
24
+ */
25
+ const _missingProviderWarned = new Set();
26
+ function warnMissingProviderOnce(key) {
27
+ if (_missingProviderWarned.has(key)) return;
28
+ _missingProviderWarned.add(key);
29
+ try {
30
+ process.stderr.write(`[usage-log] provider missing on usage entry (model=${key}). audit the caller.\n`);
31
+ } catch { /* logging only */ }
32
+ }
33
+
34
+ export function logLlmCall(entry, opts = {}) {
35
+ try {
36
+ if (!entry.provider) warnMissingProviderOnce(entry.model || '?');
37
+ appendBridgeTrace({
38
+ ts: entry.ts || Date.now(),
39
+ kind: 'usage',
40
+ ...entry,
41
+ payload: entry.payload ?? {},
42
+ maintenanceLog: opts.maintenance === true ? true : undefined,
43
+ });
44
+ } catch {
45
+ // Never let logging break the caller.
46
+ }
47
+ }
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Canonical resolver for CLAUDE_PLUGIN_DATA (plugin data dir).
3
+ *
4
+ * Resolution order:
5
+ * 1. process.env.CLAUDE_PLUGIN_DATA — set by Claude Code when spawning
6
+ * the MCP server or a hook.
7
+ * 2. Derive from CLAUDE_PLUGIN_ROOT — supports two real layouts:
8
+ * cache: .../cache/{marketplace}/{plugin}/{version}/
9
+ * marketplace: .../marketplaces/{marketplace}/ (root *is* the
10
+ * marketplace dir; plugin name comes from
11
+ * .claude-plugin/plugin.json or DEFAULT_PLUGIN)
12
+ *
13
+ * Throws if neither env var is present — the plugin always runs under
14
+ * Claude Code, which sets one of them. Callers must not silently fall
15
+ * back to a hardcoded path.
16
+ *
17
+ * DEFAULT_PLUGIN / DEFAULT_MARKETPLACE are exported so a handful of
18
+ * callers (MCP client spawning sibling plugins, session-manager building
19
+ * PLUGIN_ROOT for rule injection) can reference the canonical names
20
+ * without re-hardcoding the strings. Update both in lockstep with
21
+ * `.claude-plugin/marketplace.json` if the marketplace is ever renamed.
22
+ */
23
+
24
+ import { homedir } from 'os';
25
+ import { join, basename } from 'path';
26
+ import { readFileSync } from 'fs';
27
+
28
+ export const DEFAULT_PLUGIN = 'mixdog';
29
+ export const DEFAULT_MARKETPLACE = 'trib-plugin';
30
+
31
+ function readPluginManifestName(root) {
32
+ try {
33
+ const manifest = JSON.parse(readFileSync(join(root, '.claude-plugin', 'plugin.json'), 'utf8'));
34
+ if (manifest && typeof manifest.name === 'string' && manifest.name.trim()) return manifest.name.trim();
35
+ } catch { /* fall through to default */ }
36
+ return DEFAULT_PLUGIN;
37
+ }
38
+
39
+ export function resolvePluginData() {
40
+ if (process.env.CLAUDE_PLUGIN_DATA) return process.env.CLAUDE_PLUGIN_DATA;
41
+ const root = process.env.CLAUDE_PLUGIN_ROOT;
42
+ if (root) {
43
+ const dirName = basename(root);
44
+ // Cache layout: .../cache/{marketplace}/{plugin}/{version}/
45
+ if (/^\d+\.\d+\.\d+/.test(dirName)) {
46
+ const pluginName = basename(join(root, '..'));
47
+ const marketplace = basename(join(root, '..', '..'));
48
+ return join(homedir(), '.claude', 'plugins', 'data', `${pluginName}-${marketplace}`);
49
+ }
50
+ // Marketplace layout: .../marketplaces/{marketplace}/
51
+ // The root dir itself is the marketplace. Plugin name lives in the
52
+ // manifest; fall back to DEFAULT_PLUGIN when it's unreadable.
53
+ const marketplace = dirName;
54
+ const pluginName = readPluginManifestName(root);
55
+ return join(homedir(), '.claude', 'plugins', 'data', `${pluginName}-${marketplace}`);
56
+ }
57
+ throw new Error('[plugin-paths] CLAUDE_PLUGIN_DATA and CLAUDE_PLUGIN_ROOT are both unset — cannot resolve plugin data dir outside of Claude Code.');
58
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Canonical reader for registered schedules.
3
+ *
4
+ * `${CLAUDE_PLUGIN_DATA}/schedules/<name>/` is the single source of truth.
5
+ * Each schedule directory contains `config.json` (metadata) and
6
+ * `instructions.md` (prompt body). Both the setup UI (POST /schedules)
7
+ * and the `schedule-add` skill write the same two files; every reader —
8
+ * setup-server (GET /schedules), channels/lib/config.mjs (loadConfig),
9
+ * status/aggregator.mjs — must go through listSchedules() so a single
10
+ * entry shape is presented everywhere.
11
+ *
12
+ * The legacy `mixdog-config.json` `channels.schedules.items` /
13
+ * `channels.nonInteractive` / `channels.interactive` arrays are no longer
14
+ * consulted. Migration: rename any legacy `prompt.md` to `instructions.md`
15
+ * — no in-code fallback.
16
+ */
17
+
18
+ import { readFileSync, readdirSync } from 'fs';
19
+ import { join } from 'path';
20
+ import { resolvePluginData } from './plugin-paths.mjs';
21
+
22
+ function schedulesDir() {
23
+ return join(resolvePluginData(), 'schedules');
24
+ }
25
+
26
+ function readJsonFile(path) {
27
+ try { return JSON.parse(readFileSync(path, 'utf8')); }
28
+ catch { return null; }
29
+ }
30
+
31
+ function readTextFile(path) {
32
+ try { return readFileSync(path, 'utf8'); }
33
+ catch { return ''; }
34
+ }
35
+
36
+ /**
37
+ * List every registered schedule.
38
+ *
39
+ * Return shape per entry: `{ name, ...config, prompt }`.
40
+ * - `name` is the directory name (slug).
41
+ * - Spread of `config.json` keys (time/days/type/channel/model/enabled
42
+ * when written by the setup UI; cron/timezone/mode/role when written
43
+ * by the schedule-add skill).
44
+ * - `prompt` carries `instructions.md` content (empty string when the
45
+ * file is missing — caller decides whether that is a hard error).
46
+ *
47
+ * Returns an empty array when the directory does not exist (fresh
48
+ * install with no schedules registered yet).
49
+ */
50
+ export function listSchedules() {
51
+ const dir = schedulesDir();
52
+ const out = [];
53
+ let entries;
54
+ try {
55
+ entries = readdirSync(dir, { withFileTypes: true });
56
+ } catch {
57
+ // ENOENT (fresh install, no schedules/ yet) / EACCES -> empty list.
58
+ // Replaces the previous existsSync check, which was racy: the dir
59
+ // could disappear between existsSync and readdirSync.
60
+ return out;
61
+ }
62
+ for (const ent of entries) {
63
+ if (!ent.isDirectory()) continue;
64
+ const name = ent.name;
65
+ const cfg = readJsonFile(join(dir, name, 'config.json')) || {};
66
+ const prompt = readTextFile(join(dir, name, 'instructions.md'));
67
+ out.push({ name, ...cfg, prompt });
68
+ }
69
+ return out;
70
+ }
@@ -0,0 +1,119 @@
1
+ import { existsSync, mkdirSync, readFileSync } from 'fs';
2
+ import { dirname, join } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import { DEFAULT_PRESETS, DEFAULT_MAINTENANCE } from '../agent/orchestrator/config.mjs';
5
+ import { writeFileAtomicSync, withFileLockSync } from './atomic-file.mjs';
6
+ import { backupUserData, markUserDataInitialized, shouldSeedMissingUserData } from './user-data-guard.mjs';
7
+ import { disableClaudeBuiltinsOnFirstInstall } from './disable-claude-builtins.mjs';
8
+
9
+ const DEFAULTS_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', '..', 'defaults');
10
+
11
+ // Idempotent seed of the unified mixdog-config.json so first-time installs
12
+ // land with the Config UI already populated with defaults (presets, search
13
+ // scaffold, memory config) instead of presenting empty lists.
14
+ //
15
+ // Only plugin-owned paths under `<plugin-data>/` are seeded. User-owned
16
+ // surfaces — global CLAUDE.md files, project repo files, etc. — are not
17
+ // touched by seeding. `existsSync()` gates every write so a second boot
18
+ // never overwrites user edits.
19
+
20
+ //
21
+ // Seed bodies are thunks so dynamic content (DEFAULT_PRESETS pulling
22
+ // ANTHROPIC_DEFAULT_*_MODEL overrides at load time) resolves at seed time,
23
+ // not at module-import time.
24
+ const SEEDS = {
25
+ // Single unified config file — all sections in one JSON.
26
+ // Prompt injection is seeded under `channels`. New installs default to
27
+ // CLAUDE.md mode so the managed global rule block is authoritative from
28
+ // the next Claude Code session.
29
+ // providers/mcpServers intentionally omitted from `agent` so runtime
30
+ // auto-detect (buildDefaultConfig) decides based on env keys / OAuth.
31
+ 'mixdog-config.json': () => {
32
+ // Template carries the static channels/memory/search defaults; agent
33
+ // section is composed at seed time so DEFAULT_PRESETS picks up the
34
+ // ANTHROPIC_DEFAULT_*_MODEL env overrides resolved at boot. Top-level
35
+ // key order is rebuilt explicitly so seed output stays
36
+ // channels/memory/agent/search regardless of template author.
37
+ const template = JSON.parse(
38
+ readFileSync(join(DEFAULTS_DIR, 'mixdog-config.template.json'), 'utf8'),
39
+ );
40
+ const composed = {
41
+ channels: template.channels,
42
+ memory: template.memory,
43
+ agent: {
44
+ presets: DEFAULT_PRESETS.map((p) => ({ ...p })),
45
+ maintenance: { ...DEFAULT_MAINTENANCE },
46
+ default: 'opus-high',
47
+ },
48
+ search: template.search,
49
+ };
50
+ return JSON.stringify(composed, null, 2) + '\n';
51
+ },
52
+ };
53
+
54
+ export function ensureDataSeeds(dataDir) {
55
+ if (!dataDir) return { created: [], skipped: [] };
56
+ const created = [];
57
+ const skipped = [];
58
+ for (const [rel, bodyFn] of Object.entries(SEEDS)) {
59
+ const full = join(dataDir, rel);
60
+ if (existsSync(full)) {
61
+ markUserDataInitialized(dataDir);
62
+ skipped.push(rel);
63
+ continue;
64
+ }
65
+ if (!shouldSeedMissingUserData(dataDir, rel)) {
66
+ skipped.push(rel);
67
+ continue;
68
+ }
69
+ // Body composition (template read / config build) errors are fatal —
70
+ // a missing defaults/ file means the plugin install itself is
71
+ // incomplete, and silently skipping the seed would leave the user
72
+ // with an empty Config UI. Filesystem errors during the actual write
73
+ // are non-fatal and only logged so a transient mkdir/write failure
74
+ // does not block boot.
75
+ const body = bodyFn();
76
+ try {
77
+ mkdirSync(dirname(full), { recursive: true });
78
+ // Re-check existence under a file lock to serialize cooperating
79
+ // seed writers, then use createOnly:true so the final commit
80
+ // step (linkSync with O_EXCL semantics) refuses to overwrite a
81
+ // file that a non-locking external writer (user/editor)
82
+ // created in between. linkSync→EEXIST is caught inside
83
+ // writeFileAtomicSync and reported as `false`; we treat that
84
+ // as a clean skip rather than an overwrite, preserving the
85
+ // "never overwrites user edits" invariant in the header.
86
+ withFileLockSync(`${full}.lock`, () => {
87
+ if (existsSync(full)) {
88
+ markUserDataInitialized(dataDir);
89
+ skipped.push(rel);
90
+ return;
91
+ }
92
+ const wrote = writeFileAtomicSync(full, body, {
93
+ fsyncDir: true,
94
+ createOnly: true,
95
+ });
96
+ if (wrote) {
97
+ markUserDataInitialized(dataDir);
98
+ created.push(rel);
99
+ // Fresh creation of mixdog-config.json is the first-install
100
+ // signal: disable Claude Code's built-in memory/recap once
101
+ // (restore snapshot captured first). Best-effort; never
102
+ // breaks seeding.
103
+ if (rel === 'mixdog-config.json') {
104
+ disableClaudeBuiltinsOnFirstInstall();
105
+ }
106
+ } else {
107
+ skipped.push(rel);
108
+ }
109
+ });
110
+ } catch (e) {
111
+ process.stderr.write(`[seed] ${rel} create failed: ${e.message}\n`);
112
+ }
113
+ }
114
+ if (created.length > 0) {
115
+ process.stderr.write(`[seed] created ${created.length} file(s): ${created.join(', ')}\n`);
116
+ try { backupUserData(dataDir, 'post-seed'); } catch {}
117
+ }
118
+ return { created, skipped };
119
+ }