@aiwg/cli 2026.10.1 → 2026.10.4
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/README.md +2 -2
- package/agentic/code/providers/capability-matrix.yaml +270 -0
- package/agentic/code/providers/model-capabilities.v1.json +3183 -24
- package/bin/aiwg.mjs +135 -47
- package/dist/src/a2a/codecs.js +9 -0
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +57 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +285 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +65 -0
- package/dist/src/artifacts/index-refresh.js +576 -0
- package/dist/src/artifacts/index-worker.mjs +9 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/repair.js +9 -4
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +78 -12
- package/dist/src/cli/child-process-result.js +40 -0
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/env.js +38 -16
- package/dist/src/cli/flag-parsing.js +236 -0
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +218 -5
- package/dist/src/cli/handlers/diagnose.js +13 -5
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/feedback.js +14 -5
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +248 -30
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/mc.js +23 -0
- package/dist/src/cli/handlers/models.js +169 -10
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/ralph.js +3 -0
- package/dist/src/cli/handlers/refresh.js +28 -0
- package/dist/src/cli/handlers/regenerate.js +14 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +25 -11
- package/dist/src/cli/handlers/script-runner.js +19 -8
- package/dist/src/cli/handlers/session.js +406 -62
- package/dist/src/cli/handlers/sessions.js +243 -76
- package/dist/src/cli/handlers/setup-manifest.js +474 -79
- package/dist/src/cli/handlers/setup.js +180 -39
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +60 -3
- package/dist/src/cli/handlers/team.js +18 -8
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +307 -55
- package/dist/src/cli/handlers/utilities.js +125 -26
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/prompt-utils.js +72 -0
- package/dist/src/cli/provider-resolution.js +11 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +349 -35
- package/dist/src/config/cli.js +256 -23
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-health.mjs +14 -3
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +38 -11
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/adapters/jev.js +75 -27
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +14 -7
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +25 -6
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +15 -14
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/index.js +1 -0
- package/dist/src/decision/interop.js +60 -8
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +942 -0
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/decision/validate.js +6 -3
- package/dist/src/effects/dispatch-verifier.js +252 -0
- package/dist/src/effects/index.js +1 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/features/installer.js +2 -2
- package/dist/src/flow/graph-metadata.js +5 -0
- package/dist/src/gates/providers/loader.js +64 -18
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +15 -3
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +95 -5
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +366 -56
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +620 -85
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-file.mjs +279 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/config-layers.mjs +348 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/credentials.mjs +484 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +17 -27
- package/dist/src/mcp/helpers.mjs +109 -4
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/omp-config.mjs +50 -29
- package/dist/src/mcp/profiles.js +97 -23
- package/dist/src/mcp/profiles.mjs +99 -27
- package/dist/src/mcp/registry.js +248 -131
- package/dist/src/mcp/registry.mjs +169 -100
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +127 -82
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-string.mjs +9 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tool-filters.mjs +357 -0
- package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
- package/dist/src/mcp/tools/decision.mjs +22 -3
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +50 -2
- package/dist/src/mcp/tools/subsystems.mjs +39 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
- package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
- package/dist/src/memory/project-registry.js +2 -2
- package/dist/src/mission-protocol/codecs.js +647 -1
- package/dist/src/mission-protocol/types.js +110 -0
- package/dist/src/mission-protocol/worker-status.js +2 -0
- package/dist/src/models/config-loader.js +76 -14
- package/dist/src/models/grok-build-models.js +93 -41
- package/dist/src/models/model-capabilities.v1.json +3183 -24
- package/dist/src/models/model-discovery.js +931 -67
- package/dist/src/models/provider-policy.js +719 -11
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/qualification-digest.mjs +17 -0
- package/dist/src/models/resolver.js +261 -0
- package/dist/src/models/worker-direct-readiness.js +550 -0
- package/dist/src/models/worker-dispatch-offer.js +169 -0
- package/dist/src/models/worker-health-readiness.js +144 -0
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +986 -0
- package/dist/src/models/wrapper-route.js +18 -0
- package/dist/src/ops/registry.js +9 -14
- package/dist/src/plugins/standalone-packager.js +4 -3
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +430 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/cli-command.mjs +75 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/capability-matrix.js +8 -0
- package/dist/src/providers/capability-matrix.yaml +270 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +53 -23
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/provider-definitions.js +9 -1
- package/dist/src/providers/provider-definitions.mjs +9 -2
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/executor-registry.js +16 -24
- package/dist/src/serve/fleet-mission-conductor.js +9 -0
- package/dist/src/serve/mission-conductor.js +47 -12
- package/dist/src/serve/shared-host-scheduler.js +2 -0
- package/dist/src/serve/worker-invocation.js +558 -0
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/serve/worker-stdin-frame.mjs +107 -0
- package/dist/src/sessions/adapter-registry.js +49 -0
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +82 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +43 -9
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
- package/dist/src/sessions/adapters/grokbot.js +434 -24
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
- package/dist/src/sessions/adapters/muse.js +200 -104
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +30 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +25 -5
- package/dist/src/sessions/batch-import.js +72 -51
- package/dist/src/sessions/candidates.js +47 -11
- package/dist/src/sessions/contracts.js +75 -2
- package/dist/src/sessions/coverage-preflight.js +134 -0
- package/dist/src/sessions/discovery.js +3 -0
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/grok-build-cli.js +67 -5
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +84 -46
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +133 -25
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +106 -0
- package/dist/src/sessions/repository.js +199 -63
- package/dist/src/sessions/workspace-discovery.js +315 -88
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/adapters/clawhub.js +10 -8
- package/dist/src/skills/adapters/openclaw.js +10 -7
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +195 -14
- package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
- package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
- package/dist/src/smiths/mcpsmith/example.js +1 -1
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +85 -31
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/logseq.js +68 -7
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
- package/dist/src/testing/generators/test-code-generator.js +57 -30
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/uhp/client.js +11 -1
- package/dist/src/uhp/mission.js +5 -0
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/checker.mjs +5 -5
- package/dist/src/update/notifier.mjs +54 -2
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/dist/src/writing/fidelity.js +18 -1
- package/package.json +32 -2
- package/schemas/mission-v1.schema.json +2429 -0
- package/schemas/models/model-catalog.v1.schema.json +301 -0
- package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
- package/schemas/models/model-policy.v1.schema.json +14 -0
- package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
- package/tools/_resolve-impl.mjs +39 -2
- package/tools/agents/deploy-agents.mjs +64 -23
- package/tools/agents/providers/base.mjs +153 -166
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/grokbot.mjs +11 -12
- package/tools/agents/providers/hermes.mjs +62 -49
- package/tools/agents/providers/omp.mjs +5 -2
- package/tools/agents/providers/openclaw-translator.mjs +19 -5
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +360 -0
- package/tools/providers/omp-transport.mjs +194 -0
- package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
- package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
- package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
- package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
- package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
- package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
- package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +439 -0
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +2916 -0
package/dist/src/mcp/registry.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import { tomlString } from './toml-string.mjs';
|
|
2
|
+
import { buildServerConfig as renderServerConfig } from './server-config.mjs';
|
|
3
|
+
import { isLowerLayerEntry, loadLayered, lowerEntryQualified, resolveConfigLayers, saveLayerData } from './config-layers.mjs';
|
|
4
|
+
import { assertConfigDestination, assertProjectCredentials, classifyMcpDestination, projectCredentialRemedy, writeConfigAtomic, writeConfigTransaction } from './config-file.mjs';
|
|
1
5
|
import { manageOmpMcp } from './omp-config.mjs';
|
|
2
6
|
import { manageGrokBuildMcp } from './grok-build-config.mjs';
|
|
3
7
|
import { replaceServer } from './toml-editor.mjs';
|
|
4
8
|
import { resolveOmpPaths } from '../providers/omp-paths.mjs';
|
|
9
|
+
import { applyJsonToolFilterPlan, claudeSettingsPath, prepareClaudePermissions, planToolFilters } from './tool-filters.mjs';
|
|
10
|
+
import { assertCredentialPolicy, resolveCredentialPolicy, validateEnvReferenceName } from './credentials.mjs';
|
|
5
11
|
/**
|
|
6
12
|
* MCP Server Registry
|
|
7
13
|
*
|
|
@@ -11,10 +17,12 @@ import { resolveOmpPaths } from '../providers/omp-paths.mjs';
|
|
|
11
17
|
*
|
|
12
18
|
* @implements #554
|
|
13
19
|
*/
|
|
14
|
-
import { readFile
|
|
15
|
-
import {
|
|
20
|
+
import { readFile } from 'fs/promises';
|
|
21
|
+
import { qualificationDigest } from '../models/qualification-digest.mjs';
|
|
22
|
+
import { qualifyWorkerInvocationProfile, requiredWorkerControls } from '../models/provider-policy.js';
|
|
23
|
+
import { dirname, isAbsolute, resolve } from 'path';
|
|
24
|
+
import { homedir } from 'os';
|
|
16
25
|
import { resolveConfigDir } from '../config/user-config.js';
|
|
17
|
-
import { getProviderDefinition } from '../providers/provider-definitions.js';
|
|
18
26
|
// ============================================
|
|
19
27
|
// Registry
|
|
20
28
|
// ============================================
|
|
@@ -33,12 +41,76 @@ function validateCredentialReferences(def) {
|
|
|
33
41
|
throw new Error(`Invalid MCP header environment variable reference "${envName}"`);
|
|
34
42
|
}
|
|
35
43
|
}
|
|
44
|
+
for (const [key, envName] of Object.entries(def.envFrom ?? {})) {
|
|
45
|
+
if (!ENV_REFERENCE_NAME.test(key))
|
|
46
|
+
throw new Error(`Invalid MCP env-from variable name "${key}"`);
|
|
47
|
+
if (!ENV_REFERENCE_NAME.test(envName)) {
|
|
48
|
+
throw new Error(`Invalid MCP env-from environment variable reference "${envName}"`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function workerServerDigest(server) {
|
|
53
|
+
const { workerQualification, description, injectedProviders, addedAt, updatedAt, ...execution } = server;
|
|
54
|
+
return qualificationDigest(execution);
|
|
55
|
+
}
|
|
56
|
+
function workerQualificationBinding(server, input) {
|
|
57
|
+
if (!Array.isArray(input.requiredControls) || input.requiredControls.some(name => typeof name !== 'string' || !name || !Object.hasOwn(input.adapter.invocationProfiles?.[input.profile]?.controls ?? {}, name))) {
|
|
58
|
+
throw new Error('MCP worker must declare valid required controls');
|
|
59
|
+
}
|
|
60
|
+
if (server.enabled === false || input.mcp.serverRef !== server.name) {
|
|
61
|
+
throw new Error('MCP worker server is disabled or does not match the qualified profile');
|
|
62
|
+
}
|
|
63
|
+
if (input.authorizedServerDigest !== workerServerDigest(server)) {
|
|
64
|
+
throw new Error('MCP server command, endpoint or configuration lacks matching host authorization');
|
|
65
|
+
}
|
|
66
|
+
if (server.type === 'stdio') {
|
|
67
|
+
if (!server.command || !isAbsolute(server.command) || server.command.includes('\0')
|
|
68
|
+
|| (server.args ?? []).some(arg => typeof arg !== 'string' || arg.includes('\0'))) {
|
|
69
|
+
throw new Error('MCP worker requires an authorized absolute local command and typed argv');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
let endpoint;
|
|
74
|
+
try {
|
|
75
|
+
endpoint = new URL(server.url ?? '');
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new Error('MCP worker endpoint is invalid');
|
|
79
|
+
}
|
|
80
|
+
if (!['http:', 'https:'].includes(endpoint.protocol) || endpoint.username || endpoint.password || endpoint.hash) {
|
|
81
|
+
throw new Error('MCP worker endpoint must be an authorized HTTP URL without credentials or fragment');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const profile = qualifyWorkerInvocationProfile(input.adapter, { ...input, transport: 'mcp' });
|
|
85
|
+
const installed = input.installationQualification;
|
|
86
|
+
if (installed?.serverDigest !== input.authorizedServerDigest) {
|
|
87
|
+
throw new Error('MCP worker installation does not cover the authorized registration');
|
|
88
|
+
}
|
|
89
|
+
const evidence = profile.installationQualification;
|
|
90
|
+
if (!installed || installed.status !== 'ENABLED' || installed.platform !== 'linux' || installed.cliVersion !== input.cliVersion
|
|
91
|
+
|| !evidence || ['scopeDigest', 'fixtureDigest', 'verifiedAt', 'evidenceRef'].some(key => installed[key] !== evidence[key])) {
|
|
92
|
+
throw new Error('MCP worker requires current trusted installation qualification');
|
|
93
|
+
}
|
|
94
|
+
if (Object.keys(server.env ?? {}).some(key => !profile.envAllowlist.includes(key))
|
|
95
|
+
|| Object.values(server.headerEnv ?? {}).some(key => !profile.envAllowlist.includes(key))) {
|
|
96
|
+
throw new Error('MCP worker server environment exceeds the qualified profile allowlist');
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
serverDigest: workerServerDigest(server), adapterDigest: qualificationDigest(input.adapter),
|
|
100
|
+
profile: input.profile, cliVersion: input.cliVersion,
|
|
101
|
+
scopeDigest: installed.scopeDigest, fixtureDigest: installed.fixtureDigest,
|
|
102
|
+
requiredControls: requiredWorkerControls(input).sort(),
|
|
103
|
+
};
|
|
36
104
|
}
|
|
37
105
|
export class McpServerRegistry {
|
|
38
106
|
configDir;
|
|
39
107
|
cache = null;
|
|
108
|
+
/** Configuration layers, lowest precedence first; null for a single directory */
|
|
109
|
+
layers;
|
|
110
|
+
layering = null;
|
|
40
111
|
constructor(configDirOverride) {
|
|
41
|
-
this.
|
|
112
|
+
this.layers = resolveConfigLayers(configDirOverride);
|
|
113
|
+
this.configDir = this.layers ? this.layers[this.layers.length - 1] : resolveConfigDir(configDirOverride);
|
|
42
114
|
}
|
|
43
115
|
/** Get the registry file path */
|
|
44
116
|
getPath() {
|
|
@@ -48,6 +120,12 @@ export class McpServerRegistry {
|
|
|
48
120
|
async load() {
|
|
49
121
|
if (this.cache)
|
|
50
122
|
return this.cache;
|
|
123
|
+
if (this.layers) {
|
|
124
|
+
const layered = await loadLayered(this.layers, REGISTRY_FILENAME, 'servers', DEFAULT_REGISTRY);
|
|
125
|
+
this.cache = layered.data;
|
|
126
|
+
this.layering = layered.layering;
|
|
127
|
+
return this.cache;
|
|
128
|
+
}
|
|
51
129
|
const filePath = this.getPath();
|
|
52
130
|
try {
|
|
53
131
|
const content = await readFile(filePath, 'utf-8');
|
|
@@ -61,43 +139,67 @@ export class McpServerRegistry {
|
|
|
61
139
|
catch {
|
|
62
140
|
this.cache = { ...DEFAULT_REGISTRY, servers: {} };
|
|
63
141
|
}
|
|
142
|
+
try {
|
|
143
|
+
resolveCredentialPolicy({ registryPolicy: this.cache.credentialPolicy, env: {} });
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
this.cache = null;
|
|
147
|
+
throw new Error(`Invalid MCP credential policy in ${filePath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
148
|
+
}
|
|
64
149
|
return this.cache;
|
|
65
150
|
}
|
|
66
151
|
/** Save the registry to disk */
|
|
67
|
-
async save() {
|
|
68
|
-
if (!
|
|
152
|
+
async save(data = this.cache, explicitPolicy = false) {
|
|
153
|
+
if (!data)
|
|
69
154
|
return;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
155
|
+
// A fresh instance has no ownership record yet; load it first so inherited
|
|
156
|
+
// entries and inherited policy are never copied into the write layer.
|
|
157
|
+
let layering = this.layering;
|
|
158
|
+
if (this.layers && !layering) {
|
|
159
|
+
await this.load();
|
|
160
|
+
layering = this.layering;
|
|
161
|
+
}
|
|
162
|
+
await saveLayerData(this.getPath(), data, 'servers', this.layers, layering, explicitPolicy);
|
|
163
|
+
this.cache = data;
|
|
164
|
+
if (this.layers) {
|
|
165
|
+
this.clearCache();
|
|
166
|
+
await this.load();
|
|
167
|
+
}
|
|
73
168
|
}
|
|
74
169
|
/** Add a new MCP server definition */
|
|
75
170
|
async add(def) {
|
|
76
171
|
validateCredentialReferences(def);
|
|
77
|
-
const data = await this.load();
|
|
172
|
+
const data = structuredClone(await this.load());
|
|
78
173
|
if (data.servers[def.name]) {
|
|
79
174
|
throw new Error(`Server "${def.name}" already exists. Use "update" to modify it.`);
|
|
80
175
|
}
|
|
81
176
|
data.servers[def.name] = {
|
|
82
177
|
...def,
|
|
178
|
+
workerQualification: undefined,
|
|
83
179
|
injectedProviders: [],
|
|
84
180
|
addedAt: new Date().toISOString(),
|
|
85
181
|
updatedAt: new Date().toISOString(),
|
|
86
182
|
};
|
|
87
|
-
await this.save();
|
|
183
|
+
await this.save(data);
|
|
88
184
|
}
|
|
89
185
|
/** Remove an MCP server definition */
|
|
90
186
|
async remove(name) {
|
|
91
|
-
const data = await this.load();
|
|
187
|
+
const data = structuredClone(await this.load());
|
|
92
188
|
if (!data.servers[name]) {
|
|
93
189
|
throw new Error(`Server "${name}" not found.`);
|
|
94
190
|
}
|
|
191
|
+
if (this.layering && isLowerLayerEntry(this.layering, name)) {
|
|
192
|
+
throw new Error(`Server "${name}" is defined in a lower configuration layer; remove it there.`);
|
|
193
|
+
}
|
|
194
|
+
if (this.layering && lowerEntryQualified(this.layering, name)) {
|
|
195
|
+
throw new Error(`Server "${name}" overrides a qualified lower-layer entry; removing the override would silently re-expose its qualification. Remove the lower-layer entry in its own layer instead.`);
|
|
196
|
+
}
|
|
95
197
|
delete data.servers[name];
|
|
96
|
-
await this.save();
|
|
198
|
+
await this.save(data);
|
|
97
199
|
}
|
|
98
200
|
/** Update an existing MCP server definition */
|
|
99
201
|
async update(name, updates) {
|
|
100
|
-
const data = await this.load();
|
|
202
|
+
const data = structuredClone(await this.load());
|
|
101
203
|
if (!data.servers[name]) {
|
|
102
204
|
throw new Error(`Server "${name}" not found.`);
|
|
103
205
|
}
|
|
@@ -108,8 +210,35 @@ export class McpServerRegistry {
|
|
|
108
210
|
updatedAt: new Date().toISOString(),
|
|
109
211
|
};
|
|
110
212
|
validateCredentialReferences(next);
|
|
213
|
+
// Ordinary registration edits cannot mint qualification, including a copied binding.
|
|
214
|
+
next.workerQualification = workerServerDigest(next) === workerServerDigest(data.servers[name])
|
|
215
|
+
? data.servers[name].workerQualification : undefined;
|
|
111
216
|
data.servers[name] = next;
|
|
217
|
+
await this.save(data);
|
|
218
|
+
}
|
|
219
|
+
/** Bind an already qualified host installation to this exact MCP registration. */
|
|
220
|
+
async recordWorkerQualification(name, input) {
|
|
221
|
+
this.clearCache();
|
|
222
|
+
const server = await this.get(name);
|
|
223
|
+
if (!server)
|
|
224
|
+
throw new Error(`Server "${name}" not found.`);
|
|
225
|
+
const binding = workerQualificationBinding(server, input);
|
|
226
|
+
server.workerQualification = binding;
|
|
112
227
|
await this.save();
|
|
228
|
+
return structuredClone(binding);
|
|
229
|
+
}
|
|
230
|
+
/** Recheck immediately before use; direct shell invocations do not use this registry. */
|
|
231
|
+
async assertWorkerQualified(name, input) {
|
|
232
|
+
// Other trusted registry writers may have changed the registration since load().
|
|
233
|
+
this.clearCache();
|
|
234
|
+
const server = await this.get(name);
|
|
235
|
+
if (!server)
|
|
236
|
+
throw new Error(`Server "${name}" not found.`);
|
|
237
|
+
const current = workerQualificationBinding(server, input);
|
|
238
|
+
if (!server.workerQualification || qualificationDigest(server.workerQualification) !== qualificationDigest(current)) {
|
|
239
|
+
throw new Error('MCP worker registration qualification is missing or changed');
|
|
240
|
+
}
|
|
241
|
+
return structuredClone(server);
|
|
113
242
|
}
|
|
114
243
|
/** Get a specific server definition */
|
|
115
244
|
async get(name) {
|
|
@@ -123,7 +252,7 @@ export class McpServerRegistry {
|
|
|
123
252
|
}
|
|
124
253
|
/** Record that a server was injected into a provider */
|
|
125
254
|
async recordInjection(name, provider) {
|
|
126
|
-
const data = await this.load();
|
|
255
|
+
const data = structuredClone(await this.load());
|
|
127
256
|
const server = data.servers[name];
|
|
128
257
|
if (!server)
|
|
129
258
|
return;
|
|
@@ -133,7 +262,7 @@ export class McpServerRegistry {
|
|
|
133
262
|
if (!server.injectedProviders.includes(provider)) {
|
|
134
263
|
server.injectedProviders.push(provider);
|
|
135
264
|
}
|
|
136
|
-
await this.save();
|
|
265
|
+
await this.save(data);
|
|
137
266
|
}
|
|
138
267
|
/** Get all providers that have had servers injected */
|
|
139
268
|
async getInjectedProviders() {
|
|
@@ -146,6 +275,33 @@ export class McpServerRegistry {
|
|
|
146
275
|
}
|
|
147
276
|
return [...providers];
|
|
148
277
|
}
|
|
278
|
+
/** Registry-wide default credential policy, if one is set */
|
|
279
|
+
async getCredentialPolicy() {
|
|
280
|
+
const data = await this.load();
|
|
281
|
+
return data.credentialPolicy;
|
|
282
|
+
}
|
|
283
|
+
/** The enforced organisation floor for this registry, if any layer below the write layer sets one. */
|
|
284
|
+
async getCredentialPolicyFloor() {
|
|
285
|
+
await this.load();
|
|
286
|
+
return this.layering?.lowerPolicy;
|
|
287
|
+
}
|
|
288
|
+
/** The config file of the layer that set the enforced floor, for diagnostics. */
|
|
289
|
+
async getCredentialPolicyFloorSource() {
|
|
290
|
+
await this.load();
|
|
291
|
+
return this.layering?.lowerPolicySource;
|
|
292
|
+
}
|
|
293
|
+
async setCredentialPolicy(policy) {
|
|
294
|
+
const data = structuredClone(await this.load());
|
|
295
|
+
const floorPolicy = this.layering?.lowerPolicy;
|
|
296
|
+
const floorSource = this.layering?.lowerPolicySource;
|
|
297
|
+
const effective = resolveCredentialPolicy({ flag: policy, floorPolicy, floorSource, env: {} });
|
|
298
|
+
if (effective !== policy) {
|
|
299
|
+
const location = floorSource ? ` (set in ${floorSource})` : '';
|
|
300
|
+
throw new Error(`Cannot relax MCP credential policy floor "${effective}"${location} to "${policy}".`);
|
|
301
|
+
}
|
|
302
|
+
data.credentialPolicy = policy;
|
|
303
|
+
await this.save(data, true);
|
|
304
|
+
}
|
|
149
305
|
/** Clear the in-memory cache */
|
|
150
306
|
clearCache() {
|
|
151
307
|
this.cache = null;
|
|
@@ -157,110 +313,16 @@ export class McpServerRegistry {
|
|
|
157
313
|
/**
|
|
158
314
|
* Build the MCP config block for a single server in a given provider's format.
|
|
159
315
|
*/
|
|
160
|
-
function buildServerConfig(server, provider) {
|
|
161
|
-
|
|
162
|
-
switch (adapter) {
|
|
163
|
-
case 'antigravity': {
|
|
164
|
-
if (server.type === 'stdio') {
|
|
165
|
-
return { command: server.command, args: server.args || [], ...(server.env ? { env: server.env } : {}) };
|
|
166
|
-
}
|
|
167
|
-
return { serverUrl: server.url, ...(server.headers ? { headers: server.headers } : {}) };
|
|
168
|
-
}
|
|
169
|
-
case 'claude-code': {
|
|
170
|
-
if (server.type === 'stdio') {
|
|
171
|
-
return {
|
|
172
|
-
command: server.command,
|
|
173
|
-
args: server.args || [],
|
|
174
|
-
...(server.env ? { env: server.env } : {}),
|
|
175
|
-
};
|
|
176
|
-
}
|
|
177
|
-
// http/sse
|
|
178
|
-
return {
|
|
179
|
-
url: server.url,
|
|
180
|
-
...(server.headers ? { headers: server.headers } : {}),
|
|
181
|
-
};
|
|
182
|
-
}
|
|
183
|
-
case 'cursor': {
|
|
184
|
-
if (server.type === 'stdio') {
|
|
185
|
-
return {
|
|
186
|
-
command: server.command,
|
|
187
|
-
args: server.args || [],
|
|
188
|
-
...(server.env ? { env: server.env } : {}),
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
return {
|
|
192
|
-
url: server.url,
|
|
193
|
-
...(server.headers ? { headers: server.headers } : {}),
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
case 'factory': {
|
|
197
|
-
if (server.type === 'stdio') {
|
|
198
|
-
return {
|
|
199
|
-
type: 'stdio',
|
|
200
|
-
command: server.command,
|
|
201
|
-
args: server.args || [],
|
|
202
|
-
disabled: false,
|
|
203
|
-
...(server.env ? { env: server.env } : {}),
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
type: server.type,
|
|
208
|
-
url: server.url,
|
|
209
|
-
disabled: false,
|
|
210
|
-
...(server.headers ? { headers: server.headers } : {}),
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
case 'opencode': {
|
|
214
|
-
if (server.type === 'stdio') {
|
|
215
|
-
return {
|
|
216
|
-
type: 'local',
|
|
217
|
-
command: [server.command, ...(server.args || [])],
|
|
218
|
-
...(server.env ? { env: server.env } : {}),
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
return {
|
|
222
|
-
type: 'remote',
|
|
223
|
-
url: server.url,
|
|
224
|
-
...(server.headers ? { headers: server.headers } : {}),
|
|
225
|
-
};
|
|
226
|
-
}
|
|
227
|
-
case 'windsurf':
|
|
228
|
-
case 'warp': {
|
|
229
|
-
if (server.type === 'stdio') {
|
|
230
|
-
return {
|
|
231
|
-
command: server.command,
|
|
232
|
-
args: server.args || [],
|
|
233
|
-
...(server.env ? { env: server.env } : {}),
|
|
234
|
-
};
|
|
235
|
-
}
|
|
236
|
-
return {
|
|
237
|
-
url: server.url,
|
|
238
|
-
...(server.headers ? { headers: server.headers } : {}),
|
|
239
|
-
};
|
|
240
|
-
}
|
|
241
|
-
case 'codex':
|
|
242
|
-
// TOML format handled separately
|
|
243
|
-
return {};
|
|
244
|
-
default:
|
|
245
|
-
return {};
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
/**
|
|
249
|
-
* Build a TOML section for a server (Codex/OpenAI provider).
|
|
250
|
-
*/
|
|
251
|
-
function tomlString(value) {
|
|
252
|
-
if (typeof value !== 'string' || [...value].some(char => {
|
|
253
|
-
const point = char.codePointAt(0);
|
|
254
|
-
return point >= 0xd800 && point <= 0xdfff;
|
|
255
|
-
}))
|
|
256
|
-
throw new Error('TOML values must be strings containing valid Unicode scalar values');
|
|
257
|
-
// JSON escapes align with TOML basic strings except DEL must also be escaped.
|
|
258
|
-
return JSON.stringify(value).replace(/\u007f/g, '\\u007f');
|
|
316
|
+
export function buildServerConfig(server, provider) {
|
|
317
|
+
return renderServerConfig(server, provider);
|
|
259
318
|
}
|
|
260
319
|
function tomlKey(value) {
|
|
261
320
|
return typeof value === 'string' && /^[A-Za-z0-9_-]+$/.test(value) ? value : tomlString(value);
|
|
262
321
|
}
|
|
263
|
-
function
|
|
322
|
+
function tomlInlineTable(values) {
|
|
323
|
+
return `{ ${Object.entries(values).map(([name, value]) => `${tomlKey(name)} = ${tomlString(value)}`).join(', ')} }`;
|
|
324
|
+
}
|
|
325
|
+
export function buildServerToml(server) {
|
|
264
326
|
const lines = [];
|
|
265
327
|
lines.push(`[mcp_servers.${tomlKey(server.name)}]`);
|
|
266
328
|
if (server.type === 'stdio') {
|
|
@@ -269,9 +331,27 @@ function buildServerToml(server) {
|
|
|
269
331
|
const argsStr = server.args.map(a => tomlString(a)).join(', ');
|
|
270
332
|
lines.push(`args = [${argsStr}]`);
|
|
271
333
|
}
|
|
334
|
+
if (server.env && Object.keys(server.env).length > 0)
|
|
335
|
+
lines.push(`env = ${tomlInlineTable(server.env)}`);
|
|
336
|
+
// Codex forwards a variable only under its own name (env_vars).
|
|
337
|
+
const forwarded = Object.entries(server.envFrom ?? {});
|
|
338
|
+
for (const [key, name] of forwarded) {
|
|
339
|
+
validateEnvReferenceName(name);
|
|
340
|
+
if (key !== name) {
|
|
341
|
+
throw new Error(`MCP server "${server.name}": Codex forwards environment variables under their own name only; env-from ${key}=${name} cannot be rendered. Use ${name}=${name}.`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
if (forwarded.length > 0)
|
|
345
|
+
lines.push(`env_vars = [${forwarded.map(([name]) => tomlString(name)).join(', ')}]`);
|
|
272
346
|
}
|
|
273
347
|
else {
|
|
274
348
|
lines.push(`url = ${tomlString(server.url)}`);
|
|
349
|
+
if (server.headers && Object.keys(server.headers).length > 0)
|
|
350
|
+
lines.push(`http_headers = ${tomlInlineTable(server.headers)}`);
|
|
351
|
+
for (const name of Object.values(server.headerEnv ?? {}))
|
|
352
|
+
validateEnvReferenceName(name);
|
|
353
|
+
if (server.headerEnv && Object.keys(server.headerEnv).length > 0)
|
|
354
|
+
lines.push(`env_http_headers = ${tomlInlineTable(server.headerEnv)}`);
|
|
275
355
|
}
|
|
276
356
|
lines.push(`startup_timeout_sec = 10.0`);
|
|
277
357
|
lines.push(`tool_timeout_sec = 60.0`);
|
|
@@ -285,6 +365,9 @@ export function getProviderConfigPath(provider, projectDir = '.', options = {})
|
|
|
285
365
|
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
286
366
|
return resolve(homeDir, '.gemini/config/mcp_config.json');
|
|
287
367
|
}
|
|
368
|
+
if ((provider === 'claude-code' || provider === 'claude') && options.scope === 'user') {
|
|
369
|
+
return resolve(process.env.HOME || process.env.USERPROFILE || homedir(), '.claude.json');
|
|
370
|
+
}
|
|
288
371
|
if ((provider === 'omp' || provider === 'oh-my-pi') && options.scope !== undefined && !['user', 'project'].includes(options.scope))
|
|
289
372
|
throw new Error('OMP MCP scope must be user or project');
|
|
290
373
|
if ((provider === 'omp' || provider === 'oh-my-pi') && options.scope === 'user')
|
|
@@ -295,12 +378,12 @@ export function getProviderConfigPath(provider, projectDir = '.', options = {})
|
|
|
295
378
|
agy: resolve(projectDir, '.agents/mcp_config.json'),
|
|
296
379
|
omp: resolve(projectDir, '.omp/mcp.json'),
|
|
297
380
|
'oh-my-pi': resolve(projectDir, '.omp/mcp.json'),
|
|
298
|
-
'claude-code': resolve(projectDir, '.
|
|
299
|
-
claude: resolve(projectDir, '.
|
|
381
|
+
'claude-code': resolve(projectDir, '.mcp.json'),
|
|
382
|
+
claude: resolve(projectDir, '.mcp.json'),
|
|
300
383
|
cursor: resolve(projectDir, '.cursor/mcp.json'),
|
|
301
384
|
factory: resolve(homeDir, '.factory/mcp.json'),
|
|
302
|
-
codex: resolve(homeDir, '.codex/config.toml'),
|
|
303
|
-
openai: resolve(homeDir, '.codex/config.toml'),
|
|
385
|
+
codex: process.env.CODEX_HOME ? resolve(process.env.CODEX_HOME, 'config.toml') : resolve(homeDir, '.codex/config.toml'),
|
|
386
|
+
openai: process.env.CODEX_HOME ? resolve(process.env.CODEX_HOME, 'config.toml') : resolve(homeDir, '.codex/config.toml'),
|
|
304
387
|
'grok-build': options.scope === 'user'
|
|
305
388
|
? resolve(process.env.GROK_HOME || resolve(homeDir, '.grok'), 'config.toml')
|
|
306
389
|
: resolve(projectDir, '.grok/config.toml'),
|
|
@@ -327,16 +410,37 @@ export async function injectServers(registry, provider, options = {}) {
|
|
|
327
410
|
};
|
|
328
411
|
// Get servers to inject
|
|
329
412
|
let allServers = await registry.list();
|
|
330
|
-
if (serverFilter
|
|
413
|
+
if (serverFilter !== undefined) {
|
|
331
414
|
allServers = allServers.filter(s => serverFilter.includes(s.name));
|
|
332
415
|
}
|
|
416
|
+
const toolPlan = options.toolFilters
|
|
417
|
+
? planToolFilters(provider, allServers.map(server => server.name), options.toolFilters)
|
|
418
|
+
: null;
|
|
419
|
+
if (toolPlan)
|
|
420
|
+
result.warnings = toolPlan.warnings;
|
|
333
421
|
if (allServers.length === 0) {
|
|
334
422
|
result.error = 'No servers to inject. Use "aiwg mcp add" first.';
|
|
335
423
|
return result;
|
|
336
424
|
}
|
|
425
|
+
assertCredentialPolicy(allServers, resolveCredentialPolicy({
|
|
426
|
+
flag: options.credentialPolicy, registryPolicy: await registry.getCredentialPolicy(),
|
|
427
|
+
floorPolicy: await registry.getCredentialPolicyFloor(),
|
|
428
|
+
floorSource: await registry.getCredentialPolicyFloorSource(),
|
|
429
|
+
}));
|
|
430
|
+
// The shareable-project decision follows the actual resolved destination,
|
|
431
|
+
// never the requested scope: a `--scope user` request for a provider without
|
|
432
|
+
// a user-scope destination still resolves to the project file and is refused.
|
|
433
|
+
const { userScope, projectRoot } = classifyMcpDestination(provider, options.scope, configPath, projectDir);
|
|
434
|
+
await assertConfigDestination(configPath, projectRoot);
|
|
435
|
+
// Every destination inside the project directory is meant to be committed to
|
|
436
|
+
// version control; home destinations are private, so literals there are not
|
|
437
|
+
// copied into a shared file.
|
|
438
|
+
if (projectRoot) {
|
|
439
|
+
assertProjectCredentials(allServers, configPath, projectCredentialRemedy(provider, projectDir));
|
|
440
|
+
}
|
|
337
441
|
if (provider === 'omp' || provider === 'oh-my-pi') {
|
|
338
442
|
try {
|
|
339
|
-
const managed = await manageOmpMcp(configPath, allServers, { dryRun });
|
|
443
|
+
const managed = await manageOmpMcp(configPath, allServers, { dryRun, userScope, projectRoot });
|
|
340
444
|
if (!dryRun)
|
|
341
445
|
for (const server of allServers)
|
|
342
446
|
await registry.recordInjection(server.name, 'omp');
|
|
@@ -350,6 +454,7 @@ export async function injectServers(registry, provider, options = {}) {
|
|
|
350
454
|
try {
|
|
351
455
|
const managed = await manageGrokBuildMcp(configPath, allServers, {
|
|
352
456
|
dryRun,
|
|
457
|
+
userScope,
|
|
353
458
|
root: options.scope === 'user' ? dirname(dirname(configPath)) : resolve(projectDir),
|
|
354
459
|
});
|
|
355
460
|
if (!dryRun && !managed.error)
|
|
@@ -363,12 +468,12 @@ export async function injectServers(registry, provider, options = {}) {
|
|
|
363
468
|
}
|
|
364
469
|
// Handle TOML-based providers (Codex/OpenAI) separately
|
|
365
470
|
if (provider === 'codex' || provider === 'openai') {
|
|
366
|
-
return injectToml(registry, allServers, configPath, provider, dryRun, result);
|
|
471
|
+
return injectToml(registry, allServers, configPath, provider, dryRun, result, userScope, projectRoot, toolPlan);
|
|
367
472
|
}
|
|
368
473
|
// JSON-based providers
|
|
369
|
-
return injectJson(registry, allServers, configPath, provider, dryRun, result);
|
|
474
|
+
return injectJson(registry, allServers, configPath, provider, dryRun, result, userScope, projectRoot, toolPlan, { projectDir, scope: options.scope });
|
|
370
475
|
}
|
|
371
|
-
async function injectJson(registry, servers, configPath, provider, dryRun, result) {
|
|
476
|
+
async function injectJson(registry, servers, configPath, provider, dryRun, result, userScope, projectRoot, toolPlan = null, location = {}) {
|
|
372
477
|
// Load existing config
|
|
373
478
|
let existing = {};
|
|
374
479
|
try {
|
|
@@ -406,9 +511,21 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
406
511
|
}
|
|
407
512
|
// Merge back
|
|
408
513
|
const merged = { ...existing, [mcpKey]: newServers };
|
|
514
|
+
if (toolPlan) {
|
|
515
|
+
applyJsonToolFilterPlan(merged, mcpKey, toolPlan);
|
|
516
|
+
}
|
|
517
|
+
const isClaude = provider === 'claude-code' || provider === 'claude';
|
|
518
|
+
const settingsPath = isClaude ? claudeSettingsPath(location.projectDir, location.scope) : null;
|
|
519
|
+
const settings = settingsPath ? await prepareClaudePermissions(settingsPath, toolPlan?.claudePermissions || { deny: [], allow: [] }, { userScope, projectRoot, managedDir: dirname(registry.getPath()), mcpPath: configPath }) : null;
|
|
520
|
+
if (settings?.active && settingsPath)
|
|
521
|
+
result.settingsPath = settingsPath;
|
|
522
|
+
if (settings?.warnings.length)
|
|
523
|
+
result.warnings = [...(result.warnings || []), ...settings.warnings];
|
|
409
524
|
if (!dryRun) {
|
|
410
|
-
await
|
|
411
|
-
|
|
525
|
+
await writeConfigTransaction([
|
|
526
|
+
{ file: configPath, content: JSON.stringify(merged, null, 2) + '\n', options: { userScope, projectRoot } },
|
|
527
|
+
...(settings?.writes || []),
|
|
528
|
+
]);
|
|
412
529
|
// Record injection in registry
|
|
413
530
|
for (const server of servers) {
|
|
414
531
|
if ((provider === 'antigravity' || provider === 'agy') && !result.serversInjected.includes(server.name))
|
|
@@ -418,7 +535,7 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
418
535
|
}
|
|
419
536
|
return result;
|
|
420
537
|
}
|
|
421
|
-
async function injectToml(registry, servers, configPath, provider, dryRun, result) {
|
|
538
|
+
async function injectToml(registry, servers, configPath, provider, dryRun, result, userScope, projectRoot, toolPlan = null) {
|
|
422
539
|
let existing = '';
|
|
423
540
|
try {
|
|
424
541
|
existing = await readFile(configPath, 'utf-8');
|
|
@@ -428,15 +545,15 @@ async function injectToml(registry, servers, configPath, provider, dryRun, resul
|
|
|
428
545
|
throw error;
|
|
429
546
|
}
|
|
430
547
|
for (const server of servers) {
|
|
431
|
-
const
|
|
548
|
+
const filterLines = toolPlan?.tomlLines[server.name] || [];
|
|
549
|
+
const edited = replaceServer(existing, server.name, [buildServerToml(server), ...filterLines].join('\n'));
|
|
432
550
|
existing = edited.text;
|
|
433
551
|
if (edited.alreadyPresent)
|
|
434
552
|
result.alreadyPresent.push(server.name);
|
|
435
553
|
result.serversInjected.push(server.name);
|
|
436
554
|
}
|
|
437
555
|
if (!dryRun) {
|
|
438
|
-
await
|
|
439
|
-
await writeFile(configPath, existing, 'utf-8');
|
|
556
|
+
await writeConfigAtomic(configPath, existing, { userScope, projectRoot });
|
|
440
557
|
for (const server of servers) {
|
|
441
558
|
await registry.recordInjection(server.name, provider);
|
|
442
559
|
}
|