@ashlr/hub 3.4.0 → 3.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +107 -1
- package/README.md +3 -0
- package/dist/build-identity.json +2 -2
- package/dist/cli/index.js +11 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/local-runtime.js +40 -9
- package/dist/cli/local-runtime.js.map +1 -1
- package/dist/core/fleet/external-skill-audit.js +1 -1
- package/dist/core/fleet/external-skill-audit.js.map +1 -1
- package/dist/core/local-eval/classify.d.ts +57 -0
- package/dist/core/local-eval/classify.js +121 -0
- package/dist/core/local-eval/classify.js.map +1 -0
- package/dist/core/local-eval/configuration.d.ts +37 -0
- package/dist/core/local-eval/configuration.js +171 -0
- package/dist/core/local-eval/configuration.js.map +1 -0
- package/dist/core/local-eval/index.d.ts +15 -0
- package/dist/core/local-eval/index.js +16 -0
- package/dist/core/local-eval/index.js.map +1 -0
- package/dist/core/local-eval/main.d.ts +31 -0
- package/dist/core/local-eval/main.js +174 -0
- package/dist/core/local-eval/main.js.map +1 -0
- package/dist/core/local-eval/report.d.ts +25 -0
- package/dist/core/local-eval/report.js +157 -0
- package/dist/core/local-eval/report.js.map +1 -0
- package/dist/core/local-eval/runner.d.ts +55 -0
- package/dist/core/local-eval/runner.js +290 -0
- package/dist/core/local-eval/runner.js.map +1 -0
- package/dist/core/local-eval/tasks.d.ts +22 -0
- package/dist/core/local-eval/tasks.js +303 -0
- package/dist/core/local-eval/tasks.js.map +1 -0
- package/dist/core/local-eval/trace.d.ts +67 -0
- package/dist/core/local-eval/trace.js +309 -0
- package/dist/core/local-eval/trace.js.map +1 -0
- package/dist/core/local-eval/types.d.ts +262 -0
- package/dist/core/local-eval/types.js +23 -0
- package/dist/core/local-eval/types.js.map +1 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-host.d.ts +68 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-host.js +120 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-host.js.map +1 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-process.d.ts +15 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-process.js +21 -0
- package/dist/core/local-runtime/llama/anthropic-proxy-process.js.map +1 -0
- package/dist/core/local-runtime/llama/anthropic-proxy.d.ts +2 -1
- package/dist/core/local-runtime/llama/anthropic-proxy.js +14 -6
- package/dist/core/local-runtime/llama/anthropic-proxy.js.map +1 -1
- package/dist/core/local-runtime/llama/anthropic-shim.d.ts +33 -0
- package/dist/core/local-runtime/llama/anthropic-shim.js +59 -0
- package/dist/core/local-runtime/llama/anthropic-shim.js.map +1 -1
- package/dist/core/local-runtime/llama/config.d.ts +123 -6
- package/dist/core/local-runtime/llama/config.js +196 -6
- package/dist/core/local-runtime/llama/config.js.map +1 -1
- package/dist/core/local-runtime/llama/index.d.ts +15 -0
- package/dist/core/local-runtime/llama/index.js +13 -0
- package/dist/core/local-runtime/llama/index.js.map +1 -1
- package/dist/core/local-runtime/llama/paths.d.ts +17 -0
- package/dist/core/local-runtime/llama/paths.js +25 -0
- package/dist/core/local-runtime/llama/paths.js.map +1 -1
- package/dist/core/local-runtime/llama/proxy-invocation.d.ts +101 -0
- package/dist/core/local-runtime/llama/proxy-invocation.js +134 -0
- package/dist/core/local-runtime/llama/proxy-invocation.js.map +1 -0
- package/dist/core/local-runtime/llama/proxy-launchd.d.ts +83 -0
- package/dist/core/local-runtime/llama/proxy-launchd.js +216 -0
- package/dist/core/local-runtime/llama/proxy-launchd.js.map +1 -0
- package/dist/core/local-runtime/llama/shapes.d.ts +2 -1
- package/dist/core/local-runtime/llama/shapes.js +2 -1
- package/dist/core/local-runtime/llama/shapes.js.map +1 -1
- package/dist/core/verse/adapters/claude.js +16 -0
- package/dist/core/verse/adapters/claude.js.map +1 -1
- package/dist/core/verse/adapters/codex.js +60 -2
- package/dist/core/verse/adapters/codex.js.map +1 -1
- package/dist/core/verse/adapters/grok.js +13 -0
- package/dist/core/verse/adapters/grok.js.map +1 -1
- package/dist/core/verse/control-api.d.ts +8 -9
- package/dist/core/verse/control-api.js +14 -114
- package/dist/core/verse/control-api.js.map +1 -1
- package/dist/core/verse/github-api.d.ts +50 -0
- package/dist/core/verse/github-api.js +211 -0
- package/dist/core/verse/github-api.js.map +1 -0
- package/dist/core/verse/github-proposal.d.ts +64 -0
- package/dist/core/verse/github-proposal.js +186 -0
- package/dist/core/verse/github-proposal.js.map +1 -0
- package/dist/core/verse/github-repo.d.ts +104 -0
- package/dist/core/verse/github-repo.js +476 -0
- package/dist/core/verse/github-repo.js.map +1 -0
- package/dist/core/verse/github-types.d.ts +174 -0
- package/dist/core/verse/github-types.js +31 -0
- package/dist/core/verse/github-types.js.map +1 -0
- package/dist/core/verse/mcp-cli-health.d.ts +149 -0
- package/dist/core/verse/mcp-cli-health.js +227 -0
- package/dist/core/verse/mcp-cli-health.js.map +1 -0
- package/dist/core/verse/mcp-control-api.d.ts +68 -0
- package/dist/core/verse/mcp-control-api.js +322 -0
- package/dist/core/verse/mcp-control-api.js.map +1 -0
- package/dist/core/verse/mcp-mutation.d.ts +187 -0
- package/dist/core/verse/mcp-mutation.js +471 -0
- package/dist/core/verse/mcp-mutation.js.map +1 -0
- package/dist/core/verse/mcp-scope.d.ts +114 -0
- package/dist/core/verse/mcp-scope.js +149 -0
- package/dist/core/verse/mcp-scope.js.map +1 -0
- package/dist/core/verse/mcp-seat-view.d.ts +197 -0
- package/dist/core/verse/mcp-seat-view.js +322 -0
- package/dist/core/verse/mcp-seat-view.js.map +1 -0
- package/dist/core/verse/path-guard.d.ts +115 -0
- package/dist/core/verse/path-guard.js +171 -0
- package/dist/core/verse/path-guard.js.map +1 -0
- package/dist/core/verse/seats.js +30 -2
- package/dist/core/verse/seats.js.map +1 -1
- package/dist/core/verse/session-engine.js +60 -1
- package/dist/core/verse/session-engine.js.map +1 -1
- package/dist/core/verse/session-store.js +20 -0
- package/dist/core/verse/session-store.js.map +1 -1
- package/dist/core/verse/types.d.ts +225 -1
- package/dist/core/verse/types.js +26 -0
- package/dist/core/verse/types.js.map +1 -1
- package/dist/core/verse/verse-api.d.ts +16 -1
- package/dist/core/verse/verse-api.js +338 -16
- package/dist/core/verse/verse-api.js.map +1 -1
- package/dist/core/verse/workspaces.d.ts +130 -0
- package/dist/core/verse/workspaces.js +501 -0
- package/dist/core/verse/workspaces.js.map +1 -0
- package/dist/core/web/api.js +23 -0
- package/dist/core/web/api.js.map +1 -1
- package/dist/core/web/public/next/assets/App-BbVoUCIi.js +7 -0
- package/dist/core/web/public/next/assets/App-BbVoUCIi.js.map +1 -0
- package/dist/core/web/public/next/assets/App-Cgi6j1Gk.css +1 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-BW9iVjUa.js +2 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-BW9iVjUa.js.map +1 -0
- package/dist/core/web/public/next/assets/ApprovalsSection-Su-NUTis.css +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js +2 -0
- package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js.map +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-Cpk_oEhc.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js +80 -0
- package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js.map +1 -0
- package/dist/core/web/public/next/assets/ChatSection-LQiAn6Eu.css +1 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-CXevY3Au.js +2 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-CXevY3Au.js.map +1 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-cYuivhCX.css → ConfirmDialog-Dx15x0Ho.css} +1 -1
- package/dist/core/web/public/next/assets/Dialog-Bn0CgEGz.js +2 -0
- package/dist/core/web/public/next/assets/Dialog-Bn0CgEGz.js.map +1 -0
- package/dist/core/web/public/next/assets/Dialog-tQ8kFulD.css +1 -0
- package/dist/core/web/public/next/assets/DiffViewer-C8HHTnVE.css +1 -0
- package/dist/core/web/public/next/assets/DiffViewer-QKyisN2L.js +7 -0
- package/dist/core/web/public/next/assets/DiffViewer-QKyisN2L.js.map +1 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-jWLLCxWn.css → MutationTokenDialog-CrfJ0PdD.css} +1 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-DbSHPy3w.js +2 -0
- package/dist/core/web/public/next/assets/MutationTokenDialog-DbSHPy3w.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-C-PCgCzo.js +7 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-C-PCgCzo.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CM_8pJs6.css +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-Dw8ZjmkS.js +2 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-Dw8ZjmkS.js.map +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-ekyMXAK8.css +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-BII7TTSD.css +1 -0
- package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js +2 -0
- package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Bk5HipM0.js +2 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Bk5HipM0.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-Dh7A-hLD.css +1 -0
- package/dist/core/web/public/next/assets/UniverseView-Bqa8DH57.css +1 -0
- package/dist/core/web/public/next/assets/UniverseView-D8k9q0ce.js +9 -0
- package/dist/core/web/public/next/assets/UniverseView-D8k9q0ce.js.map +1 -0
- package/dist/core/web/public/next/assets/UsageSection-B2E06ZH1.js +2 -0
- package/dist/core/web/public/next/assets/UsageSection-B2E06ZH1.js.map +1 -0
- package/dist/core/web/public/next/assets/UsageSection-DwgNOYvi.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-D2E3mU9a.css +1 -0
- package/dist/core/web/public/next/assets/charts-CsrtT4rk.css +1 -0
- package/dist/core/web/public/next/assets/charts-DSUpczxG.js +2 -0
- package/dist/core/web/public/next/assets/charts-DSUpczxG.js.map +1 -0
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js +2 -0
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js.map +1 -0
- package/dist/core/web/public/next/assets/format-BNYWGJat.js +2 -0
- package/dist/core/web/public/next/assets/format-BNYWGJat.js.map +1 -0
- package/dist/core/web/public/next/assets/global-C4jfYHrj.js +2 -0
- package/dist/core/web/public/next/assets/global-C4jfYHrj.js.map +1 -0
- package/dist/core/web/public/next/assets/global-D463gG1X.css +1 -0
- package/dist/core/web/public/next/assets/icons-BxOX8-XB.js +2 -0
- package/dist/core/web/public/next/assets/icons-BxOX8-XB.js.map +1 -0
- package/dist/core/web/public/next/assets/index-BMRIET7F.js +11 -0
- package/dist/core/web/public/next/assets/index-BMRIET7F.js.map +1 -0
- package/dist/core/web/public/next/assets/queries-AxnVa02h.js +2 -0
- package/dist/core/web/public/next/assets/queries-AxnVa02h.js.map +1 -0
- package/dist/core/web/public/next/assets/use-guarded-action-BO6c94Wp.js +2 -0
- package/dist/core/web/public/next/assets/use-guarded-action-BO6c94Wp.js.map +1 -0
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js +2 -0
- package/dist/core/web/public/next/assets/verse-model-CvtK6vP6.js.map +1 -0
- package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js +2 -0
- package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js.map +1 -0
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/docs/README.md +4 -0
- package/node_modules/marked/README.md +8 -0
- package/node_modules/marked/bin/main.js +12 -11
- package/node_modules/marked/lib/marked.d.ts +88 -25
- package/node_modules/marked/lib/marked.esm.js +50 -44
- package/node_modules/marked/lib/marked.esm.js.map +3 -3
- package/node_modules/marked/lib/marked.umd.js +50 -44
- package/node_modules/marked/lib/marked.umd.js.map +3 -3
- package/node_modules/marked/man/marked.1 +1 -1
- package/node_modules/marked/package.json +21 -21
- package/package.json +13 -8
- package/dist/cli/activation.d.ts +0 -41
- package/dist/cli/activation.js +0 -485
- package/dist/cli/activation.js.map +0 -1
- package/dist/core/fleet/generated-repair-resolution.d.ts +0 -36
- package/dist/core/fleet/generated-repair-resolution.js +0 -245
- package/dist/core/fleet/generated-repair-resolution.js.map +0 -1
- package/dist/core/local-runtime/llama/port.d.ts +0 -17
- package/dist/core/local-runtime/llama/port.js +0 -47
- package/dist/core/local-runtime/llama/port.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-host.d.ts +0 -54
- package/dist/core/local-runtime/llama/proxy-host.js +0 -159
- package/dist/core/local-runtime/llama/proxy-host.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-process.d.ts +0 -148
- package/dist/core/local-runtime/llama/proxy-process.js +0 -250
- package/dist/core/local-runtime/llama/proxy-process.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-record.d.ts +0 -40
- package/dist/core/local-runtime/llama/proxy-record.js +0 -133
- package/dist/core/local-runtime/llama/proxy-record.js.map +0 -1
- package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +0 -118
- package/dist/core/local-runtime/llama/proxy-supervisor.js +0 -511
- package/dist/core/local-runtime/llama/proxy-supervisor.js.map +0 -1
- package/dist/core/web/public/next/assets/App-BCKqSppK.css +0 -1
- package/dist/core/web/public/next/assets/App-LuILXjWG.js +0 -16
- package/dist/core/web/public/next/assets/App-LuILXjWG.js.map +0 -1
- package/dist/core/web/public/next/assets/ApprovalsSection-B_Xor8JH.js +0 -2
- package/dist/core/web/public/next/assets/ApprovalsSection-B_Xor8JH.js.map +0 -1
- package/dist/core/web/public/next/assets/ApprovalsSection-CRP59wSb.css +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-BB8RD-tv.css +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-BEwITtPJ.js +0 -2
- package/dist/core/web/public/next/assets/AutonomySection-BEwITtPJ.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-DrxqhBPK.css +0 -1
- package/dist/core/web/public/next/assets/ChatSection-bRAzlMth.js +0 -77
- package/dist/core/web/public/next/assets/ChatSection-bRAzlMth.js.map +0 -1
- package/dist/core/web/public/next/assets/ConfirmDialog-BqkZdPs_.js +0 -2
- package/dist/core/web/public/next/assets/ConfirmDialog-BqkZdPs_.js.map +0 -1
- package/dist/core/web/public/next/assets/Dialog-CPmedg4S.js +0 -2
- package/dist/core/web/public/next/assets/Dialog-CPmedg4S.js.map +0 -1
- package/dist/core/web/public/next/assets/Dialog-DxN7RgB5.css +0 -1
- package/dist/core/web/public/next/assets/DiffViewer-DmPJbeM_.js +0 -7
- package/dist/core/web/public/next/assets/DiffViewer-DmPJbeM_.js.map +0 -1
- package/dist/core/web/public/next/assets/DiffViewer-hN7X6wGT.css +0 -1
- package/dist/core/web/public/next/assets/Epistemic-DiyMyeaN.css +0 -1
- package/dist/core/web/public/next/assets/Epistemic-M3SxLHjq.js +0 -2
- package/dist/core/web/public/next/assets/Epistemic-M3SxLHjq.js.map +0 -1
- package/dist/core/web/public/next/assets/Meter-CGBsbXUX.css +0 -1
- package/dist/core/web/public/next/assets/Meter-D_X7c9U3.js +0 -2
- package/dist/core/web/public/next/assets/Meter-D_X7c9U3.js.map +0 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-Ba5ZHu-8.js +0 -2
- package/dist/core/web/public/next/assets/MutationTokenDialog-Ba5ZHu-8.js.map +0 -1
- package/dist/core/web/public/next/assets/RefreshIndicator-O7jUBOmX.css +0 -1
- package/dist/core/web/public/next/assets/RefreshIndicator-vHGpmyzb.js +0 -2
- package/dist/core/web/public/next/assets/RefreshIndicator-vHGpmyzb.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-B5g6JEVk.js +0 -7
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-B5g6JEVk.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-DLl4DbGG.css +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-BIpdnxp-.css +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-CroxuKoi.js +0 -2
- package/dist/core/web/public/next/assets/RouteErrorBoundary-CroxuKoi.js.map +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-DGJMdUh2.css +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-p-7FCGfn.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-p-7FCGfn.js.map +0 -1
- package/dist/core/web/public/next/assets/Skeleton-4qq4HuJO.js +0 -2
- package/dist/core/web/public/next/assets/Skeleton-4qq4HuJO.js.map +0 -1
- package/dist/core/web/public/next/assets/Skeleton-D2JaTXyv.css +0 -1
- package/dist/core/web/public/next/assets/StatusBadge-BbEdqEGn.js +0 -2
- package/dist/core/web/public/next/assets/StatusBadge-BbEdqEGn.js.map +0 -1
- package/dist/core/web/public/next/assets/StatusBadge-TpDqZf6K.css +0 -1
- package/dist/core/web/public/next/assets/TableView-R6Yeztp1.css +0 -1
- package/dist/core/web/public/next/assets/TableView-nyYs7Sv1.js +0 -2
- package/dist/core/web/public/next/assets/TableView-nyYs7Sv1.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-CiZZxRPV.css +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-DjTpQUrA.js +0 -2
- package/dist/core/web/public/next/assets/UniverseConsoleApp-DjTpQUrA.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseView-BtApwayT.js +0 -9
- package/dist/core/web/public/next/assets/UniverseView-BtApwayT.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseView-gBxl6yum.css +0 -1
- package/dist/core/web/public/next/assets/UsageSection-Db99N6ao.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-Db99N6ao.js.map +0 -1
- package/dist/core/web/public/next/assets/UsageSection-UUYDidOg.css +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-COa3J2dO.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-COa3J2dO.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-mOAXvWa6.css +0 -1
- package/dist/core/web/public/next/assets/fleet-model-DXCfVtNW.js +0 -2
- package/dist/core/web/public/next/assets/fleet-model-DXCfVtNW.js.map +0 -1
- package/dist/core/web/public/next/assets/format-fggwu_Rs.js +0 -2
- package/dist/core/web/public/next/assets/format-fggwu_Rs.js.map +0 -1
- package/dist/core/web/public/next/assets/global-BeRYd1Bu.css +0 -1
- package/dist/core/web/public/next/assets/global-CNVapoV1.js +0 -2
- package/dist/core/web/public/next/assets/global-CNVapoV1.js.map +0 -1
- package/dist/core/web/public/next/assets/index-BkUlX2Se.js +0 -51
- package/dist/core/web/public/next/assets/index-BkUlX2Se.js.map +0 -1
- package/dist/core/web/public/next/assets/index-YNTgDG2b.js +0 -2
- package/dist/core/web/public/next/assets/index-YNTgDG2b.js.map +0 -1
- package/dist/core/web/public/next/assets/queries-C9XS4SYq.js +0 -2
- package/dist/core/web/public/next/assets/queries-C9XS4SYq.js.map +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-Bqa2v0a-.css +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-Bql1nA-z.js +0 -2
- package/dist/core/web/public/next/assets/use-guarded-action-Bql1nA-z.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-IrNQKtER.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-IrNQKtER.js.map +0 -1
- package/node_modules/which/CHANGELOG.md +0 -166
- /package/node_modules/marked/{LICENSE.md → LICENSE} +0 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/verse/mcp-control-api.ts — the HTTP surface for MCP and per-account
|
|
3
|
+
* CLI management.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately a SEPARATE handler from `control-api.ts` rather than new arms
|
|
6
|
+
* on its `if`-chain: that file is owned by another work stream, and this one
|
|
7
|
+
* carries a mutation that installs arbitrary code. Keeping them apart means
|
|
8
|
+
* the review surface for "can the hub run new code" is one file.
|
|
9
|
+
*
|
|
10
|
+
* ── Route shape ─────────────────────────────────────────────────────────────
|
|
11
|
+
*
|
|
12
|
+
* GET /api/verse/mcp which servers each seat would load
|
|
13
|
+
* GET /api/verse/mcp/cli-health per-account auth, plan and version drift
|
|
14
|
+
* POST /api/verse/mcp/cli-probe read the installed CLI versions (SPAWNS)
|
|
15
|
+
* POST /api/verse/mcp/proposal validate + disclose a write (writes nothing)
|
|
16
|
+
* POST /api/verse/mcp/apply perform the write the digest confirms
|
|
17
|
+
*
|
|
18
|
+
* The two GETs are free: no subprocess, no provider call, no write. Everything
|
|
19
|
+
* that costs something or changes something is a POST behind
|
|
20
|
+
* `passesMutationGate`, including `cli-probe` — it launches up to four vendor
|
|
21
|
+
* binaries, and a read route that does that is a side effect in disguise.
|
|
22
|
+
*
|
|
23
|
+
* `proposal` is a POST for the same reason, even though it writes nothing: it
|
|
24
|
+
* carries an operator-supplied command in its body, and it is the step that
|
|
25
|
+
* must be authenticated for the resulting digest to mean anything.
|
|
26
|
+
*
|
|
27
|
+
* ── Ordering requirement ────────────────────────────────────────────────────
|
|
28
|
+
*
|
|
29
|
+
* These paths live under `/api/verse/*`, which `isVerseApiPath()` matches
|
|
30
|
+
* wholesale and 404s when it does not recognise. So the dispatch call in
|
|
31
|
+
* `src/core/web/api.ts` MUST come before both `isVerseControlPath` and
|
|
32
|
+
* `isVerseApiPath`. See the comment at that call site.
|
|
33
|
+
*/
|
|
34
|
+
import { passesMutationGate, readBody, sendJson } from '../web/api.js';
|
|
35
|
+
import { audit } from '../sandbox/audit.js';
|
|
36
|
+
import { buildVerseAccountsSnapshot, readVerseAccountIdentities } from './accounts.js';
|
|
37
|
+
import { getVerseAccountCollector } from './accounts.js';
|
|
38
|
+
import { defaultAccountsRoot, resolveAccountsRoot } from './seats.js';
|
|
39
|
+
import { buildVerseMcpSnapshot } from './mcp-seat-view.js';
|
|
40
|
+
import { readVerseMcpScopeGate } from './mcp-scope.js';
|
|
41
|
+
import { buildVerseCliHealth, probeVerseAccountCliVersions, } from './mcp-cli-health.js';
|
|
42
|
+
import { applyVerseMcpProposal, buildVerseMcpProposal, } from './mcp-mutation.js';
|
|
43
|
+
const MCP_PREFIX = '/api/verse/mcp';
|
|
44
|
+
const MCP_ROUTES = new Set([
|
|
45
|
+
MCP_PREFIX,
|
|
46
|
+
`${MCP_PREFIX}/cli-health`,
|
|
47
|
+
`${MCP_PREFIX}/cli-probe`,
|
|
48
|
+
`${MCP_PREFIX}/proposal`,
|
|
49
|
+
`${MCP_PREFIX}/apply`,
|
|
50
|
+
]);
|
|
51
|
+
/** True for exactly the five MCP-management routes. */
|
|
52
|
+
export function isVerseMcpPath(path) {
|
|
53
|
+
return MCP_ROUTES.has(path);
|
|
54
|
+
}
|
|
55
|
+
const ERROR_STATUS = {
|
|
56
|
+
VERSE_INVALID: 400,
|
|
57
|
+
VERSE_REFUSED: 409,
|
|
58
|
+
VERSE_TOO_LARGE: 413,
|
|
59
|
+
VERSE_UNAVAILABLE: 503,
|
|
60
|
+
};
|
|
61
|
+
function sendError(res, code, error) {
|
|
62
|
+
sendJson(res, ERROR_STATUS[code], { code, error });
|
|
63
|
+
}
|
|
64
|
+
function sendInvalid(res, error) {
|
|
65
|
+
sendError(res, 'VERSE_INVALID', error);
|
|
66
|
+
}
|
|
67
|
+
function isRecord(value) {
|
|
68
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
69
|
+
}
|
|
70
|
+
async function readJsonBody(req, res) {
|
|
71
|
+
let raw;
|
|
72
|
+
try {
|
|
73
|
+
raw = await readBody(req);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
sendError(res, 'VERSE_TOO_LARGE', 'request body too large');
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
let parsed;
|
|
80
|
+
try {
|
|
81
|
+
parsed = raw.length === 0 ? {} : JSON.parse(raw);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
sendInvalid(res, 'invalid JSON body');
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (!isRecord(parsed)) {
|
|
88
|
+
sendInvalid(res, 'body must be a JSON object');
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
function passesPostGate(ctx, req, res) {
|
|
94
|
+
if (!ctx.allowDispatch) {
|
|
95
|
+
sendJson(res, 404, { error: 'not found' });
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return passesMutationGate(req, res, ctx.token);
|
|
99
|
+
}
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
// Shared reads
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
function accountsRootFor(ctx) {
|
|
104
|
+
if (ctx.accountsRoot !== undefined)
|
|
105
|
+
return ctx.accountsRoot;
|
|
106
|
+
try {
|
|
107
|
+
return resolveAccountsRoot(ctx.cfg);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return defaultAccountsRoot();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Seat inputs for the MCP view, WITHOUT running `discoverSeats()`.
|
|
115
|
+
*
|
|
116
|
+
* `discoverSeats` probes Ollama over HTTP and builds telemetry — none of which
|
|
117
|
+
* this view needs, and all of which would make a cheap read expensive. What
|
|
118
|
+
* the MCP question turns on is (engine, account), and that is exactly what
|
|
119
|
+
* `readVerseAccountIdentities` publishes. Seat ids for native seats ARE the
|
|
120
|
+
* account ids (see VerseSeat.id's own documentation).
|
|
121
|
+
*
|
|
122
|
+
* Local seats are collapsed into ONE row on purpose: every Ollama tag is
|
|
123
|
+
* launched through the same `buildClaudeLaunch` argv, so they are all isolated
|
|
124
|
+
* identically and listing twelve identical rows would be noise, not detail.
|
|
125
|
+
*/
|
|
126
|
+
export function verseMcpSeatInputs(accountsRoot) {
|
|
127
|
+
const seats = readVerseAccountIdentities(accountsRoot).map((identity) => ({
|
|
128
|
+
id: identity.id,
|
|
129
|
+
label: identity.label,
|
|
130
|
+
engine: identity.provider,
|
|
131
|
+
accountId: identity.id,
|
|
132
|
+
}));
|
|
133
|
+
seats.push({
|
|
134
|
+
id: 'local',
|
|
135
|
+
label: 'Local seats (every Ollama tag)',
|
|
136
|
+
engine: 'local',
|
|
137
|
+
accountId: 'local',
|
|
138
|
+
});
|
|
139
|
+
return seats;
|
|
140
|
+
}
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
// Handler
|
|
143
|
+
// ---------------------------------------------------------------------------
|
|
144
|
+
/**
|
|
145
|
+
* Handle one MCP-management request. Returns true when a response was
|
|
146
|
+
* written (including errors); false when `path` is not one of these routes.
|
|
147
|
+
*/
|
|
148
|
+
export async function handleVerseMcpApi(ctx, req, res, path, method) {
|
|
149
|
+
if (!isVerseMcpPath(path))
|
|
150
|
+
return false;
|
|
151
|
+
try {
|
|
152
|
+
const accountsRoot = accountsRootFor(ctx);
|
|
153
|
+
// ── GET /api/verse/mcp ────────────────────────────────────────────────
|
|
154
|
+
if (path === MCP_PREFIX) {
|
|
155
|
+
if (method !== 'GET') {
|
|
156
|
+
sendJson(res, 404, { error: `not found: ${method} ${path}` });
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
sendJson(res, 200, buildVerseMcpSnapshot({
|
|
160
|
+
accountsRoot,
|
|
161
|
+
seats: verseMcpSeatInputs(accountsRoot),
|
|
162
|
+
}));
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
// ── GET /api/verse/mcp/cli-health ─────────────────────────────────────
|
|
166
|
+
//
|
|
167
|
+
// Free: derived entirely from the collector's existing records plus the
|
|
168
|
+
// pinned-version constant. No subprocess. A version NUMBER requires the
|
|
169
|
+
// probe below; its absence is reported as `unverified`, never faked.
|
|
170
|
+
if (path === `${MCP_PREFIX}/cli-health`) {
|
|
171
|
+
if (method !== 'GET') {
|
|
172
|
+
sendJson(res, 404, { error: `not found: ${method} ${path}` });
|
|
173
|
+
return true;
|
|
174
|
+
}
|
|
175
|
+
const snapshot = buildVerseAccountsSnapshot({
|
|
176
|
+
accountsRoot,
|
|
177
|
+
collector: getVerseAccountCollector(),
|
|
178
|
+
});
|
|
179
|
+
sendJson(res, 200, buildVerseCliHealth({ accounts: snapshot.accounts }));
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
// ── POST /api/verse/mcp/cli-probe ─────────────────────────────────────
|
|
183
|
+
//
|
|
184
|
+
// Gated because it SPAWNS: help/version invocations only, but four vendor
|
|
185
|
+
// binaries is a real cost and a real side effect on this machine.
|
|
186
|
+
if (path === `${MCP_PREFIX}/cli-probe`) {
|
|
187
|
+
if (method !== 'POST') {
|
|
188
|
+
sendJson(res, 404, { error: `not found: ${method} ${path}` });
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
if (!passesPostGate(ctx, req, res))
|
|
192
|
+
return true;
|
|
193
|
+
const body = await readJsonBody(req, res);
|
|
194
|
+
if (!body)
|
|
195
|
+
return true;
|
|
196
|
+
for (const key of Object.keys(body)) {
|
|
197
|
+
sendInvalid(res, `unknown key: ${key}`);
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
let readings;
|
|
201
|
+
try {
|
|
202
|
+
readings = await probeVerseAccountCliVersions({ accountsRoot });
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
sendError(res, 'VERSE_UNAVAILABLE', 'the CLI version probe could not be run');
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
const snapshot = buildVerseAccountsSnapshot({
|
|
209
|
+
accountsRoot,
|
|
210
|
+
collector: getVerseAccountCollector(),
|
|
211
|
+
});
|
|
212
|
+
const health = buildVerseCliHealth({ accounts: snapshot.accounts, readings });
|
|
213
|
+
audit({
|
|
214
|
+
action: 'verse.mcp.cli-probe',
|
|
215
|
+
repo: null,
|
|
216
|
+
sandboxId: null,
|
|
217
|
+
summary: `read CLI versions for ${readings.size} account(s); drift=${health.driftDetected}`,
|
|
218
|
+
result: 'ok',
|
|
219
|
+
});
|
|
220
|
+
sendJson(res, 200, health);
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
// ── POST /api/verse/mcp/proposal ──────────────────────────────────────
|
|
224
|
+
//
|
|
225
|
+
// Writes NOTHING. Returns the full command, args and env KEYS (values
|
|
226
|
+
// redacted), the warnings, the Locus scope, and the digest that the apply
|
|
227
|
+
// step demands back.
|
|
228
|
+
if (path === `${MCP_PREFIX}/proposal` || path === `${MCP_PREFIX}/apply`) {
|
|
229
|
+
const applying = path === `${MCP_PREFIX}/apply`;
|
|
230
|
+
if (method !== 'POST') {
|
|
231
|
+
sendJson(res, 404, { error: `not found: ${method} ${path}` });
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
if (!passesPostGate(ctx, req, res))
|
|
235
|
+
return true;
|
|
236
|
+
const body = await readJsonBody(req, res);
|
|
237
|
+
if (!body)
|
|
238
|
+
return true;
|
|
239
|
+
const allowed = applying
|
|
240
|
+
? new Set(['target', 'server', 'digest', 'confirm'])
|
|
241
|
+
: new Set(['target', 'server']);
|
|
242
|
+
for (const key of Object.keys(body)) {
|
|
243
|
+
if (!allowed.has(key)) {
|
|
244
|
+
sendInvalid(res, `unknown key: ${key}`);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const target = body['target'];
|
|
249
|
+
if (typeof target !== 'string' || target.length === 0 || target.length > 128) {
|
|
250
|
+
sendInvalid(res, 'target is required');
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
if (body['server'] === undefined) {
|
|
254
|
+
sendInvalid(res, 'server is required');
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
const scope = readVerseMcpScopeGate();
|
|
258
|
+
if (!applying) {
|
|
259
|
+
const proposal = buildVerseMcpProposal({
|
|
260
|
+
targetId: target,
|
|
261
|
+
server: body['server'],
|
|
262
|
+
accountsRoot,
|
|
263
|
+
scope,
|
|
264
|
+
});
|
|
265
|
+
sendRefusableResult(res, proposal);
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
// An explicit `confirm: true` on top of the digest. The digest is the
|
|
269
|
+
// real control; this is the second half of "never a one-click install"
|
|
270
|
+
// being visible in the request itself.
|
|
271
|
+
if (body['confirm'] !== true) {
|
|
272
|
+
sendInvalid(res, 'confirm must be true to apply a proposal');
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
const supplied = body['digest'];
|
|
276
|
+
if (typeof supplied !== 'string' || supplied.length === 0 || supplied.length > 128) {
|
|
277
|
+
sendInvalid(res, 'digest is required to apply a proposal');
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
const result = applyVerseMcpProposal({
|
|
281
|
+
targetId: target,
|
|
282
|
+
server: body['server'],
|
|
283
|
+
accountsRoot,
|
|
284
|
+
scope,
|
|
285
|
+
digest: supplied,
|
|
286
|
+
});
|
|
287
|
+
// The audit summary names the target and the server NAME. It never
|
|
288
|
+
// carries the command, args or env — `stripSecrets` is a backstop, not
|
|
289
|
+
// a licence to hand it a secret.
|
|
290
|
+
const serverName = isRecord(body['server']) && typeof body['server']['name'] === 'string'
|
|
291
|
+
? body['server']['name']
|
|
292
|
+
: '(unnamed)';
|
|
293
|
+
audit({
|
|
294
|
+
action: 'verse.mcp.apply',
|
|
295
|
+
repo: null,
|
|
296
|
+
sandboxId: null,
|
|
297
|
+
summary: result.ok
|
|
298
|
+
? `${result.action} MCP server ${serverName} in ${result.target.ref}`
|
|
299
|
+
: `refused MCP server ${serverName} for ${target}: ${result.refusal}`,
|
|
300
|
+
result: result.ok ? 'ok' : 'refused',
|
|
301
|
+
});
|
|
302
|
+
sendRefusableResult(res, result);
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
/* c8 ignore next 2 -- isVerseMcpPath already narrowed to the five routes. */
|
|
306
|
+
sendJson(res, 404, { error: `not found: ${method} ${path}` });
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
sendError(res, 'VERSE_UNAVAILABLE', 'MCP management is unavailable on this server');
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* A refusal is a 409 carrying the full result body with a plain-language
|
|
316
|
+
* `note` — the same convention `VerseScopeResult` established, which the web
|
|
317
|
+
* client relies on when it reads `error` and falls back to `note`.
|
|
318
|
+
*/
|
|
319
|
+
function sendRefusableResult(res, result) {
|
|
320
|
+
sendJson(res, result.ok ? 200 : 409, result);
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=mcp-control-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-control-api.js","sourceRoot":"","sources":["../../../src/core/verse/mcp-control-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/verse/mcp-mutation.ts — adding or editing an MCP server, deliberately
|
|
3
|
+
* made difficult.
|
|
4
|
+
*
|
|
5
|
+
* docs/VERSE-WORKSPACES.md §3: "an MCP server is arbitrary code with the
|
|
6
|
+
* agent's privileges"; "Adding or editing a server is a privileged,
|
|
7
|
+
* outward-facing change. It belongs behind the same mutation gate as the other
|
|
8
|
+
* control-plane writes, and it should show the full command and environment
|
|
9
|
+
* (redacted) before it is saved — never a one-click install of something the
|
|
10
|
+
* operator has not read."
|
|
11
|
+
*
|
|
12
|
+
* ── How "never one-click" is enforced, rather than just intended ────────────
|
|
13
|
+
*
|
|
14
|
+
* A write takes TWO requests, and the second cannot be forged from the first
|
|
15
|
+
* by a client that did not render it:
|
|
16
|
+
*
|
|
17
|
+
* 1. {@link buildVerseMcpProposal} validates the spec, resolves the target,
|
|
18
|
+
* and returns a PROPOSAL containing the full command and args verbatim,
|
|
19
|
+
* the env KEYS with every value redacted to '<set>', the warnings, and a
|
|
20
|
+
* `digest` over exactly what was shown plus the target file's current
|
|
21
|
+
* contents. Nothing is written.
|
|
22
|
+
* 2. {@link applyVerseMcpProposal} refuses unless it is handed that same
|
|
23
|
+
* digest back AND the target file is still byte-identical to what the
|
|
24
|
+
* digest was taken over. A stale digest is a refusal, not a merge.
|
|
25
|
+
*
|
|
26
|
+
* The digest binds the decision to the disclosure. An operator who never saw
|
|
27
|
+
* the command cannot produce it, and a file that changed underneath the
|
|
28
|
+
* proposal invalidates it.
|
|
29
|
+
*
|
|
30
|
+
* ── What this refuses to do ─────────────────────────────────────────────────
|
|
31
|
+
*
|
|
32
|
+
* - Rewrite TOML. Codex and Grok keep their MCP servers in `config.toml`.
|
|
33
|
+
* `src/core/integrations/editors.ts` already established the rule for
|
|
34
|
+
* this repo — Codex "is intentionally delegated to its official CLI so
|
|
35
|
+
* this module never attempts to parse and rewrite a user's TOML
|
|
36
|
+
* configuration" — and a half-understood TOML rewrite of an operator's
|
|
37
|
+
* config is a worse outcome than a refusal.
|
|
38
|
+
* - Touch ~/.ashlr/config.json, ~/.ashlr/enrollment.json or ~/.ashlr/KILL.
|
|
39
|
+
* Those are not MCP registries and are explicitly out of bounds.
|
|
40
|
+
* - Write anywhere the caller names freely. Targets are an enumerated set.
|
|
41
|
+
*
|
|
42
|
+
* ── What may leave this module ──────────────────────────────────────────────
|
|
43
|
+
*
|
|
44
|
+
* Env VALUES never leave, in any form, on any path: not in the proposal, not
|
|
45
|
+
* in the apply result, not in the audit summary, not in an error message. The
|
|
46
|
+
* proposal carries `redactEnv`'d specs only. The real values live in the
|
|
47
|
+
* request body and go straight to disk.
|
|
48
|
+
*/
|
|
49
|
+
import type { McpServerSpec } from '../types.js';
|
|
50
|
+
import { type VerseMcpServerView } from './mcp-seat-view.js';
|
|
51
|
+
import type { VerseMcpScopeGate } from './mcp-scope.js';
|
|
52
|
+
/**
|
|
53
|
+
* Where a server may be written.
|
|
54
|
+
*
|
|
55
|
+
* `hub` ~/.ashlr/settings.json — the hub's own aggregated
|
|
56
|
+
* gateway registry (M66; `knownConfigPaths()` scans it).
|
|
57
|
+
* `account:<id>` that account's private JSON registry. Only accounts
|
|
58
|
+
* whose native config is JSON qualify; Codex and Grok keep
|
|
59
|
+
* TOML and are refused by name below.
|
|
60
|
+
*/
|
|
61
|
+
export type VerseMcpTargetId = 'hub' | `account:${string}`;
|
|
62
|
+
export type VerseMcpRefusal = 'mcp-target-unknown' | 'mcp-target-not-json' | 'mcp-target-unresolved' | 'mcp-target-forbidden' | 'mcp-spec-invalid' | 'mcp-digest-mismatch' | 'mcp-target-changed' | 'mcp-scope-refused' | 'mcp-write-failed';
|
|
63
|
+
/** Files that must never be written by this module, whatever a caller asks. */
|
|
64
|
+
export declare const VERSE_MCP_FORBIDDEN_FILES: readonly string[];
|
|
65
|
+
export interface VerseMcpTarget {
|
|
66
|
+
id: VerseMcpTargetId;
|
|
67
|
+
/** Absolute path. SERVER-SIDE ONLY — projected to `ref` for transport. */
|
|
68
|
+
path: string;
|
|
69
|
+
/** Path relative to $HOME. What the operator is shown. */
|
|
70
|
+
ref: string;
|
|
71
|
+
/** Human label for the surface. */
|
|
72
|
+
label: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolve a target id to a file, or explain why not.
|
|
76
|
+
*
|
|
77
|
+
* `accountsRoot` is only consulted for `account:` targets. Account state
|
|
78
|
+
* directories are private and never published — only `ref` crosses out.
|
|
79
|
+
*/
|
|
80
|
+
export declare function resolveVerseMcpTarget(id: string, options: {
|
|
81
|
+
accountsRoot: string;
|
|
82
|
+
home?: string;
|
|
83
|
+
}): {
|
|
84
|
+
ok: true;
|
|
85
|
+
target: VerseMcpTarget;
|
|
86
|
+
} | {
|
|
87
|
+
ok: false;
|
|
88
|
+
refusal: VerseMcpRefusal;
|
|
89
|
+
error: string;
|
|
90
|
+
};
|
|
91
|
+
export type VerseMcpSpecParse = {
|
|
92
|
+
ok: true;
|
|
93
|
+
spec: McpServerSpec;
|
|
94
|
+
warnings: string[];
|
|
95
|
+
} | {
|
|
96
|
+
ok: false;
|
|
97
|
+
error: string;
|
|
98
|
+
};
|
|
99
|
+
/**
|
|
100
|
+
* Validate a caller-supplied server spec.
|
|
101
|
+
*
|
|
102
|
+
* Strict by construction: unknown keys are rejected, every string is bounded
|
|
103
|
+
* and printable, and nothing is coerced. Warnings are returned rather than
|
|
104
|
+
* silently swallowed — they are part of what the operator must read.
|
|
105
|
+
*/
|
|
106
|
+
export declare function parseVerseMcpSpec(body: unknown): VerseMcpSpecParse;
|
|
107
|
+
export interface VerseMcpProposal {
|
|
108
|
+
ok: true;
|
|
109
|
+
/** What the operator must read before confirming. Env values are '<set>'. */
|
|
110
|
+
server: VerseMcpServerView;
|
|
111
|
+
target: {
|
|
112
|
+
id: VerseMcpTargetId;
|
|
113
|
+
ref: string;
|
|
114
|
+
label: string;
|
|
115
|
+
};
|
|
116
|
+
/** 'add' when the name is new in the target, 'replace' when it is not. */
|
|
117
|
+
action: 'add' | 'replace';
|
|
118
|
+
/** The server this would overwrite, redacted. Null on an add. */
|
|
119
|
+
replaces: VerseMcpServerView | null;
|
|
120
|
+
/** Everything the operator should weigh. Never empty for a real install. */
|
|
121
|
+
warnings: string[];
|
|
122
|
+
/** The scope this write lands under, and whether Locus permits it. */
|
|
123
|
+
scope: VerseMcpScopeGate;
|
|
124
|
+
/**
|
|
125
|
+
* Binds this exact disclosure to the target's current contents. `apply`
|
|
126
|
+
* refuses without it, and refuses again if the file moved underneath.
|
|
127
|
+
*/
|
|
128
|
+
digest: string;
|
|
129
|
+
note: string;
|
|
130
|
+
}
|
|
131
|
+
export interface VerseMcpRefusalResult {
|
|
132
|
+
ok: false;
|
|
133
|
+
refusal: VerseMcpRefusal;
|
|
134
|
+
error: string;
|
|
135
|
+
note: string;
|
|
136
|
+
}
|
|
137
|
+
export declare const VERSE_MCP_PROPOSAL_NOTE: string;
|
|
138
|
+
/**
|
|
139
|
+
* The digest the operator confirms against.
|
|
140
|
+
*
|
|
141
|
+
* Covers the REDACTED spec (what was shown), the target, and a hash of the
|
|
142
|
+
* target file's current bytes. Env values are deliberately outside it: the
|
|
143
|
+
* digest must be reproducible from what was displayed.
|
|
144
|
+
*/
|
|
145
|
+
export declare function verseMcpProposalDigest(input: {
|
|
146
|
+
server: VerseMcpServerView;
|
|
147
|
+
targetId: string;
|
|
148
|
+
targetBytes: string;
|
|
149
|
+
}): string;
|
|
150
|
+
export interface VerseMcpProposalOptions {
|
|
151
|
+
targetId: string;
|
|
152
|
+
server: unknown;
|
|
153
|
+
accountsRoot: string;
|
|
154
|
+
scope: VerseMcpScopeGate;
|
|
155
|
+
home?: string;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Validate, disclose, and hand back a digest. Writes nothing.
|
|
159
|
+
*/
|
|
160
|
+
export declare function buildVerseMcpProposal(options: VerseMcpProposalOptions): VerseMcpProposal | VerseMcpRefusalResult;
|
|
161
|
+
export interface VerseMcpApplyResult {
|
|
162
|
+
ok: true;
|
|
163
|
+
action: 'add' | 'replace';
|
|
164
|
+
target: {
|
|
165
|
+
id: VerseMcpTargetId;
|
|
166
|
+
ref: string;
|
|
167
|
+
};
|
|
168
|
+
/** Re-read from disk after the write, redacted. What was actually persisted. */
|
|
169
|
+
server: VerseMcpServerView;
|
|
170
|
+
note: string;
|
|
171
|
+
}
|
|
172
|
+
export declare const VERSE_MCP_APPLIED_NOTE: string;
|
|
173
|
+
export interface VerseMcpApplyOptions extends VerseMcpProposalOptions {
|
|
174
|
+
/** The digest returned by the proposal. A mismatch is a refusal. */
|
|
175
|
+
digest: string;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Apply a proposal the operator confirmed.
|
|
179
|
+
*
|
|
180
|
+
* Refuses unless the supplied digest reproduces from (a) the redacted spec it
|
|
181
|
+
* is about to write and (b) the target file's CURRENT bytes. That second half
|
|
182
|
+
* is what makes a stale confirmation fail instead of quietly clobbering a
|
|
183
|
+
* change made in between.
|
|
184
|
+
*
|
|
185
|
+
* The write is atomic: a sibling temp file, mode 0600, then rename.
|
|
186
|
+
*/
|
|
187
|
+
export declare function applyVerseMcpProposal(options: VerseMcpApplyOptions): VerseMcpApplyResult | VerseMcpRefusalResult;
|