@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.
Files changed (263) hide show
  1. package/README.md +149 -17
  2. package/package.json +4 -2
  3. package/skills/flywheel/SKILL.md +4 -3
  4. package/skills/flywheel/getting-started/flywheel-quickstart.md +4 -4
  5. package/skills/flywheel/references/flywheel-cli-tool-map.md +47 -35
  6. package/skills/flywheel/references/flywheel-mcp-tool-map.md +16 -5
  7. package/skills/flywheel/setting-up-flywheel/claude-code-cli-installation.md +3 -3
  8. package/skills/flywheel/setting-up-flywheel/codex-cli-installation.md +3 -3
  9. package/skills/flywheel/setting-up-flywheel/installation-overview.md +9 -8
  10. package/skills/flywheel/setting-up-flywheel/other-hosts-installation.md +1 -1
  11. package/skills/flywheel/setting-up-flywheel/updating-flywheel-mcp.md +4 -4
  12. package/skills/flywheel-auto/SKILL.md +4 -3
  13. package/skills/flywheel-auto/references/flywheel-cli-tool-map.md +37 -35
  14. package/skills/flywheel-auto/references/flywheel-mcp-tool-map.md +4 -4
  15. package/skills/flywheel-lookahead/SKILL.md +1 -1
  16. package/skills/flywheel-lookahead/references/flywheel-cli-tool-map.md +37 -35
  17. package/skills/flywheel-lookahead/references/flywheel-mcp-tool-map.md +4 -4
  18. package/skills/flywheel-prove/SKILL.md +1 -1
  19. package/skills/flywheel-reproduce/SKILL.md +4 -3
  20. package/skills/flywheel-reproduce/references/flywheel-cli-tool-map.md +37 -35
  21. package/skills/flywheel-reproduce/references/flywheel-mcp-tool-map.md +4 -4
  22. package/skills/flywheel-to-graph/SKILL.md +1 -1
  23. package/skills/flywheel-to-graph/references/flywheel-cli-tool-map.md +37 -35
  24. package/skills/flywheel-to-graph/references/flywheel-mcp-tool-map.md +4 -4
  25. package/skills/flywheel-tree/SKILL.md +1 -1
  26. package/src/agents.mjs +114 -48
  27. package/src/cli.mjs +373 -56
  28. package/src/mcp-writer.mjs +190 -17
  29. package/src/runtime/required-runtime-commands.json +19 -4
  30. package/src/runtime/vendor/flywheel-cli-dist/auth/login.d.ts +1 -0
  31. package/src/runtime/vendor/flywheel-cli-dist/auth/login.js +3 -6
  32. package/src/runtime/vendor/flywheel-cli-dist/auth/login.js.map +1 -1
  33. package/src/runtime/vendor/flywheel-cli-dist/auth/profiles.d.ts +1 -0
  34. package/src/runtime/vendor/flywheel-cli-dist/auth/profiles.js +1 -1
  35. package/src/runtime/vendor/flywheel-cli-dist/auth/profiles.js.map +1 -1
  36. package/src/runtime/vendor/flywheel-cli-dist/commands/_admin-auth.d.ts +27 -0
  37. package/src/runtime/vendor/flywheel-cli-dist/commands/_admin-auth.js +54 -0
  38. package/src/runtime/vendor/flywheel-cli-dist/commands/_admin-auth.js.map +1 -0
  39. package/src/runtime/vendor/flywheel-cli-dist/commands/_artifacts-upload-helpers.d.ts +1 -1
  40. package/src/runtime/vendor/flywheel-cli-dist/commands/_artifacts-upload-helpers.js +6 -5
  41. package/src/runtime/vendor/flywheel-cli-dist/commands/_artifacts-upload-helpers.js.map +1 -1
  42. package/src/runtime/vendor/flywheel-cli-dist/commands/_browser-handoff.d.ts +21 -0
  43. package/src/runtime/vendor/flywheel-cli-dist/commands/_browser-handoff.js +51 -0
  44. package/src/runtime/vendor/flywheel-cli-dist/commands/_browser-handoff.js.map +1 -0
  45. package/src/runtime/vendor/flywheel-cli-dist/commands/_open-url.d.ts +1 -1
  46. package/src/runtime/vendor/flywheel-cli-dist/commands/_open-url.js +6 -3
  47. package/src/runtime/vendor/flywheel-cli-dist/commands/_open-url.js.map +1 -1
  48. package/src/runtime/vendor/flywheel-cli-dist/commands/_secret-param.d.ts +7 -0
  49. package/src/runtime/vendor/flywheel-cli-dist/commands/_secret-param.js +18 -0
  50. package/src/runtime/vendor/flywheel-cli-dist/commands/_secret-param.js.map +1 -0
  51. package/src/runtime/vendor/flywheel-cli-dist/commands/_stream-file-out.d.ts +39 -0
  52. package/src/runtime/vendor/flywheel-cli-dist/commands/_stream-file-out.js +72 -0
  53. package/src/runtime/vendor/flywheel-cli-dist/commands/_stream-file-out.js.map +1 -0
  54. package/src/runtime/vendor/flywheel-cli-dist/commands/account-detach.js +2 -0
  55. package/src/runtime/vendor/flywheel-cli-dist/commands/account-detach.js.map +1 -1
  56. package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-add.js +2 -0
  57. package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-add.js.map +1 -1
  58. package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-remove.js +2 -0
  59. package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-remove.js.map +1 -1
  60. package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-set-primary.js +2 -0
  61. package/src/runtime/vendor/flywheel-cli-dist/commands/account-emails-set-primary.js.map +1 -1
  62. package/src/runtime/vendor/flywheel-cli-dist/commands/account-get.d.ts +2 -1
  63. package/src/runtime/vendor/flywheel-cli-dist/commands/account-get.js +6 -1
  64. package/src/runtime/vendor/flywheel-cli-dist/commands/account-get.js.map +1 -1
  65. package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-preview.js +2 -0
  66. package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-preview.js.map +1 -1
  67. package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-proof.js +2 -0
  68. package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge-proof.js.map +1 -1
  69. package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge.js +2 -0
  70. package/src/runtime/vendor/flywheel-cli-dist/commands/account-merge.js.map +1 -1
  71. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-get.d.ts +2 -0
  72. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-get.js +11 -0
  73. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-get.js.map +1 -0
  74. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-set.d.ts +2 -0
  75. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-set.js +60 -0
  76. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-compute-policy-set.js.map +1 -0
  77. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export-stream.d.ts +2 -0
  78. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export-stream.js +115 -0
  79. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export-stream.js.map +1 -0
  80. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export.d.ts +2 -0
  81. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export.js +12 -0
  82. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-export.js.map +1 -0
  83. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-list.d.ts +4 -0
  84. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-list.js +39 -0
  85. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-graphs-list.js.map +1 -0
  86. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-nodes-audit-list.d.ts +2 -0
  87. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-nodes-audit-list.js +15 -0
  88. package/src/runtime/vendor/flywheel-cli-dist/commands/admin-nodes-audit-list.js.map +1 -0
  89. package/src/runtime/vendor/flywheel-cli-dist/commands/api-keys-list.d.ts +18 -1
  90. package/src/runtime/vendor/flywheel-cli-dist/commands/api-keys-list.js +38 -5
  91. package/src/runtime/vendor/flywheel-cli-dist/commands/api-keys-list.js.map +1 -1
  92. package/src/runtime/vendor/flywheel-cli-dist/commands/artifacts-delete.js +1 -1
  93. package/src/runtime/vendor/flywheel-cli-dist/commands/artifacts-delete.js.map +1 -1
  94. package/src/runtime/vendor/flywheel-cli-dist/commands/auth-mode.d.ts +4 -0
  95. package/src/runtime/vendor/flywheel-cli-dist/commands/auth-mode.js +42 -0
  96. package/src/runtime/vendor/flywheel-cli-dist/commands/auth-mode.js.map +1 -0
  97. package/src/runtime/vendor/flywheel-cli-dist/commands/auth-status.js +15 -1
  98. package/src/runtime/vendor/flywheel-cli-dist/commands/auth-status.js.map +1 -1
  99. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-list.js +8 -2
  100. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-list.js.map +1 -1
  101. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-request-approval.js +6 -1
  102. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-grants-request-approval.js.map +1 -1
  103. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-release-all.js +18 -7
  104. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-release-all.js.map +1 -1
  105. package/src/runtime/vendor/flywheel-cli-dist/commands/credits-billing-portal.js +8 -4
  106. package/src/runtime/vendor/flywheel-cli-dist/commands/credits-billing-portal.js.map +1 -1
  107. package/src/runtime/vendor/flywheel-cli-dist/commands/credits-purchase.js +8 -4
  108. package/src/runtime/vendor/flywheel-cli-dist/commands/credits-purchase.js.map +1 -1
  109. package/src/runtime/vendor/flywheel-cli-dist/commands/credits-subscribe.js +8 -4
  110. package/src/runtime/vendor/flywheel-cli-dist/commands/credits-subscribe.js.map +1 -1
  111. package/src/runtime/vendor/flywheel-cli-dist/commands/destructive-confirmation.d.ts +2 -0
  112. package/src/runtime/vendor/flywheel-cli-dist/commands/destructive-confirmation.js +7 -0
  113. package/src/runtime/vendor/flywheel-cli-dist/commands/destructive-confirmation.js.map +1 -0
  114. package/src/runtime/vendor/flywheel-cli-dist/commands/enums.d.ts +8 -0
  115. package/src/runtime/vendor/flywheel-cli-dist/commands/enums.js +4 -0
  116. package/src/runtime/vendor/flywheel-cli-dist/commands/enums.js.map +1 -1
  117. package/src/runtime/vendor/flywheel-cli-dist/commands/env.d.ts +0 -4
  118. package/src/runtime/vendor/flywheel-cli-dist/commands/env.js +7 -12
  119. package/src/runtime/vendor/flywheel-cli-dist/commands/env.js.map +1 -1
  120. package/src/runtime/vendor/flywheel-cli-dist/commands/export-history.js +42 -30
  121. package/src/runtime/vendor/flywheel-cli-dist/commands/export-history.js.map +1 -1
  122. package/src/runtime/vendor/flywheel-cli-dist/commands/export-subgraph.js +12 -4
  123. package/src/runtime/vendor/flywheel-cli-dist/commands/export-subgraph.js.map +1 -1
  124. package/src/runtime/vendor/flywheel-cli-dist/commands/github-link.js +9 -14
  125. package/src/runtime/vendor/flywheel-cli-dist/commands/github-link.js.map +1 -1
  126. package/src/runtime/vendor/flywheel-cli-dist/commands/help-format.d.ts +31 -0
  127. package/src/runtime/vendor/flywheel-cli-dist/commands/help-format.js +69 -0
  128. package/src/runtime/vendor/flywheel-cli-dist/commands/help-format.js.map +1 -0
  129. package/src/runtime/vendor/flywheel-cli-dist/commands/help.d.ts +6 -1
  130. package/src/runtime/vendor/flywheel-cli-dist/commands/help.js +226 -124
  131. package/src/runtime/vendor/flywheel-cli-dist/commands/help.js.map +1 -1
  132. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-create.d.ts +2 -0
  133. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-create.js +25 -0
  134. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-create.js.map +1 -0
  135. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-delete.d.ts +1 -0
  136. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-delete.js +6 -0
  137. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-delete.js.map +1 -0
  138. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-list.d.ts +2 -0
  139. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-list.js +10 -0
  140. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-list.js.map +1 -0
  141. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-runs-list.d.ts +2 -0
  142. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-runs-list.js +15 -0
  143. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-runs-list.js.map +1 -0
  144. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-create.d.ts +2 -0
  145. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-create.js +8 -0
  146. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-create.js.map +1 -0
  147. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-delete.d.ts +1 -0
  148. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-delete.js +6 -0
  149. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-delete.js.map +1 -0
  150. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-list.d.ts +1 -0
  151. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-list.js +6 -0
  152. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-list.js.map +1 -0
  153. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-update.d.ts +2 -0
  154. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-update.js +8 -0
  155. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-secrets-update.js.map +1 -0
  156. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-set-enabled.d.ts +2 -0
  157. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-set-enabled.js +8 -0
  158. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-set-enabled.js.map +1 -0
  159. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-update.d.ts +2 -0
  160. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-update.js +29 -0
  161. package/src/runtime/vendor/flywheel-cli-dist/commands/hooks-update.js.map +1 -0
  162. package/src/runtime/vendor/flywheel-cli-dist/commands/index.js +36 -6
  163. package/src/runtime/vendor/flywheel-cli-dist/commands/index.js.map +1 -1
  164. package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-huggingface-set.js +7 -3
  165. package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-huggingface-set.js.map +1 -1
  166. package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-wandb-set.js +6 -2
  167. package/src/runtime/vendor/flywheel-cli-dist/commands/integrations-wandb-set.js.map +1 -1
  168. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-add-parent.js +6 -1
  169. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-add-parent.js.map +1 -1
  170. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete-bulk.js +2 -0
  171. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete-bulk.js.map +1 -1
  172. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete.js +2 -0
  173. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-delete.js.map +1 -1
  174. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-remove-parent.js +8 -1
  175. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-remove-parent.js.map +1 -1
  176. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-resolve-slug.js +55 -2
  177. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-resolve-slug.js.map +1 -1
  178. package/src/runtime/vendor/flywheel-cli-dist/commands/profile-list.js +13 -1
  179. package/src/runtime/vendor/flywheel-cli-dist/commands/profile-list.js.map +1 -1
  180. package/src/runtime/vendor/flywheel-cli-dist/commands/profile-set.js +4 -2
  181. package/src/runtime/vendor/flywheel-cli-dist/commands/profile-set.js.map +1 -1
  182. package/src/runtime/vendor/flywheel-cli-dist/commands/profile-show.js +16 -1
  183. package/src/runtime/vendor/flywheel-cli-dist/commands/profile-show.js.map +1 -1
  184. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/account.js +8 -7
  185. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/account.js.map +1 -1
  186. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/admin.d.ts +8 -0
  187. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/admin.js +131 -0
  188. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/admin.js.map +1 -0
  189. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/api-keys.js +8 -2
  190. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/api-keys.js.map +1 -1
  191. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/approval.js +29 -1
  192. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/approval.js.map +1 -1
  193. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/artifacts.js +13 -1
  194. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/artifacts.js.map +1 -1
  195. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/auth.js +2 -2
  196. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/auth.js.map +1 -1
  197. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/budgets.js +11 -2
  198. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/budgets.js.map +1 -1
  199. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/compute.js +2 -2
  200. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/compute.js.map +1 -1
  201. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/credits.js +8 -6
  202. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/credits.js.map +1 -1
  203. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/env.js +7 -5
  204. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/env.js.map +1 -1
  205. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/github.js +6 -14
  206. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/github.js.map +1 -1
  207. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/hooks.d.ts +2 -0
  208. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/hooks.js +312 -0
  209. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/hooks.js.map +1 -0
  210. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/integrations.js +22 -8
  211. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/integrations.js.map +1 -1
  212. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/lifecycle.js +122 -25
  213. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/lifecycle.js.map +1 -1
  214. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/profile.js +2 -2
  215. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/profile.js.map +1 -1
  216. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/resources.js +1 -31
  217. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/resources.js.map +1 -1
  218. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/sharing.js +12 -4
  219. package/src/runtime/vendor/flywheel-cli-dist/commands/registry/sharing.js.map +1 -1
  220. package/src/runtime/vendor/flywheel-cli-dist/commands/registry.d.ts +2 -1
  221. package/src/runtime/vendor/flywheel-cli-dist/commands/registry.js +46 -9
  222. package/src/runtime/vendor/flywheel-cli-dist/commands/registry.js.map +1 -1
  223. package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-refresh.d.ts +2 -0
  224. package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-refresh.js +20 -0
  225. package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-refresh.js.map +1 -0
  226. package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-resolve.d.ts +2 -0
  227. package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-resolve.js +23 -0
  228. package/src/runtime/vendor/flywheel-cli-dist/commands/remote-artifacts-resolve.js.map +1 -0
  229. package/src/runtime/vendor/flywheel-cli-dist/errors.d.ts +15 -0
  230. package/src/runtime/vendor/flywheel-cli-dist/errors.js +16 -1
  231. package/src/runtime/vendor/flywheel-cli-dist/errors.js.map +1 -1
  232. package/src/runtime/vendor/flywheel-cli-dist/http/client.d.ts +1 -0
  233. package/src/runtime/vendor/flywheel-cli-dist/http/client.js +75 -19
  234. package/src/runtime/vendor/flywheel-cli-dist/http/client.js.map +1 -1
  235. package/src/runtime/vendor/flywheel-cli-dist/http/debug.d.ts +3 -0
  236. package/src/runtime/vendor/flywheel-cli-dist/http/debug.js +21 -2
  237. package/src/runtime/vendor/flywheel-cli-dist/http/debug.js.map +1 -1
  238. package/src/runtime/vendor/flywheel-cli-dist/main.js +119 -10
  239. package/src/runtime/vendor/flywheel-cli-dist/main.js.map +1 -1
  240. package/src/runtime/vendor/flywheel-cli-dist/output/format.js +44 -6
  241. package/src/runtime/vendor/flywheel-cli-dist/output/format.js.map +1 -1
  242. package/src/runtime/vendor/manifest.json +82 -10
  243. package/src/setup/base-url.mjs +43 -0
  244. package/src/setup/command.mjs +2 -0
  245. package/src/setup/io/patchers/json.mjs +2 -0
  246. package/src/setup/io/patchers/toml.mjs +7 -1
  247. package/src/setup/io/patchers/yaml.mjs +2 -0
  248. package/src/setup/modes/cli.mjs +72 -24
  249. package/src/setup/modes/mcp-command.mjs +146 -38
  250. package/src/setup/modes/mcp.mjs +26 -1
  251. package/src/setup/resolved-selection-record.mjs +25 -0
  252. package/src/setup/shared/prior-mode-detect.mjs +133 -14
  253. package/src/setup-auth.mjs +3 -2
  254. package/src/skill-installer.mjs +179 -1
  255. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-get.d.ts +0 -1
  256. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-get.js +0 -6
  257. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-get.js.map +0 -1
  258. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-set.d.ts +0 -2
  259. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-set.js +0 -19
  260. package/src/runtime/vendor/flywheel-cli-dist/commands/compute-policy-set.js.map +0 -1
  261. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-audit-list.d.ts +0 -2
  262. package/src/runtime/vendor/flywheel-cli-dist/commands/nodes-audit-list.js +0 -7
  263. 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 = "FLYWHEEL_GUIDED_SKILL_DECISION_FOR_TESTS";
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.cursor) hosts.push("cursor");
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: typeof entry?.url === "string" ? entry.url : null,
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: label,
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
- function buildSetupResultRows({ selectedHosts, hostStates, setupResult }) {
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
- if (agentResult.success !== true) {
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: alreadyConfigured ? "already configured" : "configured with API Key",
414
+ status,
349
415
  filePath:
350
- agentResult.touchedFiles[0] || hostStates.get(hostName)?.mcpPath || "(unknown)",
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(" Optional path via skills experimental_sync for selected hosts:");
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(options.baseUrl || DEFAULT_BASE_URL);
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 hosts = await resolveHosts(
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
- skillDecisionMode === "guided",
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 } = partitionInstallSkillHosts(hosts);
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(`No bundled skills found under ${path.join(packageRoot, "skills")}.`);
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) ? 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") {
@@ -1,6 +1,9 @@
1
1
  import path from "node:path";
2
2
 
3
- import { getHost as defaultGetHost } from "../../agents.mjs";
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 { getHost as defaultGetHost } from "../../agents.mjs";
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
- return typeof entry?.url === "string" && entry.url === serverUrl;
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`, `flywheel-staging.*`, self-hosted
91
- // `flywheel.<tenant>.*`, etc.) or (b) the URL's full origin (scheme + host +
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
- if (
219
- entry &&
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
- return true;
333
+ foundAny = true;
334
+ break;
247
335
  }
248
336
  }
249
- return false;
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
- const supportedHostSet = new Set(unique(supportedCliHosts));
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(),
@@ -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("/api/auth/mcp-api-keys/setup-device/start", baseUrl);
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("/api/auth/mcp-api-keys/setup-device/poll", baseUrl);
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: {