mixdog 0.9.151 → 0.9.153
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/LICENSES/browser-import-NOTICE.txt +11 -0
- package/NOTICE.md +11 -0
- package/README.md +108 -68
- package/package.json +17 -4
- package/scripts/computer-task-cost-report.mjs +144 -0
- package/scripts/run-office-live-tests.mjs +32 -0
- package/scripts/tool-stress.mjs +0 -2
- package/src/agents/front-worker/AGENT.md +13 -0
- package/src/agents/front-worker/agent.json +6 -0
- package/src/agents/heavy-worker/AGENT.md +10 -11
- package/src/agents/heavy-worker/agent.json +1 -1
- package/src/agents/maintainer/AGENT.md +0 -2
- package/src/agents/reviewer/AGENT.md +9 -13
- package/src/agents/reviewer/agent.json +1 -1
- package/src/agents/security/AGENT.md +14 -0
- package/src/agents/security/agent.json +6 -0
- package/src/agents/worker/AGENT.md +8 -8
- package/src/agents/worker/agent.json +1 -1
- package/src/agents/writer/AGENT.md +14 -0
- package/src/agents/writer/agent.json +6 -0
- package/src/defaults/skills/setup/SKILL.md +18 -27
- package/src/headless-exec.mjs +3 -10
- package/src/headless-exec.test.mjs +2 -7
- package/src/rules/agent/00-common.md +4 -7
- package/src/rules/lead/01-general.md +0 -3
- package/src/rules/shared/10-tool-workflow.md +10 -2
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.mjs +183 -26
- package/src/runtime/agent/orchestrator/agent-runtime/agent-dispatch.test.mjs +378 -0
- package/src/runtime/agent/orchestrator/agent-runtime/session-builder.mjs +4 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.mjs +109 -0
- package/src/runtime/agent/orchestrator/cache-break-trace.test.mjs +115 -0
- package/src/runtime/agent/orchestrator/config.mjs +13 -68
- package/src/runtime/agent/orchestrator/context/collect-skills.test.mjs +153 -0
- package/src/runtime/agent/orchestrator/context/collect.mjs +49 -45
- package/src/runtime/agent/orchestrator/mcp/client.mjs +242 -15
- package/src/runtime/agent/orchestrator/mcp/features.test.mjs +66 -0
- package/src/runtime/agent/orchestrator/mcp/security.test.mjs +36 -20
- package/src/runtime/agent/orchestrator/providers/admission-scheduler-metrics.test.mjs +47 -0
- package/src/runtime/agent/orchestrator/providers/admission-scheduler.mjs +16 -3
- package/src/runtime/agent/orchestrator/providers/anthropic-sse.mjs +54 -33
- package/src/runtime/agent/orchestrator/providers/anthropic.mjs +1 -0
- package/src/runtime/agent/orchestrator/providers/antigravity-oauth.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/gemini-schema.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/gemini-stream.mjs +3 -8
- package/src/runtime/agent/orchestrator/providers/gemini.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/lib/anthropic-request-utils.mjs +19 -3
- package/src/runtime/agent/orchestrator/providers/lib/provider-replay.mjs +50 -0
- package/src/runtime/agent/orchestrator/providers/lib/sse-framing.mjs +93 -0
- package/src/runtime/agent/orchestrator/providers/media-normalization.mjs +30 -9
- package/src/runtime/agent/orchestrator/providers/media-parity.test.mjs +59 -0
- package/src/runtime/agent/orchestrator/providers/model-list-sanitize.mjs +3 -3
- package/src/runtime/agent/orchestrator/providers/openai-codex-identity.test.mjs +71 -0
- package/src/runtime/agent/orchestrator/providers/openai-codex-metadata.mjs +18 -26
- package/src/runtime/agent/orchestrator/providers/openai-compat-presets.mjs +8 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-stream.mjs +7 -0
- package/src/runtime/agent/orchestrator/providers/openai-compat-wire.mjs +25 -2
- package/src/runtime/agent/orchestrator/providers/openai-compat.mjs +35 -4
- package/src/runtime/agent/orchestrator/providers/openai-oauth-http-sse.mjs +47 -2
- package/src/runtime/agent/orchestrator/providers/openai-oauth-ws.mjs +103 -12
- package/src/runtime/agent/orchestrator/providers/openai-responses-payload.mjs +13 -0
- package/src/runtime/agent/orchestrator/providers/openai-turn-state.mjs +68 -0
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta-parity.test.mjs +122 -6
- package/src/runtime/agent/orchestrator/providers/openai-ws-delta.mjs +36 -11
- package/src/runtime/agent/orchestrator/providers/openai-ws-pool.mjs +144 -93
- package/src/runtime/agent/orchestrator/providers/openai-ws-stream.mjs +18 -13
- package/src/runtime/agent/orchestrator/providers/provider-replay.test.mjs +288 -0
- package/src/runtime/agent/orchestrator/providers/sse-framing.test.mjs +719 -0
- package/src/runtime/agent/orchestrator/providers/stream-json-pool.mjs +399 -39
- package/src/runtime/agent/orchestrator/providers/stream-json-worker.mjs +26 -0
- package/src/runtime/agent/orchestrator/session/agent-loop.mjs +86 -7
- package/src/runtime/agent/orchestrator/session/agent-loop.test.mjs +222 -0
- package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.mjs +61 -0
- package/src/runtime/agent/orchestrator/session/browser-snapshot-supersession.test.mjs +83 -0
- package/src/runtime/agent/orchestrator/session/cache/read-cache.mjs +13 -0
- package/src/runtime/agent/orchestrator/session/compact/runner.mjs +26 -2
- package/src/runtime/agent/orchestrator/session/compact-policy.test.mjs +112 -0
- package/src/runtime/agent/orchestrator/session/compaction-read-reset.test.mjs +192 -0
- package/src/runtime/agent/orchestrator/session/context-usage-restart.test.mjs +72 -0
- package/src/runtime/agent/orchestrator/session/context-utils.mjs +100 -15
- package/src/runtime/agent/orchestrator/session/eager-dispatch.mjs +17 -1
- package/src/runtime/agent/orchestrator/session/eager-dispatch.test.mjs +74 -0
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.mjs +12 -8
- package/src/runtime/agent/orchestrator/session/image-strip-recovery.test.mjs +20 -1
- package/src/runtime/agent/orchestrator/session/loop/compact-policy.mjs +110 -2
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.mjs +3 -16
- package/src/runtime/agent/orchestrator/session/loop/pre-dispatch-deny.test.mjs +28 -0
- package/src/runtime/agent/orchestrator/session/loop/recall-fasttrack.mjs +2 -2
- package/src/runtime/agent/orchestrator/session/loop/steering.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/loop/tool-exec.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/loop/tool-helpers.mjs +6 -0
- package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +111 -39
- package/src/runtime/agent/orchestrator/session/manager/ask-session.test.mjs +46 -0
- package/src/runtime/agent/orchestrator/session/manager/compaction-runner.mjs +30 -6
- package/src/runtime/agent/orchestrator/session/manager/message-sanitize.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +27 -3
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.mjs +26 -54
- package/src/runtime/agent/orchestrator/session/manager/session-lifecycle.test.mjs +63 -1
- package/src/runtime/agent/orchestrator/session/manager/status-telemetry.mjs +3 -0
- package/src/runtime/agent/orchestrator/session/manager/tool-resolution.mjs +4 -110
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.mjs +580 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint-journal.test.mjs +593 -0
- package/src/runtime/agent/orchestrator/session/manager/turn-checkpoint.mjs +119 -190
- package/src/runtime/agent/orchestrator/session/manager/turn-interruption.mjs +115 -0
- package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +43 -8
- package/src/runtime/agent/orchestrator/session/provider-prefix-guard.mjs +129 -12
- package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +9 -2
- package/src/runtime/agent/orchestrator/session/store/listing.mjs +8 -1
- package/src/runtime/agent/orchestrator/session/store/save-worker.mjs +15 -1
- package/src/runtime/agent/orchestrator/session/store-live-publication.test.mjs +83 -0
- package/src/runtime/agent/orchestrator/session/store-summary-index.mjs +36 -2
- package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +157 -30
- package/src/runtime/agent/orchestrator/session/store-summary-reader.test.mjs +64 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +57 -0
- package/src/runtime/agent/orchestrator/session/store-summary-visibility.test.mjs +219 -0
- package/src/runtime/agent/orchestrator/session/store.mjs +26 -2
- package/src/runtime/agent/orchestrator/session/tool-batch.mjs +22 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool-cwd-env.test.mjs +14 -0
- package/src/runtime/agent/orchestrator/tools/builtin/bash-tool.mjs +19 -10
- package/src/runtime/agent/orchestrator/tools/builtin/find-search-budget.test.mjs +30 -14
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-policy.mjs +15 -4
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +73 -15
- package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.test.mjs +76 -2
- package/src/runtime/agent/orchestrator/tools/builtin/list-tool.mjs +24 -683
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-client.mjs +64 -72
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-runner.mjs +2 -5
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.mjs +75 -0
- package/src/runtime/agent/orchestrator/tools/builtin/native-search-transport.test.mjs +24 -0
- package/src/runtime/agent/orchestrator/tools/builtin/read-special-files.mjs +6 -6
- package/src/runtime/agent/orchestrator/tools/code-graph/build.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/constants.mjs +4 -1
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.mjs +24 -5
- package/src/runtime/agent/orchestrator/tools/code-graph/dispatch.test.mjs +44 -0
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-binary.mjs +12 -2
- package/src/runtime/agent/orchestrator/tools/code-graph/graph-model.mjs +35 -21
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.mjs +28 -13
- package/src/runtime/agent/orchestrator/tools/code-graph/memory-cache.test.mjs +54 -0
- package/src/runtime/agent/orchestrator/tools/graph-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/patch-manifest.json +11 -11
- package/src/runtime/agent/orchestrator/tools/progress-message.mjs +12 -0
- package/src/runtime/agent/orchestrator/tools/spawn-manifest.json +11 -11
- package/src/runtime/attachments/pdf-extract.mjs +3 -0
- package/src/runtime/attachments/pdfjs-runtime.mjs +13 -0
- package/src/runtime/bridge-clients.test.mjs +827 -0
- package/src/runtime/browser-bridge/action-schema.mjs +251 -0
- package/src/runtime/browser-bridge/client.mjs +152 -0
- package/src/runtime/browser-bridge/tool-defs.mjs +159 -0
- package/src/runtime/computer-bridge/action-schema.mjs +653 -0
- package/src/runtime/computer-bridge/client.mjs +231 -0
- package/src/runtime/computer-bridge/tool-defs.mjs +33 -0
- package/src/runtime/media/store.mjs +18 -8
- package/src/runtime/media/store.test.mjs +14 -0
- package/src/runtime/memory/index.mjs +1 -1
- package/src/runtime/memory/lib/transcript-ingest.mjs +8 -6
- package/src/runtime/memory/lib/transcript-ingest.test.mjs +52 -0
- package/src/runtime/office/assurance-benchmark.mjs +358 -0
- package/src/runtime/office/assurance.mjs +833 -0
- package/src/runtime/office/benchmark.mjs +496 -0
- package/src/runtime/office/capabilities.mjs +551 -0
- package/src/runtime/office/com-adapter.mjs +283 -0
- package/src/runtime/office/content-model.mjs +183 -0
- package/src/runtime/office/contract-benchmark.mjs +105 -0
- package/src/runtime/office/design-library.mjs +1562 -0
- package/src/runtime/office/design-system.mjs +1966 -0
- package/src/runtime/office/index.mjs +2413 -0
- package/src/runtime/office/journal.mjs +82 -0
- package/src/runtime/office/office-assurance.test.mjs +371 -0
- package/src/runtime/office/office-com-host.ps1 +3781 -0
- package/src/runtime/office/office-com-session-host.ps1 +855 -0
- package/src/runtime/office/office-live-runtime.test.mjs +819 -0
- package/src/runtime/office/office-runtime.test.mjs +2070 -0
- package/src/runtime/office/ooxml-validator.mjs +271 -0
- package/src/runtime/office/pagination.mjs +132 -0
- package/src/runtime/office/pdf-adapter.mjs +591 -0
- package/src/runtime/office/pdf-analysis.mjs +372 -0
- package/src/runtime/office/pdf-render.mjs +167 -0
- package/src/runtime/office/pdf-security.mjs +63 -0
- package/src/runtime/office/polish-benchmark.mjs +190 -0
- package/src/runtime/office/portable-ooxml.mjs +1867 -0
- package/src/runtime/office/quality-live-benchmark.mjs +486 -0
- package/src/runtime/office/quality-pipeline.mjs +136 -0
- package/src/runtime/office/tabular.mjs +302 -0
- package/src/runtime/office/templates/mixdog-executive.pptx +0 -0
- package/src/runtime/office/templates/mixdog-executive.pptx.mixdog.json +190 -0
- package/src/runtime/office/tool-defs.mjs +113 -0
- package/src/runtime/office/visual-diff.mjs +89 -0
- package/src/runtime/office/xlsx-assertions.mjs +172 -0
- package/src/runtime/office/xlsx-contract.mjs +147 -0
- package/src/runtime/shared/agent-route-config.mjs +9 -0
- package/src/runtime/shared/child-spawn-gate.mjs +17 -0
- package/src/runtime/shared/child-spawn-remote.mjs +69 -7
- package/src/runtime/shared/child-spawn-remote.test.mjs +124 -0
- package/src/runtime/shared/pristine-execution-contract.json +2 -1
- package/src/runtime/shared/provider-api-key.mjs +1 -0
- package/src/runtime/shared/session-runtime-health.mjs +91 -0
- package/src/runtime/shared/session-runtime-health.test.mjs +53 -0
- package/src/runtime/shared/skill-document.mjs +86 -0
- package/src/runtime/shared/skill-document.test.mjs +81 -0
- package/src/runtime/shared/tool-execution-contract.mjs +16 -0
- package/src/runtime/shared/tool-surface.mjs +27 -0
- package/src/runtime/shared/turn-snapshot-store.mjs +1 -0
- package/src/runtime/shared/turn-snapshot.mjs +32 -9
- package/src/runtime/shared/user-cwd.mjs +33 -14
- package/src/runtime/shared/user-cwd.test.mjs +43 -0
- package/src/session-runtime/agent-disable.test.mjs +20 -1
- package/src/session-runtime/context-status.mjs +9 -3
- package/src/session-runtime/cwd-plugins.mjs +26 -26
- package/src/session-runtime/cwd-plugins.test.mjs +75 -0
- package/src/session-runtime/cwd-tool-routing.test.mjs +5 -0
- package/src/session-runtime/deferred-tool-delta.mjs +104 -0
- package/src/session-runtime/deferred-tool-delta.test.mjs +40 -0
- package/src/session-runtime/global-extensions.mjs +26 -0
- package/src/session-runtime/global-extensions.test.mjs +28 -0
- package/src/session-runtime/global-settings-session-identity.test.mjs +76 -0
- package/src/session-runtime/goal-runtime.mjs +1141 -0
- package/src/session-runtime/goal-runtime.test.mjs +645 -0
- package/src/session-runtime/lifecycle-api.mjs +58 -11
- package/src/session-runtime/lifecycle-api.test.mjs +183 -0
- package/src/session-runtime/mcp-glue.mjs +49 -47
- package/src/session-runtime/plugin-mcp-standard.test.mjs +177 -0
- package/src/session-runtime/plugin-mcp.mjs +96 -22
- package/src/session-runtime/prewarm.mjs +1 -10
- package/src/session-runtime/provider-request-snapshot.mjs +33 -9
- package/src/session-runtime/provider-request-snapshot.test.mjs +27 -5
- package/src/session-runtime/resource-api-global.test.mjs +109 -0
- package/src/session-runtime/resource-api.mjs +168 -116
- package/src/session-runtime/runtime-core.mjs +208 -29
- package/src/session-runtime/runtime-tunables.mjs +6 -8
- package/src/session-runtime/session-lifecycle.mjs +34 -12
- package/src/session-runtime/session-title.mjs +2 -2
- package/src/session-runtime/session-turn-api.mjs +37 -25
- package/src/session-runtime/skills-api.mjs +79 -25
- package/src/session-runtime/skills-api.test.mjs +99 -0
- package/src/session-runtime/tool-catalog-data.mjs +1 -1
- package/src/session-runtime/tool-catalog-schema.mjs +0 -5
- package/src/session-runtime/tool-catalog.mjs +42 -112
- package/src/session-runtime/tool-defs.mjs +6 -1
- package/src/session-runtime/tool-policy-surface.test.mjs +93 -17
- package/src/session-runtime/tool-surface.mjs +30 -8
- package/src/session-runtime/workflow-agents-api.mjs +8 -25
- package/src/session-runtime/workflow.mjs +8 -6
- package/src/standalone/agent-dispatch-broker.mjs +5 -9
- package/src/standalone/agent-tool/helpers.mjs +2 -2
- package/src/standalone/agent-tool/job-views.mjs +3 -1
- package/src/standalone/agent-tool/notify.mjs +11 -9
- package/src/standalone/agent-tool/notify.test.mjs +37 -0
- package/src/standalone/agent-tool/render.mjs +3 -0
- package/src/standalone/agent-tool/spawn-flow.mjs +61 -16
- package/src/standalone/agent-tool/spawn-flow.test.mjs +41 -0
- package/src/standalone/agent-tool/tool-def.mjs +1 -1
- package/src/standalone/agent-tool/worker-index.mjs +123 -0
- package/src/standalone/agent-tool/worker-index.test.mjs +132 -0
- package/src/standalone/agent-tool/worker-rows.mjs +2 -1
- package/src/standalone/agent-tool.mjs +57 -10
- package/src/standalone/daemon.mjs +113 -15
- package/src/standalone/hook-bus/config.mjs +1 -0
- package/src/standalone/plugin-admin.mjs +17 -0
- package/src/standalone/plugin-admin.test.mjs +7 -0
- package/src/standalone/provider-admin.mjs +1 -0
- package/src/standalone/session-protocol.mjs +5 -0
- package/src/standalone/session-runtime-agent-control-client.mjs +133 -0
- package/src/standalone/session-runtime-agent-control-client.test.mjs +71 -0
- package/src/standalone/session-runtime-dispatch-cancel.test.mjs +139 -0
- package/src/standalone/session-runtime-host-factory.mjs +17 -0
- package/src/standalone/session-runtime-host-factory.test.mjs +31 -0
- package/src/standalone/session-runtime-host-health.test.mjs +5 -0
- package/src/standalone/session-runtime-host.mjs +709 -58
- package/src/standalone/session-runtime-inline-host.mjs +258 -0
- package/src/standalone/session-runtime-inline-host.test.mjs +385 -0
- package/src/standalone/session-runtime-provider-cooldown.mjs +78 -0
- package/src/standalone/session-runtime-provider-cooldown.test.mjs +80 -0
- package/src/standalone/session-runtime-shard-host.test.mjs +642 -0
- package/src/standalone/session-runtime-shard-router.mjs +149 -0
- package/src/standalone/session-runtime-shard-router.test.mjs +101 -0
- package/src/standalone/session-runtime-worker.mjs +302 -26
- package/src/standalone/session-service-agent-tree.test.mjs +984 -0
- package/src/standalone/session-service-goal-recovery.test.mjs +177 -0
- package/src/standalone/session-service.mjs +711 -11
- package/src/tui/app/app-view.jsx +1 -0
- package/src/tui/app/core-memory-picker.mjs +2 -0
- package/src/tui/app/extension-pickers.mjs +1 -1
- package/src/tui/app/maintenance-pickers.mjs +3 -3
- package/src/tui/app/model-options.mjs +2 -0
- package/src/tui/app/model-picker.mjs +14 -4
- package/src/tui/app/panel-handoff.test.mjs +311 -0
- package/src/tui/app/project-picker.mjs +1 -0
- package/src/tui/app/route-pickers.mjs +21 -6
- package/src/tui/app/settings-picker.mjs +26 -3
- package/src/tui/app/slash-commands.mjs +1 -0
- package/src/tui/app/slash-dispatch.mjs +73 -22
- package/src/tui/app/theme-effort-pickers.mjs +7 -2
- package/src/tui/components/Picker.jsx +10 -1
- package/src/tui/dist/index.mjs +187 -45
- package/src/tui/lib/voice-setup.mjs +4 -1
- package/src/tui/session/agent-message-source.test.mjs +37 -0
- package/src/tui/session/completion-card-restore.test.mjs +50 -0
- package/src/tui/session/context-state.mjs +3 -13
- package/src/tui/session/goal-continuation.mjs +141 -0
- package/src/tui/session/goal-continuation.test.mjs +203 -0
- package/src/tui/session/queue-helpers.mjs +5 -2
- package/src/tui/session/session-action-surface.test.mjs +190 -0
- package/src/tui/session/session-api-ext.mjs +48 -8
- package/src/tui/session/session-api.mjs +73 -1
- package/src/tui/session/session-flow.mjs +31 -1
- package/src/tui/session/turn.mjs +88 -15
- package/src/tui/session-local.mjs +39 -3
- package/src/vendor/statusline/src/gateway/route-meta.mjs +31 -0
- package/src/runtime/agent/orchestrator/tools/builtin/fuzzy-match.mjs +0 -301
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { resolvePluginData } from '../../shared/plugin-paths.mjs';
|
|
2
2
|
import { readSection, updateSection, updateSectionAsync, getAgentApiKey, AGENT_PROVIDER_ENV } from '../../shared/config.mjs';
|
|
3
3
|
import {
|
|
4
|
+
DEFAULT_DISABLED_AGENT_IDS,
|
|
4
5
|
agentRouteStorageNeedsMigration,
|
|
5
6
|
canonicalizeAgentRouteStorage,
|
|
6
7
|
} from '../../shared/agent-route-config.mjs';
|
|
@@ -147,7 +148,7 @@ export const DEFAULT_PRESETS = Object.freeze([
|
|
|
147
148
|
Object.freeze({ id: 'opus-mid', name: 'OPUS MID', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('opus'), effort: 'medium', tools: 'full' }),
|
|
148
149
|
Object.freeze({ id: 'opus-high', name: 'OPUS HIGH', type: 'agent', provider: 'anthropic-oauth', model: resolveAnthropicFamilyModel('opus'), effort: 'high', tools: 'full' }),
|
|
149
150
|
]);
|
|
150
|
-
function buildDefaultConfig(options = {}) {
|
|
151
|
+
export function buildDefaultConfig(options = {}) {
|
|
151
152
|
const detectCredentials = options.detectCredentials !== false;
|
|
152
153
|
const providers = {};
|
|
153
154
|
// API providers — enabled if env key exists
|
|
@@ -196,36 +197,17 @@ function buildDefaultConfig(options = {}) {
|
|
|
196
197
|
// Local providers — opt-in via setup UI after HTTP ping confirms server is running
|
|
197
198
|
providers.ollama = { enabled: false, baseURL: 'http://localhost:11434/v1' };
|
|
198
199
|
providers.lmstudio = { enabled: false, baseURL: 'http://localhost:1234/v1' };
|
|
199
|
-
return {
|
|
200
|
+
return {
|
|
201
|
+
providers,
|
|
202
|
+
disabledAgents: [...DEFAULT_DISABLED_AGENT_IDS],
|
|
203
|
+
workflow: { active: 'default' },
|
|
204
|
+
};
|
|
200
205
|
}
|
|
201
206
|
|
|
202
207
|
function hasKeys(value) {
|
|
203
208
|
return !!value && typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length > 0;
|
|
204
209
|
}
|
|
205
210
|
|
|
206
|
-
// Process-local write intent for project MCP overrides. A loaded config contains
|
|
207
|
-
// snapshots for every project, but only entries toggled by this process may
|
|
208
|
-
// override a newer value read from disk inside the save lock.
|
|
209
|
-
const dirtyMcpProjectOverrides = new Map();
|
|
210
|
-
let mcpProjectOverrideDirtySeq = 0;
|
|
211
|
-
function mcpProjectOverrideDirtyKey(projectKey, serverName) {
|
|
212
|
-
return `${String(projectKey)}\u0000${String(serverName)}`;
|
|
213
|
-
}
|
|
214
|
-
export function markMcpProjectOverrideDirty(projectKey, serverName, enabled) {
|
|
215
|
-
const pairKey = mcpProjectOverrideDirtyKey(projectKey, serverName);
|
|
216
|
-
dirtyMcpProjectOverrides.set(pairKey, {
|
|
217
|
-
enabled: enabled !== false,
|
|
218
|
-
seq: ++mcpProjectOverrideDirtySeq,
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
function clearDurablySavedMcpProjectOverrides(appliedDirty) {
|
|
222
|
-
for (const { pairKey, seq } of appliedDirty) {
|
|
223
|
-
if (dirtyMcpProjectOverrides.get(pairKey)?.seq === seq) {
|
|
224
|
-
dirtyMcpProjectOverrides.delete(pairKey);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
211
|
function normalizeWebSearchRoute(route) {
|
|
230
212
|
if (!route || typeof route !== 'object' || Array.isArray(route))
|
|
231
213
|
return null;
|
|
@@ -435,6 +417,7 @@ function canonicalizeLegacyAgentStorage(value = {}) {
|
|
|
435
417
|
delete next.capabilities;
|
|
436
418
|
delete next.defaultProvider;
|
|
437
419
|
delete next.guide;
|
|
420
|
+
delete next.mcpProjectOverrides;
|
|
438
421
|
return next;
|
|
439
422
|
}
|
|
440
423
|
|
|
@@ -451,6 +434,7 @@ function agentConfigStorageNeedsMigration(value = {}) {
|
|
|
451
434
|
|| Object.prototype.hasOwnProperty.call(value || {}, 'searchRoute')
|
|
452
435
|
|| Object.prototype.hasOwnProperty.call(value || {}, 'capabilities')
|
|
453
436
|
|| Object.prototype.hasOwnProperty.call(value || {}, 'defaultProvider')
|
|
437
|
+
|| Object.prototype.hasOwnProperty.call(value || {}, 'mcpProjectOverrides')
|
|
454
438
|
|| presets.some((preset) => !normalizePreset(preset))
|
|
455
439
|
|| (modules && typeof modules === 'object' && Object.prototype.hasOwnProperty.call(modules, 'memory'))
|
|
456
440
|
|| normalizedFields.some((key) => JSON.stringify(value?.[key]) !== JSON.stringify(canonical?.[key]));
|
|
@@ -560,9 +544,6 @@ export function loadConfig(options = {}) {
|
|
|
560
544
|
const loaded = canonicalizeAgentRouteStorage({
|
|
561
545
|
providers: mergedProviders,
|
|
562
546
|
mcpServers,
|
|
563
|
-
mcpProjectOverrides: raw.mcpProjectOverrides && typeof raw.mcpProjectOverrides === 'object' && !Array.isArray(raw.mcpProjectOverrides)
|
|
564
|
-
? raw.mcpProjectOverrides
|
|
565
|
-
: {},
|
|
566
547
|
presets: normalizedPresets,
|
|
567
548
|
default: raw.default || null,
|
|
568
549
|
maintenance: { ...DEFAULT_MAINTENANCE, ...normalizedMaint },
|
|
@@ -628,7 +609,6 @@ export function loadConfig(options = {}) {
|
|
|
628
609
|
return {
|
|
629
610
|
...defaults,
|
|
630
611
|
mcpServers: {},
|
|
631
|
-
mcpProjectOverrides: {},
|
|
632
612
|
presets: DEFAULT_PRESETS.map(p => ({ ...p })),
|
|
633
613
|
default: null,
|
|
634
614
|
maintenance: { ...DEFAULT_MAINTENANCE },
|
|
@@ -691,7 +671,7 @@ export async function patchSkillsDisabledAsync(disabledNames) {
|
|
|
691
671
|
return nextSkills;
|
|
692
672
|
}
|
|
693
673
|
|
|
694
|
-
function buildAgentSaveBuilder(config
|
|
674
|
+
function buildAgentSaveBuilder(config) {
|
|
695
675
|
const canonicalRoutes = canonicalizeLegacyAgentStorage(config);
|
|
696
676
|
// Strip ephemeral defaults from providers but preserve any unknown
|
|
697
677
|
// per-provider subkey so future schema additions round-trip through the
|
|
@@ -745,42 +725,10 @@ function buildAgentSaveBuilder(config, appliedDirty) {
|
|
|
745
725
|
// a concurrent instance survive the save (lost-update guard).
|
|
746
726
|
return (existingRaw) => {
|
|
747
727
|
const mcpServers = config.mcpServers || {};
|
|
748
|
-
const diskOverrides = existingRaw.mcpProjectOverrides && typeof existingRaw.mcpProjectOverrides === 'object'
|
|
749
|
-
? existingRaw.mcpProjectOverrides
|
|
750
|
-
: {};
|
|
751
|
-
const memoryOverrides = config.mcpProjectOverrides && typeof config.mcpProjectOverrides === 'object'
|
|
752
|
-
? config.mcpProjectOverrides
|
|
753
|
-
: {};
|
|
754
|
-
const mcpProjectOverrides = {};
|
|
755
|
-
for (const projectKey of new Set([...Object.keys(diskOverrides), ...Object.keys(memoryOverrides)])) {
|
|
756
|
-
const diskProject = diskOverrides[projectKey] && typeof diskOverrides[projectKey] === 'object'
|
|
757
|
-
? diskOverrides[projectKey]
|
|
758
|
-
: {};
|
|
759
|
-
const memoryProject = memoryOverrides[projectKey] && typeof memoryOverrides[projectKey] === 'object'
|
|
760
|
-
? memoryOverrides[projectKey]
|
|
761
|
-
: {};
|
|
762
|
-
// Disk wins for untouched snapshot entries. Only an override this
|
|
763
|
-
// process explicitly toggled may replace the in-lock disk value.
|
|
764
|
-
const mergedProject = { ...memoryProject, ...diskProject };
|
|
765
|
-
for (const serverName of Object.keys(memoryProject)) {
|
|
766
|
-
const pairKey = mcpProjectOverrideDirtyKey(projectKey, serverName);
|
|
767
|
-
const dirty = dirtyMcpProjectOverrides.get(pairKey);
|
|
768
|
-
if (dirty) {
|
|
769
|
-
const appliedValue = { enabled: dirty.enabled };
|
|
770
|
-
mergedProject[serverName] = appliedValue;
|
|
771
|
-
appliedDirty.push({ pairKey, seq: dirty.seq, appliedValue });
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
for (const serverName of Object.keys(mergedProject)) {
|
|
775
|
-
if (!Object.prototype.hasOwnProperty.call(mcpServers, serverName)) delete mergedProject[serverName];
|
|
776
|
-
}
|
|
777
|
-
if (Object.keys(mergedProject).length > 0) mcpProjectOverrides[projectKey] = mergedProject;
|
|
778
|
-
}
|
|
779
728
|
const next = {
|
|
780
729
|
...existingRaw,
|
|
781
730
|
providers: persistedProviders,
|
|
782
731
|
mcpServers,
|
|
783
|
-
mcpProjectOverrides,
|
|
784
732
|
presets,
|
|
785
733
|
default: config.default || null,
|
|
786
734
|
maintenance: canonicalRoutes.maintenance,
|
|
@@ -810,19 +758,16 @@ function buildAgentSaveBuilder(config, appliedDirty) {
|
|
|
810
758
|
delete next.capabilities;
|
|
811
759
|
delete next.defaultProvider;
|
|
812
760
|
delete next.guide;
|
|
761
|
+
delete next.mcpProjectOverrides;
|
|
813
762
|
return next;
|
|
814
763
|
};
|
|
815
764
|
}
|
|
816
765
|
export function saveConfig(config) {
|
|
817
|
-
|
|
818
|
-
persistAgentConfig(buildAgentSaveBuilder(config, appliedDirty));
|
|
819
|
-
clearDurablySavedMcpProjectOverrides(appliedDirty);
|
|
766
|
+
persistAgentConfig(buildAgentSaveBuilder(config));
|
|
820
767
|
}
|
|
821
768
|
// Async twin used by the debounced config-save flush timer.
|
|
822
769
|
export async function saveConfigAsync(config) {
|
|
823
|
-
|
|
824
|
-
await persistAgentConfigAsync(buildAgentSaveBuilder(config, appliedDirty));
|
|
825
|
-
clearDurablySavedMcpProjectOverrides(appliedDirty);
|
|
770
|
+
await persistAgentConfigAsync(buildAgentSaveBuilder(config));
|
|
826
771
|
}
|
|
827
772
|
// --- Preset helpers ---
|
|
828
773
|
// preset shape: { id, name, type: 'agent', provider, model, effort?, fast?, tools? }
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import test from 'node:test';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
collectSkillsCached,
|
|
9
|
+
invalidateSkillsCache,
|
|
10
|
+
loadSkillResource,
|
|
11
|
+
} from './collect.mjs';
|
|
12
|
+
|
|
13
|
+
test('discovers global standard skill folders and ignores project-local skills and reference Markdown', () => {
|
|
14
|
+
const root = mkdtempSync(join(tmpdir(), 'mixdog-standard-skill-'));
|
|
15
|
+
const previousDataDir = process.env.MIXDOG_DATA_DIR;
|
|
16
|
+
process.env.MIXDOG_DATA_DIR = join(root, 'data');
|
|
17
|
+
try {
|
|
18
|
+
const cwd = join(root, 'project');
|
|
19
|
+
const skillDir = join(process.env.MIXDOG_DATA_DIR, 'skills', 'copied-skill');
|
|
20
|
+
const projectSkillDir = join(cwd, '.mixdog', 'skills', 'project-only');
|
|
21
|
+
mkdirSync(join(skillDir, 'references'), { recursive: true });
|
|
22
|
+
mkdirSync(join(skillDir, 'scripts'), { recursive: true });
|
|
23
|
+
mkdirSync(projectSkillDir, { recursive: true });
|
|
24
|
+
writeFileSync(join(skillDir, 'SKILL.md'), [
|
|
25
|
+
'---',
|
|
26
|
+
'name: copied-skill',
|
|
27
|
+
'description: >',
|
|
28
|
+
' Use when a copied standard skill',
|
|
29
|
+
' should be discovered.',
|
|
30
|
+
'metadata:',
|
|
31
|
+
' source: external',
|
|
32
|
+
'---',
|
|
33
|
+
'',
|
|
34
|
+
'# Instructions',
|
|
35
|
+
'',
|
|
36
|
+
'Read `references/guide.md` and run `scripts/check.py` when needed.',
|
|
37
|
+
'',
|
|
38
|
+
].join('\n'));
|
|
39
|
+
writeFileSync(join(skillDir, 'references', 'guide.md'), [
|
|
40
|
+
'---',
|
|
41
|
+
'name: not-a-skill',
|
|
42
|
+
'description: This reference must never become a skill.',
|
|
43
|
+
'---',
|
|
44
|
+
'',
|
|
45
|
+
'# Reference',
|
|
46
|
+
'',
|
|
47
|
+
].join('\n'));
|
|
48
|
+
writeFileSync(join(skillDir, 'scripts', 'check.py'), 'print("ok")\n');
|
|
49
|
+
writeFileSync(join(projectSkillDir, 'SKILL.md'), [
|
|
50
|
+
'---',
|
|
51
|
+
'name: project-only',
|
|
52
|
+
'description: This project-local skill must be ignored.',
|
|
53
|
+
'---',
|
|
54
|
+
'',
|
|
55
|
+
'# Project instructions',
|
|
56
|
+
'',
|
|
57
|
+
].join('\n'));
|
|
58
|
+
|
|
59
|
+
invalidateSkillsCache(cwd);
|
|
60
|
+
const copied = collectSkillsCached(cwd)
|
|
61
|
+
.find((skill) => skill.name === 'copied-skill');
|
|
62
|
+
assert.ok(copied);
|
|
63
|
+
assert.equal(copied.description,
|
|
64
|
+
'Use when a copied standard skill should be discovered.');
|
|
65
|
+
assert.equal(collectSkillsCached(cwd)
|
|
66
|
+
.some((skill) => skill.name === 'not-a-skill'), false);
|
|
67
|
+
assert.equal(collectSkillsCached(cwd)
|
|
68
|
+
.some((skill) => skill.name === 'project-only'), false);
|
|
69
|
+
|
|
70
|
+
const loaded = loadSkillResource('copied-skill', cwd);
|
|
71
|
+
assert.match(loaded.content, /^# Instructions/);
|
|
72
|
+
assert.equal(loaded.dir, skillDir);
|
|
73
|
+
assert.equal(existsSync(join(loaded.dir, 'references', 'guide.md')), true);
|
|
74
|
+
assert.equal(existsSync(join(loaded.dir, 'scripts', 'check.py')), true);
|
|
75
|
+
} finally {
|
|
76
|
+
invalidateSkillsCache(join(root, 'project'));
|
|
77
|
+
if (previousDataDir === undefined) delete process.env.MIXDOG_DATA_DIR;
|
|
78
|
+
else process.env.MIXDOG_DATA_DIR = previousDataDir;
|
|
79
|
+
rmSync(root, { recursive: true, force: true });
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test('loads skills only from globally enabled plugins', () => {
|
|
84
|
+
const root = mkdtempSync(join(tmpdir(), 'mixdog-plugin-skill-'));
|
|
85
|
+
const previousDataDir = process.env.MIXDOG_DATA_DIR;
|
|
86
|
+
process.env.MIXDOG_DATA_DIR = join(root, 'data');
|
|
87
|
+
try {
|
|
88
|
+
const enabledRoot = join(root, 'enabled-plugin');
|
|
89
|
+
const disabledRoot = join(root, 'disabled-plugin');
|
|
90
|
+
const writeSkill = (pluginRoot, name) => {
|
|
91
|
+
const dir = join(pluginRoot, 'skills', name);
|
|
92
|
+
mkdirSync(dir, { recursive: true });
|
|
93
|
+
writeFileSync(join(dir, 'SKILL.md'), [
|
|
94
|
+
'---',
|
|
95
|
+
`name: ${name}`,
|
|
96
|
+
`description: Use when ${name} is needed.`,
|
|
97
|
+
'---',
|
|
98
|
+
'',
|
|
99
|
+
'# Instructions',
|
|
100
|
+
'',
|
|
101
|
+
].join('\n'));
|
|
102
|
+
};
|
|
103
|
+
writeSkill(enabledRoot, 'enabled-plugin-skill');
|
|
104
|
+
writeSkill(disabledRoot, 'disabled-plugin-skill');
|
|
105
|
+
const registryDir = join(process.env.MIXDOG_DATA_DIR, 'plugins');
|
|
106
|
+
mkdirSync(registryDir, { recursive: true });
|
|
107
|
+
writeFileSync(join(registryDir, 'registry.json'), JSON.stringify({
|
|
108
|
+
plugins: [
|
|
109
|
+
{ id: 'enabled', root: enabledRoot, enabled: true },
|
|
110
|
+
{ id: 'disabled', root: disabledRoot, enabled: false },
|
|
111
|
+
],
|
|
112
|
+
}));
|
|
113
|
+
|
|
114
|
+
invalidateSkillsCache();
|
|
115
|
+
const names = collectSkillsCached(join(root, 'any-project')).map((skill) => skill.name);
|
|
116
|
+
assert.equal(names.includes('enabled-plugin-skill'), true);
|
|
117
|
+
assert.equal(names.includes('disabled-plugin-skill'), false);
|
|
118
|
+
} finally {
|
|
119
|
+
invalidateSkillsCache();
|
|
120
|
+
if (previousDataDir === undefined) delete process.env.MIXDOG_DATA_DIR;
|
|
121
|
+
else process.env.MIXDOG_DATA_DIR = previousDataDir;
|
|
122
|
+
rmSync(root, { recursive: true, force: true });
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test('requires a standard folder name that matches the manifest name', () => {
|
|
127
|
+
const root = mkdtempSync(join(tmpdir(), 'mixdog-mismatched-skill-'));
|
|
128
|
+
const previousDataDir = process.env.MIXDOG_DATA_DIR;
|
|
129
|
+
process.env.MIXDOG_DATA_DIR = join(root, 'data');
|
|
130
|
+
try {
|
|
131
|
+
const cwd = join(root, 'project');
|
|
132
|
+
const skillDir = join(process.env.MIXDOG_DATA_DIR, 'skills', 'folder-name');
|
|
133
|
+
mkdirSync(skillDir, { recursive: true });
|
|
134
|
+
writeFileSync(join(skillDir, 'SKILL.md'), [
|
|
135
|
+
'---',
|
|
136
|
+
'name: different-name',
|
|
137
|
+
'description: Use when testing mismatched folders.',
|
|
138
|
+
'---',
|
|
139
|
+
'',
|
|
140
|
+
'# Instructions',
|
|
141
|
+
'',
|
|
142
|
+
].join('\n'));
|
|
143
|
+
|
|
144
|
+
invalidateSkillsCache(cwd);
|
|
145
|
+
assert.equal(collectSkillsCached(cwd)
|
|
146
|
+
.some((skill) => skill.name === 'different-name'), false);
|
|
147
|
+
} finally {
|
|
148
|
+
invalidateSkillsCache(join(root, 'project'));
|
|
149
|
+
if (previousDataDir === undefined) delete process.env.MIXDOG_DATA_DIR;
|
|
150
|
+
else process.env.MIXDOG_DATA_DIR = previousDataDir;
|
|
151
|
+
rmSync(root, { recursive: true, force: true });
|
|
152
|
+
}
|
|
153
|
+
});
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { readFileSync, existsSync, readdirSync } from 'fs';
|
|
2
2
|
import { homedir } from 'os';
|
|
3
|
-
import { dirname, join } from 'path';
|
|
3
|
+
import { basename, dirname, join } from 'path';
|
|
4
4
|
import { maxMtimeRecursive } from '../cache-mtime.mjs';
|
|
5
5
|
import { resolvePluginData, mixdogRoot } from '../../../shared/plugin-paths.mjs';
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
readMarkdownDocument,
|
|
9
|
-
} from '../../../shared/markdown-frontmatter.mjs';
|
|
6
|
+
import { readMarkdownDocument } from '../../../shared/markdown-frontmatter.mjs';
|
|
7
|
+
import { parseSkillDocument } from '../../../shared/skill-document.mjs';
|
|
10
8
|
import { loadConfig, normalizeSkillsConfig } from '../config.mjs';
|
|
11
9
|
|
|
12
10
|
function skillsDisabled() {
|
|
@@ -14,8 +12,8 @@ function skillsDisabled() {
|
|
|
14
12
|
}
|
|
15
13
|
|
|
16
14
|
// --- mixdog asset roots (standalone CLI owns its own paths; never .claude) ---
|
|
17
|
-
// Project-local
|
|
18
|
-
//
|
|
15
|
+
// Skills are machine-global under <mixdogData>/skills. Project-local skill
|
|
16
|
+
// directories are intentionally outside the runtime resolution chain.
|
|
19
17
|
function mixdogHome() {
|
|
20
18
|
return process.env.MIXDOG_HOME || join(homedir(), '.mixdog');
|
|
21
19
|
}
|
|
@@ -27,16 +25,8 @@ function mixdogGlobalDir(kind) {
|
|
|
27
25
|
return join(process.env.MIXDOG_DATA_DIR || join(mixdogHome(), 'data'), kind);
|
|
28
26
|
}
|
|
29
27
|
}
|
|
30
|
-
function
|
|
31
|
-
return
|
|
32
|
-
}
|
|
33
|
-
/** Ordered asset search dirs for a kind: project-local first, then global. */
|
|
34
|
-
function mixdogAssetDirs(projectDir, kind) {
|
|
35
|
-
const dirs = [];
|
|
36
|
-
const local = mixdogProjectDir(projectDir, kind);
|
|
37
|
-
if (local) dirs.push(local);
|
|
38
|
-
dirs.push(mixdogGlobalDir(kind));
|
|
39
|
-
return dirs;
|
|
28
|
+
function mixdogAssetDirs(_projectDir, kind) {
|
|
29
|
+
return [mixdogGlobalDir(kind)];
|
|
40
30
|
}
|
|
41
31
|
/**
|
|
42
32
|
* Absolute path to the plugin registry file, or null when the data dir is
|
|
@@ -70,6 +60,8 @@ function pluginSkillDirs() {
|
|
|
70
60
|
return [];
|
|
71
61
|
const dirs = [];
|
|
72
62
|
for (const entry of registry.plugins) {
|
|
63
|
+
if (entry?.enabled === false)
|
|
64
|
+
continue;
|
|
73
65
|
const root = entry && typeof entry.root === 'string' ? entry.root : null;
|
|
74
66
|
if (!root || !existsSync(root))
|
|
75
67
|
continue;
|
|
@@ -85,19 +77,11 @@ function pluginSkillDirs() {
|
|
|
85
77
|
*/
|
|
86
78
|
export function collectSkills(cwd) {
|
|
87
79
|
if (skillsDisabled()) return [];
|
|
88
|
-
|
|
89
|
-
// cwd:null on purpose so provider-cache shards don't fork per caller
|
|
90
|
-
// workspace), skip project-scoped skills entirely — DO NOT fall back
|
|
91
|
-
// to process.cwd(), which would leak the MCP launch dir into the
|
|
92
|
-
// shard key and fragment the cache.
|
|
93
|
-
const projectDir = (typeof cwd === 'string' && cwd.length > 0) ? cwd : null;
|
|
80
|
+
void cwd;
|
|
94
81
|
const skills = [];
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
const dirs = mixdogAssetDirs(projectDir, 'skills');
|
|
99
|
-
// Plugin-provided skills load last so project-local and global mixdog
|
|
100
|
-
// skill dirs keep precedence; `seen` below dedupes by frontmatter name.
|
|
82
|
+
const dirs = mixdogAssetDirs(null, 'skills');
|
|
83
|
+
// Plugin-provided skills load last so user-global skills keep precedence;
|
|
84
|
+
// `seen` below dedupes by frontmatter name.
|
|
101
85
|
dirs.push(...pluginSkillDirs());
|
|
102
86
|
const seen = new Set();
|
|
103
87
|
for (const dir of dirs) {
|
|
@@ -106,21 +90,27 @@ export function collectSkills(cwd) {
|
|
|
106
90
|
try {
|
|
107
91
|
const files = readdirSync(dir, { recursive: true });
|
|
108
92
|
for (const f of files) {
|
|
109
|
-
if (
|
|
93
|
+
if (basename(String(f)) !== 'SKILL.md')
|
|
110
94
|
continue;
|
|
111
95
|
const filePath = join(dir, String(f));
|
|
112
96
|
const content = readSafe(filePath);
|
|
113
97
|
if (!content)
|
|
114
98
|
continue;
|
|
115
|
-
|
|
116
|
-
|
|
99
|
+
let skill;
|
|
100
|
+
try {
|
|
101
|
+
skill = parseSkillDocument(content);
|
|
102
|
+
} catch {
|
|
117
103
|
continue;
|
|
118
|
-
|
|
104
|
+
}
|
|
105
|
+
// Agent Skills requires the manifest name to match its folder.
|
|
106
|
+
if (basename(dirname(filePath)) !== skill.name)
|
|
119
107
|
continue;
|
|
120
|
-
seen.
|
|
108
|
+
if (seen.has(skill.name))
|
|
109
|
+
continue;
|
|
110
|
+
seen.add(skill.name);
|
|
121
111
|
skills.push({
|
|
122
|
-
name:
|
|
123
|
-
description:
|
|
112
|
+
name: skill.name,
|
|
113
|
+
description: skill.description,
|
|
124
114
|
filePath,
|
|
125
115
|
});
|
|
126
116
|
}
|
|
@@ -167,10 +157,10 @@ const _mtimeCache = new Map();
|
|
|
167
157
|
const _MTIME_TTL_MS = 2000;
|
|
168
158
|
export function collectSkillsCached(cwd) {
|
|
169
159
|
if (skillsDisabled()) return [];
|
|
170
|
-
|
|
171
|
-
const
|
|
160
|
+
void cwd;
|
|
161
|
+
const key = 'global';
|
|
172
162
|
// Same mixdog-owned dirs collectSkills() reads, used as the freshness gate.
|
|
173
|
-
const skillsDirs = mixdogAssetDirs(
|
|
163
|
+
const skillsDirs = mixdogAssetDirs(null, 'skills');
|
|
174
164
|
skillsDirs.push(...pluginSkillDirs());
|
|
175
165
|
// registry.json itself gates plugin add/remove: removal deletes the
|
|
176
166
|
// plugin's skills dir (so no dir mtime advances), but saveRegistry()
|
|
@@ -200,6 +190,11 @@ export function collectSkillsCached(cwd) {
|
|
|
200
190
|
}
|
|
201
191
|
return skills;
|
|
202
192
|
}
|
|
193
|
+
export function invalidateSkillsCache(cwd) {
|
|
194
|
+
void cwd;
|
|
195
|
+
_skillsCache.clear();
|
|
196
|
+
_mtimeCache.clear();
|
|
197
|
+
}
|
|
203
198
|
/**
|
|
204
199
|
* Load full skill content by name.
|
|
205
200
|
*/
|
|
@@ -209,7 +204,12 @@ function loadSkillContent(name, cwd) {
|
|
|
209
204
|
if (!skill)
|
|
210
205
|
return null;
|
|
211
206
|
const content = readSafe(skill.filePath);
|
|
212
|
-
|
|
207
|
+
if (content == null) return null;
|
|
208
|
+
try {
|
|
209
|
+
return parseSkillDocument(content).body;
|
|
210
|
+
} catch {
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
215
|
/**
|
|
@@ -226,11 +226,15 @@ export function loadSkillResource(name, cwd) {
|
|
|
226
226
|
const content = readSafe(skill.filePath);
|
|
227
227
|
if (content == null)
|
|
228
228
|
return null;
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
229
|
+
try {
|
|
230
|
+
return {
|
|
231
|
+
content: parseSkillDocument(content).body,
|
|
232
|
+
dir: dirname(skill.filePath),
|
|
233
|
+
filePath: skill.filePath,
|
|
234
|
+
};
|
|
235
|
+
} catch {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
234
238
|
}
|
|
235
239
|
|
|
236
240
|
function escapeSkillXmlText(value) {
|