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,82 @@
1
+ 'use strict';
2
+
3
+ // Per-turn latency logger. Opt-in via MIXDOG_PERF=1.
4
+ // Usage: `node turn-timer.cjs start` on UserPromptSubmit,
5
+ // `node turn-timer.cjs stop` on Stop.
6
+ // Writes one JSON line per completed turn to ${CLAUDE_PLUGIN_DATA}/perf.log.
7
+
8
+ // Default ON; opt out with MIXDOG_PERF=0|false|no|off.
9
+ if (/^(0|false|no|off)$/i.test(String(process.env.MIXDOG_PERF || ''))) process.exit(0);
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const os = require('os');
14
+
15
+ const HOOK_ENTERED_AT = Date.now();
16
+
17
+ let raw = '';
18
+ try { raw = fs.readFileSync(0, 'utf8'); } catch {}
19
+ let ev = {};
20
+ try { ev = raw ? JSON.parse(raw) : {}; } catch {}
21
+
22
+ if (ev.isSidechain) process.exit(0);
23
+ if (ev.is_sidechain) process.exit(0);
24
+ if (ev.agentId) process.exit(0);
25
+ if (ev.agent_id) process.exit(0);
26
+
27
+ const mode = process.argv[2] || '';
28
+ const DATA_DIR = process.env.CLAUDE_PLUGIN_DATA;
29
+ if (!DATA_DIR) process.exit(0);
30
+
31
+ const RUNTIME = path.join(os.tmpdir(), 'mixdog');
32
+ try { fs.mkdirSync(RUNTIME, { recursive: true }); } catch {}
33
+ try { fs.mkdirSync(DATA_DIR, { recursive: true }); } catch {}
34
+
35
+ const sessionId = ev.session_id || ev.sessionId;
36
+ if (!sessionId) process.exit(0);
37
+ const markFile = path.join(RUNTIME, `turn-${sessionId}.mark`);
38
+ const logFile = path.join(DATA_DIR, 'perf.log');
39
+ const now = Date.now();
40
+
41
+ function appendLine(obj) {
42
+ try {
43
+ try {
44
+ const st = fs.statSync(logFile);
45
+ if (st.size > 5 * 1024 * 1024) fs.renameSync(logFile, logFile + '.1');
46
+ } catch {}
47
+ fs.appendFileSync(logFile, JSON.stringify(obj) + '\n');
48
+ } catch (e) {
49
+ process.stderr.write(`[turn-timer] append failed: ${e.message}\n`);
50
+ }
51
+ }
52
+
53
+ if (mode === 'start') {
54
+ try {
55
+ fs.writeFileSync(markFile, JSON.stringify({ t: now, session: sessionId, ppid: process.ppid }));
56
+ } catch (e) {
57
+ process.stderr.write(`[turn-timer] mark failed: ${e.message}\n`);
58
+ }
59
+ appendLine({
60
+ kind: 'start',
61
+ ts: new Date(now).toISOString(),
62
+ session: sessionId,
63
+ hook_ms: Date.now() - HOOK_ENTERED_AT,
64
+ });
65
+ } else if (mode === 'stop') {
66
+ let startTs = null;
67
+ try {
68
+ const m = JSON.parse(fs.readFileSync(markFile, 'utf8'));
69
+ startTs = m.t;
70
+ fs.unlinkSync(markFile);
71
+ } catch {}
72
+ appendLine({
73
+ kind: 'stop',
74
+ ts: new Date(now).toISOString(),
75
+ session: sessionId,
76
+ duration_ms: startTs ? now - startTs : null,
77
+ stop_reason: ev.stop_reason || null,
78
+ hook_ms: Date.now() - HOOK_ENTERED_AT,
79
+ });
80
+ }
81
+
82
+ process.exit(0);
@@ -0,0 +1,386 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * mixdog CLAUDE.md managed-block writer.
5
+ *
6
+ * Manages a single marker-delimited block inside a CLAUDE.md file.
7
+ * Normally only content *between* the markers is touched — anything the
8
+ * user has written outside the block is preserved verbatim. The sole
9
+ * exception is the FIRST takeover of a non-empty, marker-less file: the
10
+ * untouched original is backed up once to
11
+ * <backupRoot>/install-restore/claude-md-original.md (atomically) and the
12
+ * file is then REPLACED with just the managed block. If that backup
13
+ * cannot be written, the writer falls back to appending the block so user
14
+ * content is never destroyed without a confirmed backup.
15
+ *
16
+ * Every write also purges blocks tagged with legacy markers (see
17
+ * LEGACY_MARKERS below) so a plugin rename never leaves stale copies
18
+ * behind. Duplicate current-marker blocks (e.g. authored by hand) are
19
+ * collapsed to the first occurrence on every write.
20
+ *
21
+ * All writes are atomic (temp file + rename) to prevent partial writes
22
+ * from corrupting the target file.
23
+ */
24
+
25
+ const fs = require('fs');
26
+ const path = require('path');
27
+ const os = require('os');
28
+
29
+ const MARKER_START = '<!-- BEGIN mixdog managed -->';
30
+ const MARKER_END = '<!-- END mixdog managed -->';
31
+ const RENAME_RETRY_CODES = new Set(['EPERM', 'EACCES', 'EBUSY', 'EEXIST']);
32
+ const RENAME_BACKOFFS_MS = [25, 50, 100, 200, 400, 800, 1200, 1600];
33
+
34
+ function sleepSync(ms) {
35
+ try {
36
+ const buf = new SharedArrayBuffer(4);
37
+ Atomics.wait(new Int32Array(buf), 0, 0, ms);
38
+ } catch {
39
+ const end = Date.now() + ms;
40
+ while (Date.now() < end) {}
41
+ }
42
+ }
43
+
44
+ function renameWithRetrySync(src, dst) {
45
+ let lastErr = null;
46
+ for (let attempt = 0; attempt <= RENAME_BACKOFFS_MS.length; attempt++) {
47
+ try {
48
+ fs.renameSync(src, dst);
49
+ return;
50
+ } catch (err) {
51
+ lastErr = err;
52
+ if (!RENAME_RETRY_CODES.has(err && err.code) || attempt >= RENAME_BACKOFFS_MS.length) break;
53
+ sleepSync(RENAME_BACKOFFS_MS[attempt] + Math.floor(Math.random() * 40));
54
+ }
55
+ }
56
+ throw lastErr;
57
+ }
58
+
59
+ function withFileLockSync(lockPath, fn) {
60
+ const deadline = Date.now() + 3000;
61
+ fs.mkdirSync(path.dirname(lockPath), { recursive: true });
62
+ while (Date.now() <= deadline) {
63
+ let fd = null;
64
+ try {
65
+ fd = fs.openSync(lockPath, 'wx');
66
+ try { fs.writeFileSync(fd, `${process.pid} ${Date.now()}\n`, 'utf8'); } catch {}
67
+ try { return fn(); }
68
+ finally {
69
+ try { if (fd !== null) fs.closeSync(fd); } catch {}
70
+ try { fs.unlinkSync(lockPath); } catch {}
71
+ }
72
+ } catch (err) {
73
+ try { if (fd !== null) fs.closeSync(fd); } catch {}
74
+ if (err && err.code !== 'EEXIST') throw err;
75
+ try {
76
+ const st = fs.statSync(lockPath);
77
+ if (Date.now() - st.mtimeMs > 30000) {
78
+ try { fs.unlinkSync(lockPath); } catch {}
79
+ continue;
80
+ }
81
+ } catch {}
82
+ sleepSync(25 + Math.floor(Math.random() * 35));
83
+ }
84
+ }
85
+ // Lock contention past the deadline: fail closed rather than executing
86
+ // fn() unlocked. Concurrent CLAUDE.md writers without a lock can
87
+ // overwrite each other's updates (last-writer-wins on an unrelated
88
+ // managed-block edit corrupts the file). Stale-lock removal already
89
+ // happens above via the 30s mtime check, so reaching here means a
90
+ // genuinely contested lock held by a live writer.
91
+ throw Object.assign(new Error(`[claude-md-writer] file lock not acquired within 3000ms: ${lockPath}`), { code: 'ELOCKED' });
92
+ }
93
+
94
+ // Marker pairs from previous plugin names. Every write strips any block
95
+ // delimited by these so a rename never leaves the old block behind next
96
+ // to the new one. Append new entries in lockstep with MARKER_START/END
97
+ // whenever the plugin is renamed again.
98
+ const LEGACY_MARKERS = Object.freeze([
99
+ Object.freeze({
100
+ start: '<!-- BEGIN trib-plugin managed -->',
101
+ end: '<!-- END trib-plugin managed -->',
102
+ }),
103
+ ]);
104
+
105
+ /**
106
+ * Expand a leading `~` to the current user's home directory.
107
+ * Any other path is returned unchanged.
108
+ *
109
+ * @param {string} p
110
+ * @returns {string}
111
+ */
112
+ function expandHome(p) {
113
+ if (typeof p !== 'string' || !p) return p;
114
+ if (p === '~') return os.homedir();
115
+ if (p.startsWith('~/') || p.startsWith('~\\')) {
116
+ return path.join(os.homedir(), p.slice(2));
117
+ }
118
+ return p;
119
+ }
120
+
121
+ /**
122
+ * Resolve the mixdog user-data backup root. Mirrors getBackupRoot() in
123
+ * src/shared/user-data-guard.mjs (env override, else ~/.claude/backups/
124
+ * mixdog-user-data) — kept as a tiny local resolver because this is a
125
+ * .cjs module that cannot import the ESM guard.
126
+ */
127
+ function userDataBackupRoot() {
128
+ return process.env.MIXDOG_USER_DATA_BACKUP_ROOT
129
+ || path.join(os.homedir(), '.claude', 'backups', 'mixdog-user-data');
130
+ }
131
+
132
+ /**
133
+ * On the FIRST takeover of a user-authored CLAUDE.md (no managed markers
134
+ * yet, real content present) back up the untouched original so it can be
135
+ * restored later. Writes only when the backup does not already exist —
136
+ * the first takeover wins; later marker-less states must never clobber
137
+ * the true original. Returns true when a backup is in place (already
138
+ * existed or freshly written), false when it could not be written (the
139
+ * caller then falls back to append so user content is never destroyed).
140
+ *
141
+ * The backup is written atomically (temp file + rename, same pattern as
142
+ * the target file) so a crashed attempt can never leave a truncated
143
+ * backup. An existing dest is therefore trustworthy going forward and is
144
+ * treated as a completed first takeover.
145
+ */
146
+ function ensureOriginalBackup(originalContent) {
147
+ const dest = path.join(userDataBackupRoot(), 'install-restore', 'claude-md-original.md');
148
+ try {
149
+ if (fs.existsSync(dest)) return true;
150
+ _atomicWriteUnlocked(dest, originalContent);
151
+ return true;
152
+ } catch {
153
+ return false;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Write `data` to `filePath` atomically via a sibling temp file.
159
+ * Creates parent directories as needed.
160
+ */
161
+ function atomicWrite(filePath, data) {
162
+ return withFileLockSync(`${filePath}.lock`, () => _atomicWriteUnlocked(filePath, data));
163
+ }
164
+
165
+ // Inner write helper used when the caller already holds `${filePath}.lock`.
166
+ // Splitting this out lets upsertManagedBlock / removeManagedBlock perform
167
+ // read+compute+rename under a SINGLE lock (RMW linearisable), mirroring
168
+ // the withConfigLock pattern in src/shared/config.mjs. Calling
169
+ // atomicWrite() from inside the same lock would deadlock on EEXIST.
170
+ function _atomicWriteUnlocked(filePath, data) {
171
+ const dir = path.dirname(filePath);
172
+ fs.mkdirSync(dir, { recursive: true });
173
+ const tmp = path.join(
174
+ dir,
175
+ `.${path.basename(filePath)}.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2, 8)}.tmp`,
176
+ );
177
+ fs.writeFileSync(tmp, data, 'utf8');
178
+ try {
179
+ renameWithRetrySync(tmp, filePath);
180
+ } catch (err) {
181
+ try { fs.unlinkSync(tmp); } catch {}
182
+ throw err;
183
+ }
184
+ }
185
+
186
+ /**
187
+ * Build the managed block string from its inner content.
188
+ */
189
+ function wrapBlock(content) {
190
+ const body = typeof content === 'string' ? content : '';
191
+ return `${MARKER_START}\n${body}\n${MARKER_END}`;
192
+ }
193
+
194
+ /**
195
+ * Strip every (start, end) block from `text`. Handles duplicates by
196
+ * looping until no more pairs remain. Invalid pairs (end before start,
197
+ * unmatched markers) are left alone.
198
+ */
199
+ function stripAllBlocks(text, start, end) {
200
+ let out = text;
201
+ let cursor = 0;
202
+ while (cursor <= out.length) {
203
+ const si = out.indexOf(start, cursor);
204
+ if (si === -1) break;
205
+ const ei = out.indexOf(end, si + start.length);
206
+ if (ei === -1) break;
207
+ // If another start marker appears before the next end marker, the
208
+ // current `si` is an unmatched start and pairing it with `ei` would
209
+ // delete the later valid block too. Leave the orphan in place and
210
+ // continue scanning from the inner start (which may itself pair with
211
+ // `ei`). This honours the contract that unmatched markers are left
212
+ // alone.
213
+ const nextStart = out.indexOf(start, si + start.length);
214
+ if (nextStart !== -1 && nextStart < ei) {
215
+ cursor = nextStart;
216
+ continue;
217
+ }
218
+ out = out.slice(0, si) + out.slice(ei + end.length);
219
+ cursor = si;
220
+ }
221
+ return out;
222
+ }
223
+
224
+ /**
225
+ * Remove any legacy-marker blocks from `text`. No-op when none are
226
+ * present, so it is safe to call on every upsert.
227
+ */
228
+ function stripLegacyBlocks(text) {
229
+ let out = text;
230
+ for (const m of LEGACY_MARKERS) {
231
+ out = stripAllBlocks(out, m.start, m.end);
232
+ }
233
+ return out;
234
+ }
235
+
236
+ /**
237
+ * Insert or update the managed block inside `filePath`.
238
+ *
239
+ * Behavior:
240
+ * - `~` in filePath is expanded via os.homedir()
241
+ * - If the file does not exist, create it containing just the block
242
+ * - Legacy-marker blocks (see LEGACY_MARKERS) are always purged first
243
+ * so plugin renames never leave stale copies behind
244
+ * - The FIRST current-marker block is replaced in place; any extra
245
+ * duplicates elsewhere in the file are removed
246
+ * - If no current-marker block exists in a non-empty file (first
247
+ * takeover of user-authored content), back up the untouched original
248
+ * to <backupRoot>/install-restore/claude-md-original.md (written once,
249
+ * first takeover wins) and REPLACE the file with just the block. If
250
+ * the backup cannot be written, fall back to appending the block so
251
+ * user content is never destroyed without a confirmed backup.
252
+ * - An empty / whitespace-only file is simply replaced with the block
253
+ * - Blank-line runs introduced by the stripping are collapsed and the
254
+ * file always ends with exactly one trailing newline
255
+ *
256
+ * @param {string} filePath
257
+ * @param {string} content — raw inner content (no markers)
258
+ */
259
+ function upsertManagedBlock(filePath, content) {
260
+ const resolved = expandHome(filePath);
261
+ const block = wrapBlock(content);
262
+
263
+ // Hold the file lock across the FULL read-modify-write window so a
264
+ // concurrent writer can't slip a different revision in between our
265
+ // read and our rename (last-writer-wins on managed-block edits).
266
+ // Mirrors the withConfigLock RMW pattern in src/shared/config.mjs.
267
+ withFileLockSync(`${resolved}.lock`, () => {
268
+ let existing = null;
269
+ try {
270
+ existing = fs.readFileSync(resolved, 'utf8');
271
+ } catch (err) {
272
+ if (err && err.code !== 'ENOENT') throw err;
273
+ }
274
+
275
+ if (existing === null) {
276
+ // File does not exist — create with just the block (trailing newline).
277
+ _atomicWriteUnlocked(resolved, block + '\n');
278
+ return;
279
+ }
280
+
281
+ // Purge legacy-marker blocks from any earlier plugin name. Only the
282
+ // gap left by legacy removal is normalised — user content outside the
283
+ // managed/legacy markers must be preserved verbatim per the header
284
+ // contract. Whole-file collapse / trailing-ws strip would silently
285
+ // rewrite the user's prose, code blocks, and intentional blank runs.
286
+ const cleaned = stripLegacyBlocks(existing);
287
+
288
+ const startIdx = cleaned.indexOf(MARKER_START);
289
+ const endIdx = cleaned.indexOf(MARKER_END, startIdx + MARKER_START.length);
290
+
291
+ let next;
292
+ if (startIdx !== -1 && endIdx !== -1) {
293
+ // Replace the first current-marker block in place. Any additional
294
+ // duplicate blocks in the tail are stripped so only one remains.
295
+ const before = cleaned.slice(0, startIdx);
296
+ const afterRaw = cleaned.slice(endIdx + MARKER_END.length);
297
+ const after = stripAllBlocks(afterRaw, MARKER_START, MARKER_END);
298
+ next = before + block + after;
299
+ } else if (cleaned.trim().length === 0) {
300
+ // Empty / whitespace-only file: nothing to preserve, just replace.
301
+ next = block + '\n';
302
+ } else if (ensureOriginalBackup(existing)) {
303
+ // First takeover of user-authored content with a confirmed backup:
304
+ // replace the whole file with just the managed block.
305
+ next = block + '\n';
306
+ } else if (cleaned.endsWith('\n\n')) {
307
+ // Backup could not be written — fall back to append so user content
308
+ // is never destroyed without a confirmed backup.
309
+ next = cleaned + block + '\n';
310
+ } else if (cleaned.endsWith('\n')) {
311
+ next = cleaned + '\n' + block + '\n';
312
+ } else {
313
+ next = cleaned + '\n\n' + block + '\n';
314
+ }
315
+
316
+ if (next !== existing) _atomicWriteUnlocked(resolved, next);
317
+ });
318
+ }
319
+
320
+ /**
321
+ * Remove the managed block (markers inclusive) from `filePath`, plus
322
+ * any legacy-marker blocks.
323
+ *
324
+ * Behavior:
325
+ * - `~` in filePath is expanded via os.homedir()
326
+ * - No-op if the file does not exist
327
+ * - Surgical removal: only bytes between/including managed and
328
+ * legacy markers are touched; user content outside the markers
329
+ * is preserved verbatim (no blank-line collapse).
330
+ * - Atomic write
331
+ *
332
+ * @param {string} filePath
333
+ * @returns {boolean} true if an actual write happened, false if no-op
334
+ */
335
+ function removeManagedBlock(filePath) {
336
+ const resolved = expandHome(filePath);
337
+
338
+ // Preserve the documented missing-file no-op before taking a lock:
339
+ // withFileLockSync creates the lock parent directory, which would be
340
+ // an observable side effect for a target that does not exist.
341
+ try {
342
+ fs.readFileSync(resolved, 'utf8');
343
+ } catch (err) {
344
+ if (err && err.code === 'ENOENT') return false;
345
+ throw err;
346
+ }
347
+
348
+ // Single lock around read+compute+rename: a concurrent upsert from
349
+ // another process must not slip between our read and our write, or
350
+ // the removal can race a re-injection and either lose the write or
351
+ // resurrect a stale block. Mirrors upsertManagedBlock's single-lock
352
+ // RMW (and withConfigLock in src/shared/config.mjs).
353
+ return withFileLockSync(`${resolved}.lock`, () => {
354
+ let existing;
355
+ try {
356
+ existing = fs.readFileSync(resolved, 'utf8');
357
+ } catch (err) {
358
+ if (err && err.code === 'ENOENT') return false;
359
+ throw err;
360
+ }
361
+
362
+ // Surgical removal: only bytes between/including the markers are
363
+ // touched. User content outside the managed/legacy markers is
364
+ // preserved verbatim per the header contract — whole-file collapse /
365
+ // trailing-ws strip would silently rewrite the user's prose, code
366
+ // blocks, and intentional blank runs (mirrors upsertManagedBlock's
367
+ // preservation guarantee on the file-existed path).
368
+ let next = existing;
369
+ next = stripAllBlocks(next, MARKER_START, MARKER_END);
370
+ next = stripLegacyBlocks(next);
371
+
372
+ if (next !== existing) {
373
+ _atomicWriteUnlocked(resolved, next);
374
+ return true;
375
+ }
376
+ return false;
377
+ });
378
+ }
379
+
380
+ module.exports = {
381
+ MARKER_START,
382
+ MARKER_END,
383
+ expandHome,
384
+ upsertManagedBlock,
385
+ removeManagedBlock,
386
+ };
@@ -0,0 +1,61 @@
1
+ 'use strict';
2
+ /**
3
+ * CJS shim for shared config reading in hooks.
4
+ *
5
+ * Read-only mirror of src/shared/config.mjs's section accessor. Hook
6
+ * processes only read mixdog-config.json — never write, never rename.
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+ const { resolvePluginData } = require('./plugin-paths.cjs');
12
+ const { getSecret: _getSecret } = require('./keychain-cjs.cjs');
13
+
14
+ const DATA_DIR = resolvePluginData();
15
+
16
+ const GENERATED_KEY = '_generated';
17
+
18
+ function stripGeneratedMarker(data) {
19
+ if (!data || typeof data !== 'object' || Array.isArray(data)) return data;
20
+ if (!Object.prototype.hasOwnProperty.call(data, GENERATED_KEY)) return data;
21
+ const { [GENERATED_KEY]: _unused, ...rest } = data;
22
+ return rest;
23
+ }
24
+
25
+ function readJsonFile(filePath) {
26
+ try {
27
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
28
+ } catch {
29
+ return null;
30
+ }
31
+ }
32
+
33
+ function readSection(section) {
34
+ const unified = readJsonFile(path.join(DATA_DIR, 'mixdog-config.json'));
35
+ if (!unified || typeof unified !== 'object') return {};
36
+ const raw = unified[section];
37
+ if (raw == null) return {};
38
+ return stripGeneratedMarker(raw) || {};
39
+ }
40
+
41
+ // ── Secret-aware getters (CJS, for hooks) ────────────────────────────────────
42
+ // Read order: ENV MIXDOG_<UPPER_SNAKE> → OS keychain → null.
43
+
44
+ function _envKey(account) {
45
+ return 'MIXDOG_' + account.replace(/[.\s]+/g, '_').toUpperCase();
46
+ }
47
+
48
+ function _readSecret(account) {
49
+ const envVal = process.env[_envKey(account)];
50
+ if (envVal) return envVal;
51
+ try { return _getSecret(account); } catch { return null; }
52
+ }
53
+
54
+ function getDiscordToken() {
55
+ return _readSecret('discord.token');
56
+ }
57
+
58
+ module.exports = {
59
+ readSection,
60
+ getDiscordToken,
61
+ };
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ // Single source for the hook IPC path. Centralizes an existing platform
4
+ // contract (not new heuristic). Rust mirror native/mixdog-shim/src/main.rs:34-43
5
+ // must stay in sync.
6
+ module.exports = function hookPipePath() {
7
+ return process.platform === 'win32'
8
+ ? '\\\\.\\pipe\\mixdog-hooks'
9
+ : require('path').join(process.env.XDG_RUNTIME_DIR || '/tmp', 'mixdog-hooks.sock');
10
+ };