@paradigma-inc/flywheel 0.1.53 → 0.1.72
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 +149 -17
- package/package.json +4 -2
- package/skills/flywheel/SKILL.md +4 -3
- package/skills/flywheel/getting-started/flywheel-quickstart.md +4 -4
- package/skills/flywheel/references/flywheel-cli-tool-map.md +47 -35
- package/skills/flywheel/references/flywheel-mcp-tool-map.md +16 -5
- package/skills/flywheel/setting-up-flywheel/claude-code-cli-installation.md +3 -3
- package/skills/flywheel/setting-up-flywheel/codex-cli-installation.md +3 -3
- package/skills/flywheel/setting-up-flywheel/installation-overview.md +9 -8
- package/skills/flywheel/setting-up-flywheel/other-hosts-installation.md +1 -1
- package/skills/flywheel/setting-up-flywheel/updating-flywheel-mcp.md +4 -4
- package/skills/flywheel-auto/SKILL.md +4 -3
- package/skills/flywheel-auto/references/flywheel-cli-tool-map.md +37 -35
- package/skills/flywheel-auto/references/flywheel-mcp-tool-map.md +4 -4
- package/skills/flywheel-lookahead/SKILL.md +1 -1
- package/skills/flywheel-lookahead/references/flywheel-cli-tool-map.md +37 -35
- package/skills/flywheel-lookahead/references/flywheel-mcp-tool-map.md +4 -4
- package/skills/flywheel-prove/SKILL.md +1 -1
- package/skills/flywheel-reproduce/SKILL.md +4 -3
- package/skills/flywheel-reproduce/references/flywheel-cli-tool-map.md +37 -35
- package/skills/flywheel-reproduce/references/flywheel-mcp-tool-map.md +4 -4
- package/skills/flywheel-to-graph/SKILL.md +1 -1
- package/skills/flywheel-to-graph/references/flywheel-cli-tool-map.md +37 -35
- package/skills/flywheel-to-graph/references/flywheel-mcp-tool-map.md +4 -4
- package/skills/flywheel-tree/SKILL.md +1 -1
- package/src/agents.mjs +114 -48
- package/src/cli.mjs +373 -56
- package/src/mcp-writer.mjs +190 -17
- package/src/runtime/required-runtime-commands.json +19 -4
- package/src/runtime/vendor/flywheel-cli-dist/auth/login.d.ts +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/auth/login.js +3 -6
- package/src/runtime/vendor/flywheel-cli-dist/auth/login.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/auth/profiles.d.ts +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/auth/profiles.js +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/auth/profiles.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/_admin-auth.d.ts +27 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_admin-auth.js +54 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_admin-auth.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_artifacts-upload-helpers.d.ts +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/_artifacts-upload-helpers.js +6 -5
- package/src/runtime/vendor/flywheel-cli-dist/commands/_artifacts-upload-helpers.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/_browser-handoff.d.ts +21 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_browser-handoff.js +51 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_browser-handoff.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_open-url.d.ts +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/_open-url.js +6 -3
- package/src/runtime/vendor/flywheel-cli-dist/commands/_open-url.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/_secret-param.d.ts +7 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_secret-param.js +18 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_secret-param.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_stream-file-out.d.ts +39 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_stream-file-out.js +72 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/_stream-file-out.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-detach.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-detach.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-add.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-add.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-remove.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-remove.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-set-primary.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-set-primary.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-get.d.ts +2 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-get.js +6 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-get.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-preview.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-preview.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-proof.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-proof.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-get.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-get.js +11 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-get.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-set.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-set.js +60 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-set.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export-stream.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export-stream.js +115 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export-stream.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export.js +12 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-list.d.ts +4 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-list.js +39 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-list.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-nodes-audit-list.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-nodes-audit-list.js +15 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/admin-nodes-audit-list.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/api-keys-list.d.ts +18 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/api-keys-list.js +38 -5
- package/src/runtime/vendor/flywheel-cli-dist/commands/api-keys-list.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/artifacts-delete.js +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/artifacts-delete.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/auth-mode.d.ts +4 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/auth-mode.js +42 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/auth-mode.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/auth-status.js +15 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/auth-status.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-list.js +8 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-list.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-request-approval.js +6 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-request-approval.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-release-all.js +18 -7
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-release-all.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/credits-billing-portal.js +8 -4
- package/src/runtime/vendor/flywheel-cli-dist/commands/credits-billing-portal.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/credits-purchase.js +8 -4
- package/src/runtime/vendor/flywheel-cli-dist/commands/credits-purchase.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/credits-subscribe.js +8 -4
- package/src/runtime/vendor/flywheel-cli-dist/commands/credits-subscribe.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/destructive-confirmation.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/destructive-confirmation.js +7 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/destructive-confirmation.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/enums.d.ts +8 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/enums.js +4 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/enums.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/env.d.ts +0 -4
- package/src/runtime/vendor/flywheel-cli-dist/commands/env.js +7 -12
- package/src/runtime/vendor/flywheel-cli-dist/commands/env.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/export-history.js +42 -30
- package/src/runtime/vendor/flywheel-cli-dist/commands/export-history.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/export-subgraph.js +12 -4
- package/src/runtime/vendor/flywheel-cli-dist/commands/export-subgraph.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/github-link.js +9 -14
- package/src/runtime/vendor/flywheel-cli-dist/commands/github-link.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/help-format.d.ts +31 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/help-format.js +69 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/help-format.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/help.d.ts +6 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/help.js +226 -124
- package/src/runtime/vendor/flywheel-cli-dist/commands/help.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-create.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-create.js +25 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-create.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-delete.d.ts +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-delete.js +6 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-delete.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-list.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-list.js +10 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-list.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-runs-list.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-runs-list.js +15 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-runs-list.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-create.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-create.js +8 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-create.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-delete.d.ts +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-delete.js +6 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-delete.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-list.d.ts +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-list.js +6 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-list.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-update.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-update.js +8 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-update.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-set-enabled.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-set-enabled.js +8 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-set-enabled.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-update.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-update.js +29 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-update.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/index.js +36 -6
- package/src/runtime/vendor/flywheel-cli-dist/commands/index.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-huggingface-set.js +7 -3
- package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-huggingface-set.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-wandb-set.js +6 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-wandb-set.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-add-parent.js +6 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-add-parent.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete-bulk.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete-bulk.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete.js +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-remove-parent.js +8 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-remove-parent.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-resolve-slug.js +55 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-resolve-slug.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/profile-list.js +13 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/profile-list.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/profile-set.js +4 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/profile-set.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/profile-show.js +16 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/profile-show.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/account.js +8 -7
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/account.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/admin.d.ts +8 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/admin.js +131 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/admin.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/api-keys.js +8 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/api-keys.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/approval.js +29 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/approval.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/artifacts.js +13 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/artifacts.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/auth.js +2 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/auth.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/budgets.js +11 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/budgets.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/compute.js +2 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/compute.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/credits.js +8 -6
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/credits.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/env.js +7 -5
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/env.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/github.js +6 -14
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/github.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/hooks.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/hooks.js +312 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/hooks.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/integrations.js +22 -8
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/integrations.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/lifecycle.js +122 -25
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/lifecycle.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/profile.js +2 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/profile.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/resources.js +1 -31
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/resources.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/sharing.js +12 -4
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry/sharing.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry.d.ts +2 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry.js +46 -9
- package/src/runtime/vendor/flywheel-cli-dist/commands/registry.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-refresh.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-refresh.js +20 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-refresh.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-resolve.d.ts +2 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-resolve.js +23 -0
- package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-resolve.js.map +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/errors.d.ts +15 -0
- package/src/runtime/vendor/flywheel-cli-dist/errors.js +16 -1
- package/src/runtime/vendor/flywheel-cli-dist/errors.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/http/client.d.ts +1 -0
- package/src/runtime/vendor/flywheel-cli-dist/http/client.js +75 -19
- package/src/runtime/vendor/flywheel-cli-dist/http/client.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/http/debug.d.ts +3 -0
- package/src/runtime/vendor/flywheel-cli-dist/http/debug.js +21 -2
- package/src/runtime/vendor/flywheel-cli-dist/http/debug.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/main.js +119 -10
- package/src/runtime/vendor/flywheel-cli-dist/main.js.map +1 -1
- package/src/runtime/vendor/flywheel-cli-dist/output/format.js +44 -6
- package/src/runtime/vendor/flywheel-cli-dist/output/format.js.map +1 -1
- package/src/runtime/vendor/manifest.json +82 -10
- package/src/setup/base-url.mjs +43 -0
- package/src/setup/command.mjs +2 -0
- package/src/setup/io/patchers/json.mjs +2 -0
- package/src/setup/io/patchers/toml.mjs +7 -1
- package/src/setup/io/patchers/yaml.mjs +2 -0
- package/src/setup/modes/cli.mjs +72 -24
- package/src/setup/modes/mcp-command.mjs +146 -38
- package/src/setup/modes/mcp.mjs +26 -1
- package/src/setup/resolved-selection-record.mjs +25 -0
- package/src/setup/shared/prior-mode-detect.mjs +133 -14
- package/src/setup-auth.mjs +3 -2
- package/src/skill-installer.mjs +179 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-get.d.ts +0 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-get.js +0 -6
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-get.js.map +0 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-set.d.ts +0 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-set.js +0 -19
- package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-set.js.map +0 -1
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-audit-list.d.ts +0 -2
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-audit-list.js +0 -7
- package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-audit-list.js.map +0 -1
|
@@ -9,23 +9,24 @@ import {
|
|
|
9
9
|
SERVER_NAME,
|
|
10
10
|
detectHosts,
|
|
11
11
|
getHost,
|
|
12
|
+
isSkillOnlyHost,
|
|
12
13
|
normalizeHosts,
|
|
13
14
|
} from "../../agents.mjs";
|
|
14
15
|
import {
|
|
16
|
+
readEntryServerUrl,
|
|
15
17
|
readNamedConfigEntry,
|
|
16
18
|
readJsonConfig,
|
|
17
19
|
readTomlServerEntry,
|
|
18
20
|
readYamlConfig,
|
|
19
21
|
resolveMcpPath,
|
|
20
22
|
} from "../../mcp-writer.mjs";
|
|
21
|
-
import {
|
|
22
|
-
resolveSetupApiKey,
|
|
23
|
-
} from "../../setup-auth.mjs";
|
|
23
|
+
import { resolveSetupApiKey } from "../../setup-auth.mjs";
|
|
24
24
|
import {
|
|
25
25
|
cleanupInstalledSkillArtifactsForHosts,
|
|
26
26
|
formatSupportedInstallSkillHosts,
|
|
27
27
|
inspectInstalledSkillArtifactsForHosts,
|
|
28
28
|
installBundledSkillForHosts,
|
|
29
|
+
isDirectCopySkillHost,
|
|
29
30
|
listBundledSkills,
|
|
30
31
|
partitionInstallSkillHosts,
|
|
31
32
|
resolveInstalledSkillDir,
|
|
@@ -34,20 +35,20 @@ import {
|
|
|
34
35
|
} from "../../skill-installer.mjs";
|
|
35
36
|
import { runMcpSetupMode } from "./mcp.mjs";
|
|
36
37
|
import { SetupModeUsageError } from "../mode.mjs";
|
|
38
|
+
import { recordResolvedHosts } from "../resolved-selection-record.mjs";
|
|
37
39
|
import {
|
|
38
40
|
detectPriorModeForSetup,
|
|
39
41
|
formatPriorModeConflictError,
|
|
40
42
|
} from "../shared/prior-mode-detect.mjs";
|
|
41
43
|
import { renderSetupSummary } from "../shared/summary.mjs";
|
|
44
|
+
import { resolveSetupBaseUrl } from "../base-url.mjs";
|
|
42
45
|
|
|
43
|
-
const INSTALL_SKILL_BASE_URL = "https://flywheel.paradigma.inc";
|
|
44
|
-
const DEFAULT_BASE_URL =
|
|
45
|
-
process.env.FLYWHEEL_PUBLIC_BASE_URL || INSTALL_SKILL_BASE_URL;
|
|
46
46
|
const NON_INTERACTIVE_SKILL_DECISION_ERROR =
|
|
47
47
|
"Non-interactive setup requires one of --install-skill or --skip-skill.";
|
|
48
48
|
const MUTUALLY_EXCLUSIVE_SKILL_FLAGS_ERROR =
|
|
49
49
|
"--install-skill and --skip-skill cannot be used together.";
|
|
50
|
-
const GUIDED_SKILL_DECISION_TEST_ENV =
|
|
50
|
+
const GUIDED_SKILL_DECISION_TEST_ENV =
|
|
51
|
+
"FLYWHEEL_GUIDED_SKILL_DECISION_FOR_TESTS";
|
|
51
52
|
const ENABLE_TEST_SEAMS_ENV = "FLYWHEEL_ENABLE_TEST_SEAMS";
|
|
52
53
|
|
|
53
54
|
const log = {
|
|
@@ -65,6 +66,12 @@ const CHECKBOX_THEME = {
|
|
|
65
66
|
},
|
|
66
67
|
};
|
|
67
68
|
|
|
69
|
+
function hostChoiceDescription({ detected = false, configured = false } = {}) {
|
|
70
|
+
if (configured) return "Already has a Flywheel entry for this scope.";
|
|
71
|
+
if (detected) return "Detected on this machine.";
|
|
72
|
+
return "Supported host; select it if you use it here.";
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
function normalizeBaseUrl(value) {
|
|
69
76
|
const normalized = String(value || "").trim();
|
|
70
77
|
let parsedUrl;
|
|
@@ -94,9 +101,12 @@ function normalizeServerName(value) {
|
|
|
94
101
|
function selectedHostsFromOptions(options) {
|
|
95
102
|
const hosts = [];
|
|
96
103
|
if (options.claude) hosts.push("claude");
|
|
104
|
+
if (options.cursor) hosts.push("cursor");
|
|
105
|
+
if (options.universal) hosts.push("universal");
|
|
106
|
+
if (options.antigravity) hosts.push("antigravity");
|
|
97
107
|
if (options.opencode) hosts.push("opencode");
|
|
98
108
|
if (options.codex) hosts.push("codex");
|
|
99
|
-
if (options.
|
|
109
|
+
if (options.gemini) hosts.push("gemini");
|
|
100
110
|
if (options.piMono) hosts.push("pi-mono");
|
|
101
111
|
if (options.hermesAgent) hosts.push("hermes-agent");
|
|
102
112
|
if (options.openclaw) hosts.push("openclaw");
|
|
@@ -112,6 +122,9 @@ function mcpCandidatesForScope(host, scope) {
|
|
|
112
122
|
|
|
113
123
|
async function readExistingServerState(hostName, scope, serverName) {
|
|
114
124
|
const host = getHost(hostName);
|
|
125
|
+
if (isSkillOnlyHost(host)) {
|
|
126
|
+
return { exists: false, url: null, mcpPath: null };
|
|
127
|
+
}
|
|
115
128
|
const mcpPath = await resolveMcpPath(mcpCandidatesForScope(host, scope));
|
|
116
129
|
|
|
117
130
|
if (host.mcp.configType === "toml") {
|
|
@@ -126,7 +139,7 @@ async function readExistingServerState(hostName, scope, serverName) {
|
|
|
126
139
|
const entry = readNamedConfigEntry(existing, host.mcp.configKey, serverName);
|
|
127
140
|
return {
|
|
128
141
|
exists: entry !== null,
|
|
129
|
-
url:
|
|
142
|
+
url: readEntryServerUrl(entry),
|
|
130
143
|
mcpPath,
|
|
131
144
|
};
|
|
132
145
|
}
|
|
@@ -151,6 +164,21 @@ async function inspectInstallSkillHosts({
|
|
|
151
164
|
const driftHosts = [];
|
|
152
165
|
|
|
153
166
|
for (const hostName of hostNames) {
|
|
167
|
+
const host = getHost(hostName);
|
|
168
|
+
// Skill-only hosts (universal, antigravity) never write an MCP config, so
|
|
169
|
+
// they are not candidates for "needs setup" / "drift" / "matching"
|
|
170
|
+
// classification. Skipping them here is what keeps the auth-resolution
|
|
171
|
+
// gate downstream accurate: without this branch they would land in
|
|
172
|
+
// `needsSetupHosts` and force an API-key mint on `setup --mode mcp
|
|
173
|
+
// --universal --skip-skill`, which is a pure no-op path that must stay
|
|
174
|
+
// hermetic (no browser, no blocking prompt).
|
|
175
|
+
if (isSkillOnlyHost(host)) {
|
|
176
|
+
hostStates.set(hostName, {
|
|
177
|
+
classification: "skill-only",
|
|
178
|
+
mcpPath: null,
|
|
179
|
+
});
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
154
182
|
// eslint-disable-next-line no-await-in-loop
|
|
155
183
|
const existingState = await readExistingServerState(
|
|
156
184
|
hostName,
|
|
@@ -237,13 +265,16 @@ async function promptHosts(scope, detected, serverName) {
|
|
|
237
265
|
scope,
|
|
238
266
|
serverName,
|
|
239
267
|
).catch(() => false);
|
|
240
|
-
const label = configured
|
|
241
|
-
? `${getHost(hostName).displayName} ${pc.dim("(already configured)")}`
|
|
242
|
-
: getHost(hostName).displayName;
|
|
243
268
|
choices.push({
|
|
244
|
-
name:
|
|
269
|
+
name: getHost(hostName).displayName,
|
|
245
270
|
value: hostName,
|
|
271
|
+
short: getHost(hostName).displayName,
|
|
272
|
+
description: hostChoiceDescription({
|
|
273
|
+
detected: detected.includes(hostName),
|
|
274
|
+
configured,
|
|
275
|
+
}),
|
|
246
276
|
checked: detected.includes(hostName),
|
|
277
|
+
disabled: configured ? "(already configured)" : false,
|
|
247
278
|
});
|
|
248
279
|
}
|
|
249
280
|
|
|
@@ -315,7 +346,53 @@ async function resolveApiKey(options, baseUrl) {
|
|
|
315
346
|
}
|
|
316
347
|
}
|
|
317
348
|
|
|
318
|
-
|
|
349
|
+
/**
|
|
350
|
+
* Classify an agent result for the human-readable MCP setup summary.
|
|
351
|
+
*
|
|
352
|
+
* The terminal outcomes are:
|
|
353
|
+
* - "failed" → explicit host-level failure (success === false).
|
|
354
|
+
* - "skipped" → the host was intentionally bypassed (skill-only host in
|
|
355
|
+
* MCP mode, or any agent result that carries success === null
|
|
356
|
+
* or status === "skipped"). Agents that fall into this
|
|
357
|
+
* bucket must NOT be rendered as failed, because the setup
|
|
358
|
+
* itself exited 0 and the user's expectation is that a
|
|
359
|
+
* green exit implies a green summary row.
|
|
360
|
+
* - "already configured" → the desired MCP entry was already on disk.
|
|
361
|
+
* - "configured (OAuth)" → oauth mode wrote a config without any
|
|
362
|
+
* Authorization header; labelling this as
|
|
363
|
+
* "API Key" would be inaccurate and would
|
|
364
|
+
* confuse users auditing the auth model.
|
|
365
|
+
* - "configured with API Key" → default MCP-mode success path, which writes
|
|
366
|
+
* a Bearer token into the host config.
|
|
367
|
+
*/
|
|
368
|
+
function classifyAgentOutcome(agentResult, { oauthMode = false } = {}) {
|
|
369
|
+
if (agentResult.success === false) {
|
|
370
|
+
return "failed";
|
|
371
|
+
}
|
|
372
|
+
if (
|
|
373
|
+
agentResult.success === null ||
|
|
374
|
+
agentResult.status === "skipped" ||
|
|
375
|
+
(Array.isArray(agentResult.skippedSteps) &&
|
|
376
|
+
(agentResult.skippedSteps.includes("skill-only-host") ||
|
|
377
|
+
agentResult.skippedSteps.includes("unsupported-host")))
|
|
378
|
+
) {
|
|
379
|
+
return "skipped";
|
|
380
|
+
}
|
|
381
|
+
const alreadyConfigured =
|
|
382
|
+
Array.isArray(agentResult.skippedSteps) &&
|
|
383
|
+
agentResult.skippedSteps.includes("already-configured");
|
|
384
|
+
if (alreadyConfigured) {
|
|
385
|
+
return "already configured";
|
|
386
|
+
}
|
|
387
|
+
return oauthMode ? "configured (OAuth)" : "configured with API Key";
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function buildSetupResultRows({
|
|
391
|
+
selectedHosts,
|
|
392
|
+
hostStates,
|
|
393
|
+
setupResult,
|
|
394
|
+
oauthMode = false,
|
|
395
|
+
}) {
|
|
319
396
|
const byAgent = new Map(
|
|
320
397
|
setupResult.agentResults.map((result) => [result.agent, result]),
|
|
321
398
|
);
|
|
@@ -331,23 +408,14 @@ function buildSetupResultRows({ selectedHosts, hostStates, setupResult }) {
|
|
|
331
408
|
};
|
|
332
409
|
}
|
|
333
410
|
|
|
334
|
-
|
|
335
|
-
return {
|
|
336
|
-
host: host.displayName,
|
|
337
|
-
status: "failed",
|
|
338
|
-
filePath: hostStates.get(hostName)?.mcpPath || "(unknown)",
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
const alreadyConfigured =
|
|
343
|
-
Array.isArray(agentResult.skippedSteps) &&
|
|
344
|
-
agentResult.skippedSteps.includes("already-configured");
|
|
345
|
-
|
|
411
|
+
const status = classifyAgentOutcome(agentResult, { oauthMode });
|
|
346
412
|
return {
|
|
347
413
|
host: host.displayName,
|
|
348
|
-
status
|
|
414
|
+
status,
|
|
349
415
|
filePath:
|
|
350
|
-
agentResult.touchedFiles[0] ||
|
|
416
|
+
agentResult.touchedFiles?.[0] ||
|
|
417
|
+
hostStates.get(hostName)?.mcpPath ||
|
|
418
|
+
"(unknown)",
|
|
351
419
|
};
|
|
352
420
|
});
|
|
353
421
|
}
|
|
@@ -386,7 +454,9 @@ function printSetupResults(
|
|
|
386
454
|
` ${pc.bold(`npx skills experimental_sync --agent ${experimentalSyncAgents[0]} -y`)}`,
|
|
387
455
|
);
|
|
388
456
|
} else if (experimentalSyncAgents.length > 1) {
|
|
389
|
-
log.plain(
|
|
457
|
+
log.plain(
|
|
458
|
+
" Optional path via skills experimental_sync for selected hosts:",
|
|
459
|
+
);
|
|
390
460
|
for (const agentName of experimentalSyncAgents) {
|
|
391
461
|
log.plain(
|
|
392
462
|
` ${pc.bold(`npx skills experimental_sync --agent ${agentName} -y`)}`,
|
|
@@ -402,6 +472,12 @@ function resolveExperimentalSyncAgentsForHosts(supportedHosts) {
|
|
|
402
472
|
const seenAgentNames = new Set();
|
|
403
473
|
|
|
404
474
|
for (const hostName of supportedHosts) {
|
|
475
|
+
// Direct-copy hosts (gemini, universal, antigravity) bypass the `skills`
|
|
476
|
+
// CLI entirely, so they have no agent name to sync with. Skip them from
|
|
477
|
+
// the experimental_sync guidance block.
|
|
478
|
+
if (isDirectCopySkillHost(hostName)) {
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
405
481
|
const agentName = resolveSkillsAgentName(hostName);
|
|
406
482
|
if (seenAgentNames.has(agentName)) {
|
|
407
483
|
continue;
|
|
@@ -522,21 +598,44 @@ export async function runMcpModeCommand(options, deps = {}) {
|
|
|
522
598
|
throw new Error(NON_INTERACTIVE_SKILL_DECISION_ERROR);
|
|
523
599
|
}
|
|
524
600
|
|
|
601
|
+
const oauthMode = options.oauth === true;
|
|
602
|
+
if (oauthMode && Object.hasOwn(options, "apiKey")) {
|
|
603
|
+
throw new SetupModeUsageError(
|
|
604
|
+
"--api-key and --oauth are mutually exclusive: choose one.",
|
|
605
|
+
);
|
|
606
|
+
}
|
|
607
|
+
|
|
525
608
|
const scope = options.project ? "project" : "global";
|
|
526
|
-
const baseUrl = normalizeBaseUrl(
|
|
609
|
+
const baseUrl = normalizeBaseUrl(
|
|
610
|
+
resolveSetupBaseUrl({ explicitBaseUrl: options.baseUrl }),
|
|
611
|
+
);
|
|
527
612
|
const serverUrl = `${baseUrl}/mcp-server`;
|
|
528
613
|
const serverName = normalizeServerName(options.name || SERVER_NAME);
|
|
529
|
-
const
|
|
614
|
+
const resolveHostsForSetup =
|
|
615
|
+
deps.resolveHostsForSetup ||
|
|
616
|
+
(async ({
|
|
617
|
+
options: hostOptions,
|
|
618
|
+
scope: hostScope,
|
|
619
|
+
serverName: hostServerName,
|
|
620
|
+
allowPrompt,
|
|
621
|
+
}) =>
|
|
622
|
+
await resolveHosts(hostOptions, hostScope, hostServerName, allowPrompt));
|
|
623
|
+
const hosts = await resolveHostsForSetup({
|
|
530
624
|
options,
|
|
531
625
|
scope,
|
|
532
626
|
serverName,
|
|
533
|
-
|
|
534
|
-
|
|
627
|
+
// `--install-skill` is an explicit refresh request. Keep the advertised
|
|
628
|
+
// no-host update command prompt-free on detected hosts; `--skip-skill`
|
|
629
|
+
// remains guided unless host flags or --yes are provided.
|
|
630
|
+
allowPrompt: skillDecisionMode !== "install",
|
|
631
|
+
});
|
|
632
|
+
recordResolvedHosts(hosts);
|
|
535
633
|
if (hosts.length === 0) {
|
|
536
634
|
return { exitCode: 0 };
|
|
537
635
|
}
|
|
538
636
|
|
|
539
|
-
const { supportedHosts, unsupportedHosts } =
|
|
637
|
+
const { supportedHosts, unsupportedHosts } =
|
|
638
|
+
partitionInstallSkillHosts(hosts);
|
|
540
639
|
const packageRoot = resolvePackageRoot();
|
|
541
640
|
const bundledSkillNames =
|
|
542
641
|
skillDecisionMode === "skip" || supportedHosts.length === 0
|
|
@@ -558,7 +657,9 @@ export async function runMcpModeCommand(options, deps = {}) {
|
|
|
558
657
|
supportedHosts.length > 0 &&
|
|
559
658
|
bundledSkillNames.length === 0
|
|
560
659
|
) {
|
|
561
|
-
throw new Error(
|
|
660
|
+
throw new Error(
|
|
661
|
+
`No bundled skills found under ${path.join(packageRoot, "skills")}.`,
|
|
662
|
+
);
|
|
562
663
|
}
|
|
563
664
|
|
|
564
665
|
const {
|
|
@@ -682,8 +783,7 @@ export async function runMcpModeCommand(options, deps = {}) {
|
|
|
682
783
|
let apiKey = null;
|
|
683
784
|
const explicitApiKeyProvided = Object.hasOwn(options, "apiKey");
|
|
684
785
|
const shouldResolveApiKey =
|
|
685
|
-
needsSetupHosts.length > 0 ||
|
|
686
|
-
explicitApiKeyProvided;
|
|
786
|
+
!oauthMode && (needsSetupHosts.length > 0 || explicitApiKeyProvided);
|
|
687
787
|
if (shouldResolveApiKey) {
|
|
688
788
|
apiKey = await resolveApiKey(options, baseUrl);
|
|
689
789
|
if (!apiKey) {
|
|
@@ -714,6 +814,11 @@ export async function runMcpModeCommand(options, deps = {}) {
|
|
|
714
814
|
serverName,
|
|
715
815
|
serverUrl,
|
|
716
816
|
apiKey,
|
|
817
|
+
// Tell the writers to reconcile auth-mode mismatches (Authorization
|
|
818
|
+
// header added/removed) only when the user explicitly set `--oauth` or
|
|
819
|
+
// `--api-key`. Without that, a passive rerun must stay idempotent and
|
|
820
|
+
// preserve the existing bearer header on disk rather than stripping it.
|
|
821
|
+
enforceAuthMode: oauthMode || explicitApiKeyProvided,
|
|
717
822
|
detectPriorMode: async () => ({
|
|
718
823
|
priorMode: null,
|
|
719
824
|
affectedHosts: [],
|
|
@@ -723,7 +828,9 @@ export async function runMcpModeCommand(options, deps = {}) {
|
|
|
723
828
|
});
|
|
724
829
|
if (reconciled.length > 0) {
|
|
725
830
|
setupResult.reconciled = [
|
|
726
|
-
...(Array.isArray(setupResult.reconciled)
|
|
831
|
+
...(Array.isArray(setupResult.reconciled)
|
|
832
|
+
? setupResult.reconciled
|
|
833
|
+
: []),
|
|
727
834
|
...reconciled,
|
|
728
835
|
];
|
|
729
836
|
}
|
|
@@ -749,6 +856,7 @@ export async function runMcpModeCommand(options, deps = {}) {
|
|
|
749
856
|
selectedHosts: hosts,
|
|
750
857
|
hostStates,
|
|
751
858
|
setupResult,
|
|
859
|
+
oauthMode,
|
|
752
860
|
});
|
|
753
861
|
|
|
754
862
|
if (skillDecisionMode !== "guided") {
|
package/src/setup/modes/mcp.mjs
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getHost as defaultGetHost,
|
|
5
|
+
isSkillOnlyHost,
|
|
6
|
+
} from "../../agents.mjs";
|
|
4
7
|
import { SUPPORTED_INSTALL_SKILL_HOSTS } from "../../skill-installer.mjs";
|
|
5
8
|
import { resolveMcpPath as defaultResolveMcpPath } from "../../mcp-writer.mjs";
|
|
6
9
|
import { SetupModeUsageError } from "../mode.mjs";
|
|
@@ -38,6 +41,12 @@ export async function runMcpSetupMode({
|
|
|
38
41
|
serverName,
|
|
39
42
|
serverUrl,
|
|
40
43
|
apiKey,
|
|
44
|
+
// `enforceAuthMode` is the "explicit auth intent" signal forwarded by the
|
|
45
|
+
// CLI layer (true when `--oauth` is set or `--api-key` was passed). When
|
|
46
|
+
// true, writers reconcile a mismatched Authorization header on an existing
|
|
47
|
+
// entry; when false, they stay idempotent by name so a benign rerun does
|
|
48
|
+
// not wipe the previously-minted bearer key.
|
|
49
|
+
enforceAuthMode = false,
|
|
41
50
|
supportedCliHosts = SUPPORTED_INSTALL_SKILL_HOSTS,
|
|
42
51
|
detectPriorMode = detectPriorModeForSetup,
|
|
43
52
|
reconcilePriorMode = null,
|
|
@@ -116,6 +125,19 @@ export async function runMcpSetupMode({
|
|
|
116
125
|
let host = null;
|
|
117
126
|
try {
|
|
118
127
|
host = getHost(hostName);
|
|
128
|
+
if (isSkillOnlyHost(host)) {
|
|
129
|
+
agentResults.push({
|
|
130
|
+
agent: hostName,
|
|
131
|
+
success: null,
|
|
132
|
+
status: "skipped",
|
|
133
|
+
touchedFiles: [],
|
|
134
|
+
skippedSteps: ["skill-only-host"],
|
|
135
|
+
warnings: [
|
|
136
|
+
`${host.displayName} is a skill-only host; MCP config write skipped.`,
|
|
137
|
+
],
|
|
138
|
+
});
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
119
141
|
const candidates = resolveCandidatesForScope(host, scope, cwd);
|
|
120
142
|
const filePath = await resolveMcpPath(candidates);
|
|
121
143
|
const entry = host.mcp.buildEntry({ serverUrl, apiKey });
|
|
@@ -127,6 +149,7 @@ export async function runMcpSetupMode({
|
|
|
127
149
|
configKey: host.mcp.configKey,
|
|
128
150
|
serverName,
|
|
129
151
|
entry,
|
|
152
|
+
enforceAuthMode,
|
|
130
153
|
});
|
|
131
154
|
} else if (host.mcp.configType === "yaml") {
|
|
132
155
|
patchResult = await patchYamlServer({
|
|
@@ -134,6 +157,7 @@ export async function runMcpSetupMode({
|
|
|
134
157
|
configKey: host.mcp.configKey,
|
|
135
158
|
serverName,
|
|
136
159
|
entry,
|
|
160
|
+
enforceAuthMode,
|
|
137
161
|
});
|
|
138
162
|
} else {
|
|
139
163
|
patchResult = await patchJsonServer({
|
|
@@ -141,6 +165,7 @@ export async function runMcpSetupMode({
|
|
|
141
165
|
configKey: host.mcp.configKey,
|
|
142
166
|
serverName,
|
|
143
167
|
entry,
|
|
168
|
+
enforceAuthMode,
|
|
144
169
|
});
|
|
145
170
|
}
|
|
146
171
|
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { writeFileSync } from "node:fs";
|
|
2
|
+
|
|
3
|
+
function resolveRecordPath(explicitPath, envName) {
|
|
4
|
+
return explicitPath || process.env[envName] || "";
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function recordResolvedMode(mode, deps = {}) {
|
|
8
|
+
const resolvedModePath = resolveRecordPath(
|
|
9
|
+
deps.resolvedModePath,
|
|
10
|
+
"FLYWHEEL_SETUP_RESOLVED_MODE_FILE",
|
|
11
|
+
);
|
|
12
|
+
if (resolvedModePath) {
|
|
13
|
+
writeFileSync(resolvedModePath, `${mode}\n`, "utf8");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function recordResolvedHosts(hosts, deps = {}) {
|
|
18
|
+
const resolvedHostsPath = resolveRecordPath(
|
|
19
|
+
deps.resolvedHostsPath,
|
|
20
|
+
"FLYWHEEL_SETUP_RESOLVED_HOSTS_FILE",
|
|
21
|
+
);
|
|
22
|
+
if (resolvedHostsPath) {
|
|
23
|
+
writeFileSync(resolvedHostsPath, `${hosts.join("\n")}\n`, "utf8");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { access, readFile } from "node:fs/promises";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getHost as defaultGetHost,
|
|
6
|
+
isSkillOnlyHost,
|
|
7
|
+
SKILL_ONLY_HOST_NAMES,
|
|
8
|
+
} from "../../agents.mjs";
|
|
5
9
|
import {
|
|
6
10
|
parseTomlSectionName,
|
|
7
11
|
parseTomlStringValue,
|
|
12
|
+
readEntryServerUrl,
|
|
8
13
|
readJsonConfig as defaultReadJsonConfig,
|
|
9
14
|
readNamedConfigEntry as defaultReadNamedConfigEntry,
|
|
10
15
|
readTomlServerEntry as defaultReadTomlServerEntry,
|
|
@@ -15,6 +20,7 @@ import {
|
|
|
15
20
|
listBundledSkills as defaultListBundledSkills,
|
|
16
21
|
resolveInstalledSkillDir as defaultResolveInstalledSkillDir,
|
|
17
22
|
resolvePackageRoot as defaultResolvePackageRoot,
|
|
23
|
+
resolveFlywheelInstalledMarkerPath,
|
|
18
24
|
SUPPORTED_INSTALL_SKILL_HOSTS,
|
|
19
25
|
} from "../../skill-installer.mjs";
|
|
20
26
|
|
|
@@ -70,7 +76,8 @@ async function hasMatchingMcpEntry({
|
|
|
70
76
|
? await readYamlConfig(filePath)
|
|
71
77
|
: await readJsonConfig(filePath);
|
|
72
78
|
const entry = readNamedConfigEntry(config, host.mcp.configKey, serverName);
|
|
73
|
-
|
|
79
|
+
const entryUrl = readEntryServerUrl(entry);
|
|
80
|
+
return entryUrl !== null && entryUrl === serverUrl;
|
|
74
81
|
} catch {
|
|
75
82
|
return false;
|
|
76
83
|
}
|
|
@@ -87,8 +94,8 @@ function originOf(url) {
|
|
|
87
94
|
// A URL is treated as a Flywheel MCP endpoint only when both its pathname is
|
|
88
95
|
// `/mcp-server` AND its origin is Flywheel-identifying. "Flywheel-identifying"
|
|
89
96
|
// means either (a) the hostname contains the substring "flywheel" (covers
|
|
90
|
-
// `flywheel.paradigma.inc`,
|
|
91
|
-
// `flywheel.<tenant
|
|
97
|
+
// the canonical `flywheel.paradigma.inc`, subdomain variants, and self-hosted
|
|
98
|
+
// `flywheel.<tenant>.*`) or (b) the URL's full origin (scheme + host +
|
|
92
99
|
// port) matches the target base URL's origin, so dev installs against
|
|
93
100
|
// `http://localhost:8000` and self-hosted tenants still round-trip. Comparing
|
|
94
101
|
// full origin rather than hostname alone is load-bearing on multi-tenant
|
|
@@ -215,13 +222,8 @@ export async function findFlywheelMcpEntryNames({
|
|
|
215
222
|
}
|
|
216
223
|
const matches = [];
|
|
217
224
|
for (const [entryName, entry] of Object.entries(section)) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
typeof entry === "object" &&
|
|
221
|
-
!Array.isArray(entry) &&
|
|
222
|
-
typeof entry.url === "string" &&
|
|
223
|
-
isFlywheelMcpUrl(entry.url, targetOrigin)
|
|
224
|
-
) {
|
|
225
|
+
const entryUrl = readEntryServerUrl(entry);
|
|
226
|
+
if (entryUrl !== null && isFlywheelMcpUrl(entryUrl, targetOrigin)) {
|
|
225
227
|
matches.push(entryName);
|
|
226
228
|
}
|
|
227
229
|
}
|
|
@@ -231,6 +233,90 @@ export async function findFlywheelMcpEntryNames({
|
|
|
231
233
|
}
|
|
232
234
|
}
|
|
233
235
|
|
|
236
|
+
/**
|
|
237
|
+
* Determine whether a truly skill-only host's ownership marker is present at
|
|
238
|
+
* the skills-root that `hostName` would write into. The two destination
|
|
239
|
+
* roots can coincide on shared paths — e.g. `--universal` writes into
|
|
240
|
+
* `.agents/skills/` which is also where `--codex` / `--opencode` / `--cursor`
|
|
241
|
+
* land. When a skill-only host marker is present there, any skill artifacts
|
|
242
|
+
* at that root are attributable to the skill-only host, not to `hostName`.
|
|
243
|
+
*
|
|
244
|
+
* This MUST iterate `SKILL_ONLY_HOST_NAMES`, not the wider direct-copy set:
|
|
245
|
+
* Gemini CLI also uses the direct-copy skill path but is MCP-capable, so
|
|
246
|
+
* attributing its own `.gemini/skills/` artifacts to itself via this helper
|
|
247
|
+
* would silently suppress the legitimate cross-mode conflict when the user
|
|
248
|
+
* transitions `--mode cli --gemini` → `--mode mcp --gemini`.
|
|
249
|
+
*/
|
|
250
|
+
async function skillsRootClaimedBySkillOnlyHost({
|
|
251
|
+
hostName,
|
|
252
|
+
scope,
|
|
253
|
+
cwd,
|
|
254
|
+
skillNames,
|
|
255
|
+
resolveInstalledSkillDir,
|
|
256
|
+
}) {
|
|
257
|
+
if (!Array.isArray(skillNames) || skillNames.length === 0) {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
const candidateSkillPath = resolveInstalledSkillDir(
|
|
261
|
+
cwd,
|
|
262
|
+
hostName,
|
|
263
|
+
scope,
|
|
264
|
+
skillNames[0],
|
|
265
|
+
);
|
|
266
|
+
const candidateSkillsRoot = path.dirname(candidateSkillPath);
|
|
267
|
+
|
|
268
|
+
// Case where the target host has its own install marker: the artifacts
|
|
269
|
+
// are co-owned — the skill-only marker alone no longer fully explains the
|
|
270
|
+
// skill dir contents, so the suppression must NOT fire. This is the
|
|
271
|
+
// difference between:
|
|
272
|
+
// `setup --mode cli --universal` → only universal marker
|
|
273
|
+
// `setup --mode cli --universal --codex` → universal + codex markers
|
|
274
|
+
// In the first case, codex's MCP setup is a fresh install and no conflict
|
|
275
|
+
// should be raised. In the second case, codex had a real CLI install of
|
|
276
|
+
// its own and the cross-mode conflict must fire.
|
|
277
|
+
try {
|
|
278
|
+
const selfMarkerPath = resolveFlywheelInstalledMarkerPath(cwd, hostName, scope);
|
|
279
|
+
if (await pathExists(selfMarkerPath)) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
} catch {
|
|
283
|
+
// hostName isn't registered with the flywheel skill installer; nothing
|
|
284
|
+
// to subtract — fall through to the skill-only scan below.
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Note: there is no reliable post-hoc signal for a CLI install of an
|
|
288
|
+
// MCP-capable host that pre-dates the per-host ownership marker scheme.
|
|
289
|
+
// `skills-lock.json` would seem like one, but its entries are keyed by
|
|
290
|
+
// skill name (not by agent) and are left behind by BOTH CLI-mode installs
|
|
291
|
+
// and MCP-mode installs with `--install-skill`, including stale entries
|
|
292
|
+
// that survive a host uninstall. Using the lock as a legacy fallback
|
|
293
|
+
// therefore false-positives on the common flow "MCP install → uninstall →
|
|
294
|
+
// universal install → MCP re-install", so we do not treat it as a cross-
|
|
295
|
+
// mode conflict signal. The legacy marker-less upgrade cohort (users on a
|
|
296
|
+
// release before ownership markers existed) can pass `--force` or re-run
|
|
297
|
+
// their CLI setup to acquire the marker; from there everything converges
|
|
298
|
+
// on the accurate per-host signal.
|
|
299
|
+
for (const skillOnlyHostName of SKILL_ONLY_HOST_NAMES) {
|
|
300
|
+
// Skill-only hosts whose destination path cannot overlap this host's
|
|
301
|
+
// path cannot explain any artifact found here. Only markers at the same
|
|
302
|
+
// skills-root are load-bearing.
|
|
303
|
+
let markerPath;
|
|
304
|
+
try {
|
|
305
|
+
markerPath = resolveFlywheelInstalledMarkerPath(cwd, skillOnlyHostName, scope);
|
|
306
|
+
} catch {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
if (path.dirname(markerPath) !== candidateSkillsRoot) {
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
// eslint-disable-next-line no-await-in-loop
|
|
313
|
+
if (await pathExists(markerPath)) {
|
|
314
|
+
return true;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return false;
|
|
318
|
+
}
|
|
319
|
+
|
|
234
320
|
async function hostHasBundledSkillArtifacts({
|
|
235
321
|
hostName,
|
|
236
322
|
scope,
|
|
@@ -238,15 +324,32 @@ async function hostHasBundledSkillArtifacts({
|
|
|
238
324
|
skillNames,
|
|
239
325
|
resolveInstalledSkillDir,
|
|
240
326
|
}) {
|
|
327
|
+
let foundAny = false;
|
|
241
328
|
for (const skillName of skillNames) {
|
|
242
329
|
// eslint-disable-next-line no-await-in-loop
|
|
243
330
|
const skillPath = resolveInstalledSkillDir(cwd, hostName, scope, skillName);
|
|
244
331
|
// eslint-disable-next-line no-await-in-loop
|
|
245
332
|
if (await pathExists(skillPath)) {
|
|
246
|
-
|
|
333
|
+
foundAny = true;
|
|
334
|
+
break;
|
|
247
335
|
}
|
|
248
336
|
}
|
|
249
|
-
|
|
337
|
+
if (!foundAny) {
|
|
338
|
+
return false;
|
|
339
|
+
}
|
|
340
|
+
// Found skill artifacts at this host's path. Attribute them to a
|
|
341
|
+
// skill-only host that explicitly claims the same skills-root (via its
|
|
342
|
+
// installation marker) rather than to this host — otherwise an MCP host
|
|
343
|
+
// sharing `.agents/skills/` with `--universal` would be misreported as
|
|
344
|
+
// having a prior CLI-mode install of its own.
|
|
345
|
+
const claimed = await skillsRootClaimedBySkillOnlyHost({
|
|
346
|
+
hostName,
|
|
347
|
+
scope,
|
|
348
|
+
cwd,
|
|
349
|
+
skillNames,
|
|
350
|
+
resolveInstalledSkillDir,
|
|
351
|
+
});
|
|
352
|
+
return !claimed;
|
|
250
353
|
}
|
|
251
354
|
|
|
252
355
|
export function formatPriorModeConflictError({
|
|
@@ -363,7 +466,23 @@ export async function detectPriorModeForSetup({
|
|
|
363
466
|
};
|
|
364
467
|
}
|
|
365
468
|
|
|
366
|
-
|
|
469
|
+
// Skill-only hosts (universal, antigravity) never write an MCP config, so
|
|
470
|
+
// every one of their installs — regardless of whether it was invoked with
|
|
471
|
+
// `--mode cli` or `--mode mcp --install-skill` — leaves the same on-disk
|
|
472
|
+
// shape: bundled skill dirs and nothing else. Treating a lingering skill
|
|
473
|
+
// dir under such a host as "a prior CLI install" would raise a bogus
|
|
474
|
+
// cross-mode conflict on every rerun of the same command. Filter them
|
|
475
|
+
// out of the CLI candidate universe up front so a subsequent `--mode mcp`
|
|
476
|
+
// pass stays idempotent.
|
|
477
|
+
const supportedHostSet = new Set(
|
|
478
|
+
unique(supportedCliHosts).filter((hostName) => {
|
|
479
|
+
try {
|
|
480
|
+
return !isSkillOnlyHost(getHost(hostName));
|
|
481
|
+
} catch {
|
|
482
|
+
return true;
|
|
483
|
+
}
|
|
484
|
+
}),
|
|
485
|
+
);
|
|
367
486
|
const mcpTouchedHosts = new Set([
|
|
368
487
|
...exactMatchHosts,
|
|
369
488
|
...flywheelEntryNamesByHost.keys(),
|
package/src/setup-auth.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { SetupInputUsageError } from "./setup/mode.mjs";
|
|
|
7
7
|
const DEFAULT_AUTH_TIMEOUT_MS = 5 * 60 * 1000;
|
|
8
8
|
const MIN_POLL_DELAY_MS = 1000;
|
|
9
9
|
const MAX_POLL_DELAY_MS = 10_000;
|
|
10
|
+
const SETUP_DEVICE_API_PREFIX = "/api/v1/auth/mcp-api-keys/setup-device";
|
|
10
11
|
|
|
11
12
|
function openUrlInBrowser(url) {
|
|
12
13
|
const platform = process.platform;
|
|
@@ -146,7 +147,7 @@ async function startSetupDeviceSession({
|
|
|
146
147
|
keyName,
|
|
147
148
|
verificationBaseUrl,
|
|
148
149
|
}) {
|
|
149
|
-
const startUrl = new URL(
|
|
150
|
+
const startUrl = new URL(`${SETUP_DEVICE_API_PREFIX}/start`, baseUrl);
|
|
150
151
|
const response = await fetch(startUrl, {
|
|
151
152
|
method: "POST",
|
|
152
153
|
headers: {
|
|
@@ -194,7 +195,7 @@ async function startSetupDeviceSession({
|
|
|
194
195
|
}
|
|
195
196
|
|
|
196
197
|
async function pollSetupDeviceSession({ baseUrl, userCode, deviceCode }) {
|
|
197
|
-
const pollUrl = new URL(
|
|
198
|
+
const pollUrl = new URL(`${SETUP_DEVICE_API_PREFIX}/poll`, baseUrl);
|
|
198
199
|
const response = await fetch(pollUrl, {
|
|
199
200
|
method: "POST",
|
|
200
201
|
headers: {
|