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.
- package/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +20 -0
- package/.gitattributes +34 -0
- package/.mcp.json +14 -0
- package/ARCHITECTURE.md +77 -0
- package/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +45 -0
- package/DATA-FLOW.md +79 -0
- package/LICENSE +21 -0
- package/README.md +389 -0
- package/SECURITY.md +138 -0
- package/UNINSTALL.md +112 -0
- package/agents/maintenance.md +5 -0
- package/agents/memory-classification.md +30 -0
- package/agents/scheduler-task.md +18 -0
- package/agents/webhook-handler.md +27 -0
- package/agents/worker.md +24 -0
- package/bin/bridge +133 -0
- package/bin/statusline-launcher.mjs +78 -0
- package/bin/statusline-lib.mjs +550 -0
- package/bin/statusline.mjs +607 -0
- package/bun.lock +802 -0
- package/commands/config.md +16 -0
- package/commands/doctor.md +13 -0
- package/commands/setup.md +17 -0
- package/defaults/cycle3-review-prompt.md +90 -0
- package/defaults/hidden-roles.json +65 -0
- package/defaults/memory-chunk-prompt.md +63 -0
- package/defaults/memory-promote-prompt.md +135 -0
- package/defaults/mixdog-config.template.json +27 -0
- package/defaults/user-workflow.json +8 -0
- package/defaults/user-workflow.md +12 -0
- package/hooks/hooks.json +73 -0
- package/hooks/lib/active-instance.cjs +77 -0
- package/hooks/lib/permission-evaluator.cjs +411 -0
- package/hooks/lib/permission-route.cjs +63 -0
- package/hooks/lib/permission-rules.cjs +170 -0
- package/hooks/lib/settings-loader.cjs +116 -0
- package/hooks/post-tool-use.cjs +84 -0
- package/hooks/pre-mcp-sandbox.cjs +158 -0
- package/hooks/pre-tool-subagent.cjs +253 -0
- package/hooks/session-start.cjs +1372 -0
- package/hooks/turn-timer.cjs +82 -0
- package/lib/claude-md-writer.cjs +386 -0
- package/lib/config-cjs.cjs +61 -0
- package/lib/hook-pipe-path.cjs +10 -0
- package/lib/keychain-cjs.cjs +263 -0
- package/lib/plugin-paths.cjs +61 -0
- package/lib/rules-builder.cjs +241 -0
- package/lib/text-utils.cjs +61 -0
- package/native/README.md +117 -0
- package/native/prebuilt/linux-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/linux-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/macos-aarch64/mixdog-shim +0 -0
- package/native/prebuilt/macos-x86_64/mixdog-shim +0 -0
- package/native/prebuilt/windows-x86_64/mixdog-shim.exe +0 -0
- package/package.json +107 -0
- package/prompts/code-review.txt +16 -0
- package/prompts/security-audit.txt +17 -0
- package/rules/bridge/00-common.md +39 -0
- package/rules/bridge/20-skip-protocol.md +18 -0
- package/rules/bridge/30-explorer.md +33 -0
- package/rules/bridge/40-cycle1-agent.md +52 -0
- package/rules/bridge/41-cycle2-agent.md +62 -0
- package/rules/bridge/42-cycle3-agent.md +44 -0
- package/rules/lead/00-tool-lead.md +61 -0
- package/rules/lead/01-general.md +23 -0
- package/rules/lead/02-channels.md +49 -0
- package/rules/lead/03-team.md +27 -0
- package/rules/lead/04-workflow.md +20 -0
- package/rules/shared/00-language.md +14 -0
- package/rules/shared/01-tool.md +138 -0
- package/scripts/bootstrap.mjs +184 -0
- package/scripts/bridge-unify-smoke.mjs +308 -0
- package/scripts/build-runtime-linux.sh +348 -0
- package/scripts/build-runtime-macos.sh +217 -0
- package/scripts/build-runtime-windows.ps1 +242 -0
- package/scripts/builtin-utils-smoke.mjs +392 -0
- package/scripts/check-json.mjs +45 -0
- package/scripts/check-syntax-changed.mjs +102 -0
- package/scripts/check-syntax.mjs +58 -0
- package/scripts/code-graph-batch.test.mjs +33 -0
- package/scripts/config-preserve-smoke.mjs +180 -0
- package/scripts/doctor.mjs +484 -0
- package/scripts/edit-normalize-fuzz.mjs +130 -0
- package/scripts/edit-normalize-smoke.mjs +401 -0
- package/scripts/edit-operation-smoke.mjs +369 -0
- package/scripts/edit2-smoke.mjs +63 -0
- package/scripts/fuzzy-e2e.mjs +28 -0
- package/scripts/fuzzy-smoke.mjs +26 -0
- package/scripts/generate-runtime-manifest.mjs +166 -0
- package/scripts/guard-smoke.mjs +66 -0
- package/scripts/hidden-role-schema-smoke.mjs +162 -0
- package/scripts/hook-routing-smoke.mjs +29 -0
- package/scripts/inject-input.ps1 +204 -0
- package/scripts/io-complex-smoke.mjs +667 -0
- package/scripts/io-explore-bench.mjs +424 -0
- package/scripts/io-guardrails-smoke.mjs +205 -0
- package/scripts/io-mini-bench-baseline.json +11 -0
- package/scripts/io-mini-bench.mjs +216 -0
- package/scripts/io-route-harness.mjs +933 -0
- package/scripts/io-telemetry-report.mjs +691 -0
- package/scripts/mutation-bench.mjs +564 -0
- package/scripts/mutation-io-smoke.mjs +1081 -0
- package/scripts/native-patch-bridge-smoke.mjs +288 -0
- package/scripts/native-patch-smoke.mjs +304 -0
- package/scripts/patch-interior-context-smoke.mjs +49 -0
- package/scripts/patch-newline-utf8-smoke.mjs +157 -0
- package/scripts/perf-hook-smoke.mjs +71 -0
- package/scripts/permission-eval-smoke.mjs +426 -0
- package/scripts/prep-patch.mjs +53 -0
- package/scripts/prep-shim.mjs +96 -0
- package/scripts/provider-cache-smoke.mjs +687 -0
- package/scripts/report-runtime-health.mjs +132 -0
- package/scripts/run-mcp.mjs +1547 -0
- package/scripts/salvage-v4a-shatter.test.mjs +58 -0
- package/scripts/scoped-cache-io-smoke.mjs +103 -0
- package/scripts/shell-policy-round3-smoke.mjs +46 -0
- package/scripts/smoke-runtime-negative.ps1 +100 -0
- package/scripts/smoke-runtime-negative.sh +95 -0
- package/scripts/stall-policy-smoke.mjs +50 -0
- package/scripts/start-memory-worker.mjs +23 -0
- package/scripts/statusline-launcher-smoke.mjs +82 -0
- package/scripts/stress-atomic-write.mjs +1028 -0
- package/scripts/test-config-rmw-restore.mjs +122 -0
- package/scripts/test-fault-inject.mjs +164 -0
- package/scripts/test-large-file.mjs +174 -0
- package/scripts/tool-edge-smoke.mjs +209 -0
- package/scripts/uninstall.mjs +201 -0
- package/scripts/webhook-selfheal-smoke.mjs +29 -0
- package/scripts/write-overwrite-guard-smoke.mjs +56 -0
- package/server-main.mjs +3055 -0
- package/server.mjs +468 -0
- package/setup/config-merge.mjs +254 -0
- package/setup/install.mjs +120 -0
- package/setup/launch-core.mjs +507 -0
- package/setup/launch.mjs +101 -0
- package/setup/setup-server.mjs +3206 -0
- package/setup/setup.html +3693 -0
- package/skills/retro-skill-proposer/SKILL.md +92 -0
- package/skills/schedule-add/SKILL.md +77 -0
- package/skills/setup/SKILL.md +346 -0
- package/skills/webhook-add/SKILL.md +81 -0
- package/src/agent/bridge-stall-watchdog.mjs +337 -0
- package/src/agent/index.mjs +2138 -0
- package/src/agent/orchestrator/activity-bus.mjs +38 -0
- package/src/agent/orchestrator/ai-wrapped-dispatch.mjs +1010 -0
- package/src/agent/orchestrator/bridge-retry.mjs +220 -0
- package/src/agent/orchestrator/bridge-trace.mjs +583 -0
- package/src/agent/orchestrator/cache-mtime.mjs +58 -0
- package/src/agent/orchestrator/config.mjs +358 -0
- package/src/agent/orchestrator/context/collect.mjs +651 -0
- package/src/agent/orchestrator/dispatch-persist.mjs +549 -0
- package/src/agent/orchestrator/drain-registry.mjs +50 -0
- package/src/agent/orchestrator/explore-validator.mjs +8 -0
- package/src/agent/orchestrator/internal-roles.mjs +118 -0
- package/src/agent/orchestrator/internal-tools.mjs +88 -0
- package/src/agent/orchestrator/jobs.mjs +116 -0
- package/src/agent/orchestrator/mcp/client.mjs +364 -0
- package/src/agent/orchestrator/providers/anthropic-betas.mjs +21 -0
- package/src/agent/orchestrator/providers/anthropic-oauth.mjs +1745 -0
- package/src/agent/orchestrator/providers/anthropic.mjs +437 -0
- package/src/agent/orchestrator/providers/gemini.mjs +1175 -0
- package/src/agent/orchestrator/providers/grok-oauth.mjs +782 -0
- package/src/agent/orchestrator/providers/model-catalog.mjs +241 -0
- package/src/agent/orchestrator/providers/openai-compat.mjs +1467 -0
- package/src/agent/orchestrator/providers/openai-oauth-ws.mjs +1890 -0
- package/src/agent/orchestrator/providers/openai-oauth.mjs +1307 -0
- package/src/agent/orchestrator/providers/openai-ws.mjs +104 -0
- package/src/agent/orchestrator/providers/registry.mjs +192 -0
- package/src/agent/orchestrator/providers/retry-classifier.mjs +325 -0
- package/src/agent/orchestrator/session/abort-lookup.mjs +13 -0
- package/src/agent/orchestrator/session/cache/post-edit-marks.mjs +42 -0
- package/src/agent/orchestrator/session/cache/prefetch-cache.mjs +142 -0
- package/src/agent/orchestrator/session/cache/read-cache.mjs +319 -0
- package/src/agent/orchestrator/session/cache/scoped-cache-outcome.mjs +11 -0
- package/src/agent/orchestrator/session/cache/scoped-cache.mjs +361 -0
- package/src/agent/orchestrator/session/cache/util.mjs +49 -0
- package/src/agent/orchestrator/session/loop.mjs +1478 -0
- package/src/agent/orchestrator/session/manager.mjs +1975 -0
- package/src/agent/orchestrator/session/read-dedup.mjs +6 -0
- package/src/agent/orchestrator/session/result-classification.mjs +65 -0
- package/src/agent/orchestrator/session/save-session-worker.mjs +18 -0
- package/src/agent/orchestrator/session/store.mjs +624 -0
- package/src/agent/orchestrator/session/stream-watchdog.mjs +130 -0
- package/src/agent/orchestrator/session/tool-result-offload.mjs +166 -0
- package/src/agent/orchestrator/session/trim.mjs +491 -0
- package/src/agent/orchestrator/smart-bridge/CACHE-SHARD.md +115 -0
- package/src/agent/orchestrator/smart-bridge/bridge-llm.mjs +327 -0
- package/src/agent/orchestrator/smart-bridge/cache-obs.mjs +150 -0
- package/src/agent/orchestrator/smart-bridge/cache-strategy.mjs +228 -0
- package/src/agent/orchestrator/smart-bridge/index.mjs +215 -0
- package/src/agent/orchestrator/smart-bridge/profiles.mjs +37 -0
- package/src/agent/orchestrator/smart-bridge/registry.mjs +348 -0
- package/src/agent/orchestrator/smart-bridge/session-builder.mjs +116 -0
- package/src/agent/orchestrator/stall-policy.mjs +195 -0
- package/src/agent/orchestrator/tool-loop-guard.mjs +75 -0
- package/src/agent/orchestrator/tools/bash-policy-scan.mjs +77 -0
- package/src/agent/orchestrator/tools/bash-session.mjs +721 -0
- package/src/agent/orchestrator/tools/builtin/advisory-lock.mjs +171 -0
- package/src/agent/orchestrator/tools/builtin/arg-guard.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/atomic-write.mjs +236 -0
- package/src/agent/orchestrator/tools/builtin/bash-tool.mjs +480 -0
- package/src/agent/orchestrator/tools/builtin/binary-file.mjs +76 -0
- package/src/agent/orchestrator/tools/builtin/builtin-tools.mjs +256 -0
- package/src/agent/orchestrator/tools/builtin/cache-layers.mjs +386 -0
- package/src/agent/orchestrator/tools/builtin/cwd-utils.mjs +37 -0
- package/src/agent/orchestrator/tools/builtin/device-paths.mjs +154 -0
- package/src/agent/orchestrator/tools/builtin/diagnostics-tool.mjs +292 -0
- package/src/agent/orchestrator/tools/builtin/diff-utils.mjs +109 -0
- package/src/agent/orchestrator/tools/builtin/edit-base-guard.mjs +58 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-plan.mjs +240 -0
- package/src/agent/orchestrator/tools/builtin/edit-byte-utils.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/edit-commit.mjs +74 -0
- package/src/agent/orchestrator/tools/builtin/edit-context-utils.mjs +242 -0
- package/src/agent/orchestrator/tools/builtin/edit-diagnostics.mjs +211 -0
- package/src/agent/orchestrator/tools/builtin/edit-engine.mjs +1364 -0
- package/src/agent/orchestrator/tools/builtin/edit-failure-context.mjs +126 -0
- package/src/agent/orchestrator/tools/builtin/edit-hint.mjs +141 -0
- package/src/agent/orchestrator/tools/builtin/edit-match-utils.mjs +194 -0
- package/src/agent/orchestrator/tools/builtin/edit-partial-write.mjs +60 -0
- package/src/agent/orchestrator/tools/builtin/edit-stale-refresh.mjs +168 -0
- package/src/agent/orchestrator/tools/builtin/edit-tool.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/edit-utf8-guard.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fs-reachability.mjs +48 -0
- package/src/agent/orchestrator/tools/builtin/fuzzy-match.mjs +99 -0
- package/src/agent/orchestrator/tools/builtin/glob-walk.mjs +170 -0
- package/src/agent/orchestrator/tools/builtin/grep-formatting.mjs +113 -0
- package/src/agent/orchestrator/tools/builtin/hash-utils.mjs +6 -0
- package/src/agent/orchestrator/tools/builtin/list-formatting.mjs +7 -0
- package/src/agent/orchestrator/tools/builtin/list-tool.mjs +593 -0
- package/src/agent/orchestrator/tools/builtin/native-edit-runner.mjs +89 -0
- package/src/agent/orchestrator/tools/builtin/notebook-edit-tool.mjs +300 -0
- package/src/agent/orchestrator/tools/builtin/open-config-tool.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/path-diagnostics.mjs +152 -0
- package/src/agent/orchestrator/tools/builtin/path-locks.mjs +35 -0
- package/src/agent/orchestrator/tools/builtin/path-utils.mjs +201 -0
- package/src/agent/orchestrator/tools/builtin/read-args.mjs +103 -0
- package/src/agent/orchestrator/tools/builtin/read-batch.mjs +172 -0
- package/src/agent/orchestrator/tools/builtin/read-constants.mjs +40 -0
- package/src/agent/orchestrator/tools/builtin/read-formatting.mjs +118 -0
- package/src/agent/orchestrator/tools/builtin/read-image-resize.mjs +189 -0
- package/src/agent/orchestrator/tools/builtin/read-image.mjs +88 -0
- package/src/agent/orchestrator/tools/builtin/read-lines.mjs +12 -0
- package/src/agent/orchestrator/tools/builtin/read-mode-tool.mjs +455 -0
- package/src/agent/orchestrator/tools/builtin/read-open.mjs +190 -0
- package/src/agent/orchestrator/tools/builtin/read-range-index.mjs +271 -0
- package/src/agent/orchestrator/tools/builtin/read-ranges.mjs +26 -0
- package/src/agent/orchestrator/tools/builtin/read-single-tool.mjs +728 -0
- package/src/agent/orchestrator/tools/builtin/read-snapshot-runtime.mjs +173 -0
- package/src/agent/orchestrator/tools/builtin/read-special-files.mjs +268 -0
- package/src/agent/orchestrator/tools/builtin/read-streaming.mjs +602 -0
- package/src/agent/orchestrator/tools/builtin/read-tool.mjs +530 -0
- package/src/agent/orchestrator/tools/builtin/read-windows.mjs +107 -0
- package/src/agent/orchestrator/tools/builtin/rename-tool.mjs +196 -0
- package/src/agent/orchestrator/tools/builtin/rg-runner.mjs +422 -0
- package/src/agent/orchestrator/tools/builtin/search-builders.mjs +158 -0
- package/src/agent/orchestrator/tools/builtin/search-tool.mjs +869 -0
- package/src/agent/orchestrator/tools/builtin/shell-analysis.mjs +653 -0
- package/src/agent/orchestrator/tools/builtin/shell-jobs.mjs +936 -0
- package/src/agent/orchestrator/tools/builtin/shell-output.mjs +36 -0
- package/src/agent/orchestrator/tools/builtin/shell-runtime.mjs +214 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-helpers.mjs +143 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-store.mjs +206 -0
- package/src/agent/orchestrator/tools/builtin/snapshot-validation.mjs +98 -0
- package/src/agent/orchestrator/tools/builtin/text-stats.mjs +69 -0
- package/src/agent/orchestrator/tools/builtin/windows-roots.mjs +23 -0
- package/src/agent/orchestrator/tools/builtin/write-tool.mjs +401 -0
- package/src/agent/orchestrator/tools/builtin.mjs +500 -0
- package/src/agent/orchestrator/tools/code-graph-prewarm-worker.mjs +39 -0
- package/src/agent/orchestrator/tools/code-graph-tool-defs.mjs +24 -0
- package/src/agent/orchestrator/tools/code-graph.mjs +4095 -0
- package/src/agent/orchestrator/tools/cwd-tool.mjs +298 -0
- package/src/agent/orchestrator/tools/destructive-warning.mjs +323 -0
- package/src/agent/orchestrator/tools/edit-normalize.mjs +603 -0
- package/src/agent/orchestrator/tools/env-scrub.mjs +100 -0
- package/src/agent/orchestrator/tools/graph-binary-fetcher.mjs +144 -0
- package/src/agent/orchestrator/tools/graph-manifest.json +26 -0
- package/src/agent/orchestrator/tools/host-input.mjs +204 -0
- package/src/agent/orchestrator/tools/mutation-content-cache.mjs +67 -0
- package/src/agent/orchestrator/tools/mutation-planner.mjs +75 -0
- package/src/agent/orchestrator/tools/next-call-utils.mjs +48 -0
- package/src/agent/orchestrator/tools/patch-binary-fetcher.mjs +133 -0
- package/src/agent/orchestrator/tools/patch-manifest.json +26 -0
- package/src/agent/orchestrator/tools/patch-tool-defs.mjs +20 -0
- package/src/agent/orchestrator/tools/patch.mjs +2754 -0
- package/src/agent/orchestrator/tools/progress-message.mjs +118 -0
- package/src/agent/orchestrator/tools/result-compression.mjs +279 -0
- package/src/agent/orchestrator/tools/shell-command.mjs +865 -0
- package/src/agent/orchestrator/tools/shell-exec-policy.mjs +89 -0
- package/src/agent/orchestrator/tools/shell-policy-danger-target.mjs +27 -0
- package/src/agent/orchestrator/tools/shell-policy-imports.mjs +7 -0
- package/src/agent/orchestrator/tools/shell-policy.mjs +345 -0
- package/src/agent/orchestrator/tools/shell-snapshot.mjs +313 -0
- package/src/agent/orchestrator/workflow-store.mjs +93 -0
- package/src/agent/tool-defs.mjs +103 -0
- package/src/channels/backends/discord.mjs +784 -0
- package/src/channels/data/voice-runtime-manifest.json +138 -0
- package/src/channels/index.mjs +3229 -0
- package/src/channels/lib/cli-worker-host.mjs +12 -0
- package/src/channels/lib/config-lock.mjs +13 -0
- package/src/channels/lib/config.mjs +292 -0
- package/src/channels/lib/drop-trace.mjs +71 -0
- package/src/channels/lib/event-pipeline.mjs +81 -0
- package/src/channels/lib/event-queue.mjs +345 -0
- package/src/channels/lib/executor.mjs +168 -0
- package/src/channels/lib/format.mjs +188 -0
- package/src/channels/lib/holidays.mjs +138 -0
- package/src/channels/lib/hook-pipe-server.mjs +802 -0
- package/src/channels/lib/interaction-workflows.mjs +184 -0
- package/src/channels/lib/memory-client.mjs +149 -0
- package/src/channels/lib/output-forwarder.mjs +765 -0
- package/src/channels/lib/runtime-paths.mjs +479 -0
- package/src/channels/lib/scheduler.mjs +723 -0
- package/src/channels/lib/session-control.mjs +36 -0
- package/src/channels/lib/session-discovery.mjs +103 -0
- package/src/channels/lib/settings.mjs +11 -0
- package/src/channels/lib/state-file.mjs +68 -0
- package/src/channels/lib/status-snapshot.mjs +219 -0
- package/src/channels/lib/tool-format.mjs +140 -0
- package/src/channels/lib/transcript-discovery.mjs +195 -0
- package/src/channels/lib/voice-runtime-fetcher.mjs +734 -0
- package/src/channels/lib/webhook.mjs +1179 -0
- package/src/channels/lib/whisper-server.mjs +477 -0
- package/src/channels/tool-defs.mjs +170 -0
- package/src/daemon/host.mjs +118 -0
- package/src/daemon/mcp-transport.mjs +47 -0
- package/src/daemon/session.mjs +100 -0
- package/src/daemon/thin-client.mjs +71 -0
- package/src/daemon/transport.mjs +163 -0
- package/src/memory/data/runtime-manifest.json +40 -0
- package/src/memory/index.mjs +3305 -0
- package/src/memory/lib/agent-ipc.mjs +93 -0
- package/src/memory/lib/bridge-trace-queries.mjs +120 -0
- package/src/memory/lib/core-memory-store.mjs +330 -0
- package/src/memory/lib/embedding-provider.mjs +269 -0
- package/src/memory/lib/embedding-worker.mjs +323 -0
- package/src/memory/lib/llm-worker-host.mjs +17 -0
- package/src/memory/lib/memory-cycle.mjs +11 -0
- package/src/memory/lib/memory-cycle1.mjs +641 -0
- package/src/memory/lib/memory-cycle2.mjs +1284 -0
- package/src/memory/lib/memory-cycle3.mjs +540 -0
- package/src/memory/lib/memory-embed.mjs +299 -0
- package/src/memory/lib/memory-extraction.mjs +5 -0
- package/src/memory/lib/memory-maintenance-store.mjs +32 -0
- package/src/memory/lib/memory-ops-policy.mjs +190 -0
- package/src/memory/lib/memory-recall-id-patch.mjs +15 -0
- package/src/memory/lib/memory-recall-read-query.mjs +7 -0
- package/src/memory/lib/memory-recall-scope-filter.mjs +63 -0
- package/src/memory/lib/memory-recall-store.mjs +621 -0
- package/src/memory/lib/memory-retrievers.mjs +112 -0
- package/src/memory/lib/memory-score.mjs +71 -0
- package/src/memory/lib/memory-text-utils.mjs +58 -0
- package/src/memory/lib/memory.mjs +412 -0
- package/src/memory/lib/model-profile.mjs +85 -0
- package/src/memory/lib/pg/adapter.mjs +308 -0
- package/src/memory/lib/pg/process.mjs +360 -0
- package/src/memory/lib/pg/supervisor.mjs +396 -0
- package/src/memory/lib/project-id-resolver.mjs +86 -0
- package/src/memory/lib/runtime-fetcher.mjs +442 -0
- package/src/memory/lib/trace-store.mjs +728 -0
- package/src/memory/tool-defs.mjs +79 -0
- package/src/search/index.mjs +1173 -0
- package/src/search/lib/backends/anthropic-oauth.mjs +98 -0
- package/src/search/lib/backends/exa.mjs +50 -0
- package/src/search/lib/backends/firecrawl.mjs +61 -0
- package/src/search/lib/backends/gemini-api.mjs +83 -0
- package/src/search/lib/backends/grok-oauth.mjs +86 -0
- package/src/search/lib/backends/index.mjs +150 -0
- package/src/search/lib/backends/openai-api.mjs +144 -0
- package/src/search/lib/backends/openai-oauth.mjs +98 -0
- package/src/search/lib/backends/openai-web-search.mjs +76 -0
- package/src/search/lib/backends/tavily.mjs +55 -0
- package/src/search/lib/backends/xai-api.mjs +113 -0
- package/src/search/lib/cache.mjs +131 -0
- package/src/search/lib/config.mjs +192 -0
- package/src/search/lib/formatter.mjs +115 -0
- package/src/search/lib/provider-usage.mjs +67 -0
- package/src/search/lib/providers.mjs +47 -0
- package/src/search/lib/search-intent.mjs +109 -0
- package/src/search/lib/setup-handler.mjs +261 -0
- package/src/search/lib/state.mjs +201 -0
- package/src/search/lib/web-tools.mjs +1207 -0
- package/src/search/tool-defs.mjs +83 -0
- package/src/setup/defender-exclusion.mjs +183 -0
- package/src/shared/abort-controller.mjs +15 -0
- package/src/shared/atomic-file.mjs +420 -0
- package/src/shared/config.mjs +350 -0
- package/src/shared/daemon-recycle.mjs +108 -0
- package/src/shared/disable-claude-builtins.mjs +88 -0
- package/src/shared/err-text.mjs +12 -0
- package/src/shared/llm/cost.mjs +66 -0
- package/src/shared/llm/http-agent.mjs +123 -0
- package/src/shared/llm/index.mjs +41 -0
- package/src/shared/llm/pid-cleanup.mjs +27 -0
- package/src/shared/llm/usage-log.mjs +47 -0
- package/src/shared/plugin-paths.mjs +58 -0
- package/src/shared/schedules-store.mjs +70 -0
- package/src/shared/seed.mjs +119 -0
- package/src/shared/user-cwd.mjs +213 -0
- package/src/shared/user-data-guard.mjs +238 -0
- package/src/status/aggregator.mjs +584 -0
- package/src/status/server.mjs +413 -0
- 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
|
+
}
|