agents-inc 0.167.0 → 0.170.0

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 (200) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +18 -15
  3. package/dist/{chunk-ZR4YPKXQ.js → chunk-3G7X2WKI.js} +4 -4
  4. package/dist/{chunk-JOEA52NR.js → chunk-44TE3RKH.js} +46 -2
  5. package/dist/chunk-44TE3RKH.js.map +1 -0
  6. package/dist/{chunk-V5WXIM2F.js → chunk-52HDHJ7I.js} +11 -19
  7. package/dist/chunk-52HDHJ7I.js.map +1 -0
  8. package/dist/{chunk-V3I7VQ7N.js → chunk-6HNXYYVF.js} +39 -22
  9. package/dist/chunk-6HNXYYVF.js.map +1 -0
  10. package/dist/{chunk-MAWNVT2C.js → chunk-6ZRH5RHC.js} +10 -11
  11. package/dist/chunk-6ZRH5RHC.js.map +1 -0
  12. package/dist/{chunk-G6UREQ4V.js → chunk-7RDMTR64.js} +14 -34
  13. package/dist/chunk-7RDMTR64.js.map +1 -0
  14. package/dist/{chunk-GE3WKJ6Q.js → chunk-BMRUNMPV.js} +4 -4
  15. package/dist/{chunk-VAPTVR3J.js → chunk-CLPUWOSA.js} +4 -4
  16. package/dist/{chunk-VAPTVR3J.js.map → chunk-CLPUWOSA.js.map} +1 -1
  17. package/dist/{chunk-HWEKHVLE.js → chunk-F2BHT5C4.js} +9 -7
  18. package/dist/chunk-F2BHT5C4.js.map +1 -0
  19. package/dist/{chunk-ZXKBERQU.js → chunk-F5EBEATU.js} +2 -2
  20. package/dist/{chunk-PMJWD27C.js → chunk-HED2DAXZ.js} +3 -3
  21. package/dist/{chunk-SAYZWCH6.js → chunk-KOLDW6SF.js} +3 -3
  22. package/dist/{chunk-SAYZWCH6.js.map → chunk-KOLDW6SF.js.map} +1 -1
  23. package/dist/{chunk-A4KDXNOT.js → chunk-MQ6CGZNJ.js} +171 -522
  24. package/dist/chunk-MQ6CGZNJ.js.map +1 -0
  25. package/dist/{chunk-G4JK7WVO.js → chunk-NCWDK6L7.js} +115 -196
  26. package/dist/chunk-NCWDK6L7.js.map +1 -0
  27. package/dist/{chunk-VRXX4D6K.js → chunk-NEZ4OAOL.js} +1 -1
  28. package/dist/chunk-NEZ4OAOL.js.map +1 -0
  29. package/dist/chunk-NIHUOWE4.js +106 -0
  30. package/dist/chunk-NIHUOWE4.js.map +1 -0
  31. package/dist/{chunk-OI2H6M5I.js → chunk-NQW25DCF.js} +2 -2
  32. package/dist/chunk-NQW25DCF.js.map +1 -0
  33. package/dist/{chunk-25MPBIK3.js → chunk-OYJQUA3D.js} +3 -3
  34. package/dist/{chunk-25MPBIK3.js.map → chunk-OYJQUA3D.js.map} +1 -1
  35. package/dist/{chunk-ENGYJCTF.js → chunk-PJWGTNOX.js} +220 -254
  36. package/dist/chunk-PJWGTNOX.js.map +1 -0
  37. package/dist/{chunk-NBXXFIIW.js → chunk-RIPSGNLU.js} +3 -3
  38. package/dist/chunk-RIPSGNLU.js.map +1 -0
  39. package/dist/{chunk-Y47EV74W.js → chunk-SZYQISA2.js} +10 -13
  40. package/dist/chunk-SZYQISA2.js.map +1 -0
  41. package/dist/{chunk-TODCQFRB.js → chunk-USVBYQSQ.js} +2 -2
  42. package/dist/{chunk-Y3VIRVVE.js → chunk-V3KTSP3Q.js} +50 -42
  43. package/dist/chunk-V3KTSP3Q.js.map +1 -0
  44. package/dist/{chunk-PXWG7KFO.js → chunk-WTWMGH2C.js} +2 -2
  45. package/dist/commands/build/marketplace.js +23 -22
  46. package/dist/commands/build/marketplace.js.map +1 -1
  47. package/dist/commands/build/plugins.js +8 -9
  48. package/dist/commands/build/plugins.js.map +1 -1
  49. package/dist/commands/compile.js +19 -20
  50. package/dist/commands/compile.js.map +1 -1
  51. package/dist/commands/doctor.js +17 -18
  52. package/dist/commands/doctor.js.map +1 -1
  53. package/dist/commands/edit.js +138 -488
  54. package/dist/commands/edit.js.map +1 -1
  55. package/dist/commands/eject.js +21 -33
  56. package/dist/commands/eject.js.map +1 -1
  57. package/dist/commands/init.js +17 -45
  58. package/dist/commands/list.js +19 -17
  59. package/dist/commands/list.js.map +1 -1
  60. package/dist/commands/new/marketplace.js +11 -11
  61. package/dist/commands/new/marketplace.js.map +1 -1
  62. package/dist/commands/search.js +12 -13
  63. package/dist/commands/search.js.map +1 -1
  64. package/dist/commands/share.js +11 -12
  65. package/dist/commands/share.js.map +1 -1
  66. package/dist/commands/uninstall.js +18 -20
  67. package/dist/commands/uninstall.js.map +1 -1
  68. package/dist/commands/update.js +8 -9
  69. package/dist/commands/update.js.map +1 -1
  70. package/dist/components/common/removal-plan-confirm.js +2 -2
  71. package/dist/components/common/scroll-affordance.js +9 -0
  72. package/dist/components/common/select-list.js +2 -3
  73. package/dist/components/common/skill-agent-summary.js +11 -0
  74. package/dist/components/common/spinner.js +1 -1
  75. package/dist/{chunk-2VUYFTUB.js → components/common/summary-panel.js} +57 -31
  76. package/dist/components/common/summary-panel.js.map +1 -0
  77. package/dist/config-exports.js +1 -1
  78. package/dist/hooks/init.js +18 -46
  79. package/dist/hooks/init.js.map +1 -1
  80. package/dist/load-agent-defs-YMDWBFDP.js +14 -0
  81. package/dist/recompile-project-agents-SZ76WNTW.js +18 -0
  82. package/dist/{source-loader-7KZ3MD5O.js → source-loader-C5SQXZXI.js} +5 -5
  83. package/dist/src/agents/meta/codex-keeper/playbook.md +2 -3
  84. package/package.json +6 -4
  85. package/src/agents/meta/codex-keeper/playbook.md +2 -3
  86. package/src/schemas/project-config.schema.json +1 -1
  87. package/assets/demo.tape +0 -266
  88. package/dist/chunk-2VUYFTUB.js.map +0 -1
  89. package/dist/chunk-4NDBUJHK.js +0 -237
  90. package/dist/chunk-4NDBUJHK.js.map +0 -1
  91. package/dist/chunk-6L75SQZU.js +0 -168
  92. package/dist/chunk-6L75SQZU.js.map +0 -1
  93. package/dist/chunk-6LF4CQBY.js +0 -51
  94. package/dist/chunk-6LF4CQBY.js.map +0 -1
  95. package/dist/chunk-7JNJ52CD.js +0 -1179
  96. package/dist/chunk-7JNJ52CD.js.map +0 -1
  97. package/dist/chunk-A4KDXNOT.js.map +0 -1
  98. package/dist/chunk-DAIEQJIF.js +0 -48
  99. package/dist/chunk-DAIEQJIF.js.map +0 -1
  100. package/dist/chunk-ENGYJCTF.js.map +0 -1
  101. package/dist/chunk-G4JK7WVO.js.map +0 -1
  102. package/dist/chunk-G6UREQ4V.js.map +0 -1
  103. package/dist/chunk-HHIYT3PI.js +0 -53
  104. package/dist/chunk-HHIYT3PI.js.map +0 -1
  105. package/dist/chunk-HWEKHVLE.js.map +0 -1
  106. package/dist/chunk-JOEA52NR.js.map +0 -1
  107. package/dist/chunk-JQRJQ4SS.js +0 -118
  108. package/dist/chunk-JQRJQ4SS.js.map +0 -1
  109. package/dist/chunk-LFWLEDUG.js +0 -59
  110. package/dist/chunk-LFWLEDUG.js.map +0 -1
  111. package/dist/chunk-MAWNVT2C.js.map +0 -1
  112. package/dist/chunk-MPTNC32T.js +0 -92
  113. package/dist/chunk-MPTNC32T.js.map +0 -1
  114. package/dist/chunk-NBXXFIIW.js.map +0 -1
  115. package/dist/chunk-OI2H6M5I.js.map +0 -1
  116. package/dist/chunk-PNB3524H.js +0 -197
  117. package/dist/chunk-PNB3524H.js.map +0 -1
  118. package/dist/chunk-QHDPLLK6.js +0 -35
  119. package/dist/chunk-QHDPLLK6.js.map +0 -1
  120. package/dist/chunk-RAHSOJQ2.js +0 -25
  121. package/dist/chunk-RAHSOJQ2.js.map +0 -1
  122. package/dist/chunk-RZDXDMT6.js +0 -23
  123. package/dist/chunk-RZDXDMT6.js.map +0 -1
  124. package/dist/chunk-SCOQ34YM.js +0 -17
  125. package/dist/chunk-SCOQ34YM.js.map +0 -1
  126. package/dist/chunk-SXVHSOTH.js +0 -268
  127. package/dist/chunk-SXVHSOTH.js.map +0 -1
  128. package/dist/chunk-T6UWJAB3.js +0 -28
  129. package/dist/chunk-T6UWJAB3.js.map +0 -1
  130. package/dist/chunk-TSIU7DME.js +0 -43
  131. package/dist/chunk-TSIU7DME.js.map +0 -1
  132. package/dist/chunk-TTY6DPJN.js +0 -27
  133. package/dist/chunk-TTY6DPJN.js.map +0 -1
  134. package/dist/chunk-TZ2YJJKK.js +0 -292
  135. package/dist/chunk-TZ2YJJKK.js.map +0 -1
  136. package/dist/chunk-V3I7VQ7N.js.map +0 -1
  137. package/dist/chunk-V5WXIM2F.js.map +0 -1
  138. package/dist/chunk-VRXX4D6K.js.map +0 -1
  139. package/dist/chunk-WTJ3AY33.js +0 -31
  140. package/dist/chunk-WTJ3AY33.js.map +0 -1
  141. package/dist/chunk-WVUDLKIO.js +0 -121
  142. package/dist/chunk-WVUDLKIO.js.map +0 -1
  143. package/dist/chunk-WWIFNPJG.js +0 -317
  144. package/dist/chunk-WWIFNPJG.js.map +0 -1
  145. package/dist/chunk-XQHZPINL.js +0 -89
  146. package/dist/chunk-XQHZPINL.js.map +0 -1
  147. package/dist/chunk-XZEVWPX6.js +0 -230
  148. package/dist/chunk-XZEVWPX6.js.map +0 -1
  149. package/dist/chunk-Y3VIRVVE.js.map +0 -1
  150. package/dist/chunk-Y47EV74W.js.map +0 -1
  151. package/dist/components/wizard/category-grid.js +0 -13
  152. package/dist/components/wizard/checkbox-grid.js +0 -12
  153. package/dist/components/wizard/domain-selection.js +0 -18
  154. package/dist/components/wizard/run-wizard-session.js +0 -40
  155. package/dist/components/wizard/run-wizard-session.js.map +0 -1
  156. package/dist/components/wizard/scroll-affordance.js +0 -9
  157. package/dist/components/wizard/skill-agent-summary.js +0 -13
  158. package/dist/components/wizard/source-grid.js +0 -16
  159. package/dist/components/wizard/source-grid.js.map +0 -1
  160. package/dist/components/wizard/stack-selection.js +0 -17
  161. package/dist/components/wizard/stack-selection.js.map +0 -1
  162. package/dist/components/wizard/step-agents.js +0 -18
  163. package/dist/components/wizard/step-agents.js.map +0 -1
  164. package/dist/components/wizard/step-build.js +0 -18
  165. package/dist/components/wizard/step-build.js.map +0 -1
  166. package/dist/components/wizard/step-confirm.js +0 -18
  167. package/dist/components/wizard/step-confirm.js.map +0 -1
  168. package/dist/components/wizard/step-sources.js +0 -19
  169. package/dist/components/wizard/step-sources.js.map +0 -1
  170. package/dist/components/wizard/step-stack.js +0 -18
  171. package/dist/components/wizard/step-stack.js.map +0 -1
  172. package/dist/components/wizard/summary-panel.js +0 -17
  173. package/dist/components/wizard/summary-panel.js.map +0 -1
  174. package/dist/components/wizard/toast.js +0 -9
  175. package/dist/components/wizard/toast.js.map +0 -1
  176. package/dist/components/wizard/wizard-layout.js +0 -22
  177. package/dist/components/wizard/wizard-layout.js.map +0 -1
  178. package/dist/components/wizard/wizard-tabs.js +0 -11
  179. package/dist/components/wizard/wizard-tabs.js.map +0 -1
  180. package/dist/components/wizard/wizard.js +0 -39
  181. package/dist/components/wizard/wizard.js.map +0 -1
  182. package/dist/load-agent-defs-3C27ENC7.js +0 -14
  183. package/dist/load-agent-defs-3C27ENC7.js.map +0 -1
  184. package/dist/recompile-project-agents-DGNBCU3N.js +0 -18
  185. package/dist/recompile-project-agents-DGNBCU3N.js.map +0 -1
  186. package/dist/source-loader-7KZ3MD5O.js.map +0 -1
  187. package/dist/stores/wizard-store.js +0 -24
  188. package/dist/stores/wizard-store.js.map +0 -1
  189. /package/assets/{demo.gif → legacy-wizard.gif} +0 -0
  190. /package/dist/{chunk-ZR4YPKXQ.js.map → chunk-3G7X2WKI.js.map} +0 -0
  191. /package/dist/{chunk-GE3WKJ6Q.js.map → chunk-BMRUNMPV.js.map} +0 -0
  192. /package/dist/{chunk-ZXKBERQU.js.map → chunk-F5EBEATU.js.map} +0 -0
  193. /package/dist/{chunk-PMJWD27C.js.map → chunk-HED2DAXZ.js.map} +0 -0
  194. /package/dist/{chunk-TODCQFRB.js.map → chunk-USVBYQSQ.js.map} +0 -0
  195. /package/dist/{chunk-PXWG7KFO.js.map → chunk-WTWMGH2C.js.map} +0 -0
  196. /package/dist/components/{wizard → common}/scroll-affordance.js.map +0 -0
  197. /package/dist/components/{wizard → common}/skill-agent-summary.js.map +0 -0
  198. /package/dist/{components/wizard/category-grid.js.map → load-agent-defs-YMDWBFDP.js.map} +0 -0
  199. /package/dist/{components/wizard/checkbox-grid.js.map → recompile-project-agents-SZ76WNTW.js.map} +0 -0
  200. /package/dist/{components/wizard/domain-selection.js.map → source-loader-C5SQXZXI.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/run-wizard-session.tsx"],"sourcesContent":["import React from \"react\";\nimport { promptValue } from \"../common/prompt-confirm.js\";\nimport { Wizard, type WizardProps, type WizardResultV2 } from \"./wizard.js\";\nimport { hydrateWizardStore, type HydrateOptions } from \"../../stores/wizard-store.js\";\nimport {\n disableBuffering,\n drainBuffer,\n enableBuffering,\n type StartupMessage,\n} from \"../../utils/logger.js\";\n\nexport type WizardSessionOptions = {\n hydrate: HydrateOptions;\n props: Omit<WizardProps, \"onComplete\" | \"onCancel\">;\n onCancel: () => void;\n /** Command-owned terminal reset, run after the Ink render unmounts. */\n clearTerminal: () => void;\n};\n\n/**\n * Hydration under buffer mode, with everything it said appended to the band the load filled.\n *\n * Hydration WARNS: `populateFromSkillIds` reports every installed skill the loaded source no\n * longer carries, and every one whose category no domain claims. Both are routine, both exist\n * to hand the user a remedy, and both were unreadable — the load's buffer is drained back in\n * `lib/operations/source/load-source.ts`, so by the time the store populates, `warn()` is a\n * plain stderr write again. Written there it survives nothing: the wizard's first frame is\n * built to the height of the terminal, so it pushes those lines off the top of the screen the\n * moment it paints. A warning raised between the load's drain and the mount has no surface but\n * this band, which is why the window reopens here rather than the message finding another way\n * out.\n *\n * The load's own messages are passed in and concatenated rather than left in the buffer,\n * because {@link enableBuffering} resets it — this is a second window, not the first one held\n * open. Holding one window across both would have to span two modules and the command's own\n * `this.error()` paths, where no `finally` can reach it.\n *\n * And that `finally` is the point of the try: buffer mode is process-wide, so hydration\n * throwing while it is on would swallow every `warn()` for the rest of the run.\n */\nfunction hydrateIntoStartupBand(\n hydrate: HydrateOptions,\n loaded: StartupMessage[] = [],\n): StartupMessage[] {\n enableBuffering();\n try {\n hydrateWizardStore(hydrate);\n return [...loaded, ...drainBuffer()];\n } finally {\n disableBuffering();\n }\n}\n\n/**\n * Runs one full wizard session: hydrate the store, render the wizard, clear the\n * screen, and return the selection — or null when it was cancelled.\n *\n * The three endings settle the same promise, first one winning: the wizard completed,\n * the wizard was cancelled, or the Ink app exited having chosen neither (Ctrl+C, or a\n * render that failed). Only the first carries a selection, so the other two are `null`\n * — `onExit` for the ending no callback announces.\n *\n * The command's own cancellation notice runs BEFORE the resolve, because resolving is\n * what clears the screen: printed after, it would be wiped by the repaint it caused.\n */\nexport async function runWizardSession(\n options: WizardSessionOptions,\n): Promise<WizardResultV2 | null> {\n const startupMessages = hydrateIntoStartupBand(options.hydrate, options.props.startupMessages);\n\n const result = await promptValue<WizardResultV2 | null>(\n (resolve) => (\n <Wizard\n {...options.props}\n startupMessages={startupMessages}\n onComplete={resolve}\n onCancel={() => {\n options.onCancel();\n resolve(null);\n }}\n />\n ),\n { onExit: null, clearOnResolve: true },\n );\n\n options.clearTerminal();\n\n return !result || result.cancelled ? null : result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA,OAAkB;AAwEZ;AAhCN,SAAS,uBACP,SACA,SAA2B,CAAC,GACV;AAClB,kBAAgB;AAChB,MAAI;AACF,uBAAmB,OAAO;AAC1B,WAAO,CAAC,GAAG,QAAQ,GAAG,YAAY,CAAC;AAAA,EACrC,UAAE;AACA,qBAAiB;AAAA,EACnB;AACF;AAcA,eAAsB,iBACpB,SACgC;AAChC,QAAM,kBAAkB,uBAAuB,QAAQ,SAAS,QAAQ,MAAM,eAAe;AAE7F,QAAM,SAAS,MAAM;AAAA,IACnB,CAAC,YACC;AAAA,MAAC;AAAA;AAAA,QACE,GAAG,QAAQ;AAAA,QACZ;AAAA,QACA,YAAY;AAAA,QACZ,UAAU,MAAM;AACd,kBAAQ,SAAS;AACjB,kBAAQ,IAAI;AAAA,QACd;AAAA;AAAA,IACF;AAAA,IAEF,EAAE,QAAQ,MAAM,gBAAgB,KAAK;AAAA,EACvC;AAEA,UAAQ,cAAc;AAEtB,SAAO,CAAC,UAAU,OAAO,YAAY,OAAO;AAC9C;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/lib/operations/project/remove-compiled-agents.ts","../src/cli/lib/operations/project/compile-agents.ts","../src/cli/lib/operations/skills/discover-skills.ts","../src/cli/lib/operations/skills/copy-local-skills.ts","../src/cli/lib/operations/skills/uninstall-plugin-skills.ts","../src/cli/lib/loading/catalogue-seat.ts","../src/cli/lib/operations/project/recompile-project-agents.ts"],"sourcesContent":["import path from \"path\";\nimport { pruneStaleCompiledAgents } from \"../../agents/list-compiled-agents.js\";\nimport type { AgentCodec } from \"../../installation/install-layout.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\nimport { remove, removeDirIfEmpty } from \"../../../utils/fs.js\";\nimport type { AgentName } from \"../../../types/index.js\";\n\nconst AGENT_FILE_EXTENSION = \".md\";\n\nexport type RemoveCompiledAgentsOptions = {\n /** The scope's `.claude/agents/` directory holding the compiled files. */\n agentsDir: string;\n agents: readonly AgentName[];\n};\n\nexport type PruneCompiledAgentsOptions = {\n agentsDir: string;\n /**\n * The COMPLETE set of agents that belong in `agentsDir` — every other\n * CLI-compiled agent there is stale. Only an authoritative pass can say this.\n */\n keep: ReadonlySet<AgentName>;\n /** The host's agent file format — Claude's `.md` when absent. */\n codec?: AgentCodec;\n};\n\nexport type RemoveCompiledAgentsResult = {\n /** Agents whose compiled file this call disposed of; an absent file counts. */\n removed: AgentName[];\n /** Agents whose file survived an error, for the caller to report. */\n failed: Array<{ name: AgentName; error: string }>;\n};\n\ntype RemovalOutcome = { name: AgentName; ok: true } | { name: AgentName; ok: false; error: string };\n\n/**\n * Deletes the named agents' compiled `.md` files from `agentsDir`, then takes the\n * directory itself when nothing at all is left in it — the shape `deleteLocalSkill`\n * models for skills.\n *\n * A scope's `.claude/agents/` is an artefact of what it holds, so the removal that\n * empties it owns the tidy and no caller has to remember. An agent with no file on\n * disk is nothing to do rather than an error.\n */\nexport async function removeCompiledAgents(\n options: RemoveCompiledAgentsOptions,\n): Promise<RemoveCompiledAgentsResult> {\n const outcomes = await Promise.all(\n options.agents.map((name) => removeCompiledAgentFile(options.agentsDir, name)),\n );\n await tidyEmptiedAgentsDir(options.agentsDir);\n\n return {\n removed: outcomes.flatMap((outcome) => (outcome.ok ? [outcome.name] : [])),\n failed: outcomes.flatMap((outcome) =>\n outcome.ok ? [] : [{ name: outcome.name, error: outcome.error }],\n ),\n };\n}\n\n/**\n * Deletes every CLI-compiled agent in `agentsDir` outside `keep`, then takes the\n * directory on the same terms as `removeCompiledAgents`.\n *\n * Hand-authored agents are preserved by `pruneStaleCompiledAgents`'s `isAgentName`\n * predicate, so a directory this leaves empty is one nothing at all remains in.\n */\nexport async function pruneCompiledAgents(options: PruneCompiledAgentsOptions): Promise<void> {\n await pruneStaleCompiledAgents(options.agentsDir, options.keep, options.codec);\n await tidyEmptiedAgentsDir(options.agentsDir);\n}\n\nasync function removeCompiledAgentFile(\n agentsDir: string,\n name: AgentName,\n): Promise<RemovalOutcome> {\n try {\n await remove(path.join(agentsDir, `${name}${AGENT_FILE_EXTENSION}`));\n return { name, ok: true };\n } catch (error) {\n return { name, ok: false, error: getErrorMessage(error) };\n }\n}\n\n/**\n * Emptiness is FILESYSTEM emptiness, never roster emptiness: a hand-authored agent\n * or any user-owned file keeps the directory alive whatever a config says. The\n * agents directory only — `.claude/` above it is uninstall's decision, not a\n * removal path's.\n */\nasync function tidyEmptiedAgentsDir(agentsDir: string): Promise<void> {\n await removeDirIfEmpty(agentsDir);\n}\n","import { pruneCompiledAgents } from \"./remove-compiled-agents.js\";\nimport { recompileAgents } from \"../../agents/index.js\";\nimport { loadInstalledConfig } from \"../../configuration/index.js\";\nimport { buildAgentScopeMap } from \"../../installation/index.js\";\nimport { agentCodec, providerInUse } from \"../../installation/install-layout.js\";\nimport type { AgentName, SkillDefinitionMap, SkillScope } from \"../../../types/index.js\";\n\nexport type CompileAgentsOptions = {\n projectDir: string;\n sourcePath: string;\n pluginDir?: string;\n skills?: SkillDefinitionMap;\n agentScopeMap?: Map<AgentName, SkillScope>;\n agents?: AgentName[];\n /** When set, loads config and filters agents to only those matching this scope. */\n scopeFilter?: SkillScope;\n outputDir?: string;\n};\n\nexport type CompilationResult = {\n compiled: AgentName[];\n /**\n * The subset of `compiled` whose file this pass actually wrote. A pass whose\n * `rewritten` is empty changed nothing on disk, which is exactly what the\n * recompile summary reports and what the count it replaced could not say.\n */\n rewritten: AgentName[];\n failed: AgentName[];\n warnings: string[];\n};\n\n/**\n * Compiles agent markdown files from templates + skill content.\n *\n * Thin wrapper around recompileAgents() that standardizes options.\n * The caller invokes this once (edit, update) or twice with scopeFilter (compile).\n */\nexport async function compileAgents(options: CompileAgentsOptions): Promise<CompilationResult> {\n const { agents: resolvedAgents, agentScopeMap: resolvedAgentScopeMap } = options.scopeFilter\n ? await rosterForScope(options, options.scopeFilter)\n : { agents: options.agents, agentScopeMap: options.agentScopeMap };\n\n const recompileResult = await recompileAgents({\n pluginDir: options.pluginDir ?? options.projectDir,\n sourcePath: options.sourcePath,\n ...(resolvedAgents !== undefined && { agents: resolvedAgents }),\n ...(options.skills !== undefined && { skills: options.skills }),\n projectDir: options.projectDir,\n ...(options.outputDir !== undefined && { outputDir: options.outputDir }),\n ...(resolvedAgentScopeMap !== undefined && { agentScopeMap: resolvedAgentScopeMap }),\n });\n\n await pruneStaleAgentsForPass(options, recompileResult);\n\n return {\n compiled: recompileResult.compiled,\n rewritten: recompileResult.rewritten,\n failed: recompileResult.failed,\n warnings: recompileResult.warnings,\n };\n}\n\n/**\n * What a scope-filtered pass compiles, read off the installed config: the requested agents\n * narrowed to those active at `scope` (all of those when none were requested), and the caller's\n * scope routing — auto-built from the config when the caller passed none. With no installed\n * config, both are the caller's as passed.\n */\nasync function rosterForScope(\n options: CompileAgentsOptions,\n scope: SkillScope,\n): Promise<{\n agents: AgentName[] | undefined;\n agentScopeMap: Map<AgentName, SkillScope> | undefined;\n}> {\n const config = (await loadInstalledConfig(options.projectDir))?.config;\n const activeAtScope = config?.agents\n .filter((agent) => !agent.excluded && agent.scope === scope)\n .map((agent) => agent.name);\n\n return {\n agents: requestedAgentsAmong(options.agents, activeAtScope),\n agentScopeMap: options.agentScopeMap ?? (config ? buildAgentScopeMap(config) : undefined),\n };\n}\n\n/** The requested agents that appear in `activeAtScope`; either list alone when the other is absent. */\nfunction requestedAgentsAmong(\n requested: AgentName[] | undefined,\n activeAtScope: AgentName[] | undefined,\n): AgentName[] | undefined {\n if (activeAtScope === undefined) return requested;\n if (requested === undefined) return activeAtScope;\n\n const atScope = new Set(activeAtScope);\n return requested.filter((name) => atScope.has(name));\n}\n\n/**\n * Compiled-agent writes are additive, so a deselected or stale agent's `.md`\n * lingers after recompile. An authoritative, scope-UNfiltered pass owns its\n * entire `outputDir` (its resolved roster is the full set for that directory),\n * so it prunes built-in agents no longer compiled there. A scope-FILTERED pass\n * (the hasBoth two-pass compile, or the registered-project recompile)\n * sees only one scope's agents and must never delete another scope's files, so\n * it skips pruning. Removing the stale files and tidying the directory they\n * emptied is one operation's job, not this pass's.\n */\nasync function pruneStaleAgentsForPass(\n options: CompileAgentsOptions,\n recompileResult: CompilationResult,\n): Promise<void> {\n if (options.scopeFilter || !options.outputDir) return;\n\n const compiledForDir = new Set<AgentName>([\n ...recompileResult.compiled,\n ...recompileResult.failed,\n ]);\n await pruneCompiledAgents({\n agentsDir: options.outputDir,\n keep: compiledForDir,\n // The host this installation compiles for — a Codex role is a `.toml`, and a prune that only\n // knew `.md` left a deselected role in place for Codex to keep offering (CLI-896's sibling).\n codec: agentCodec(providerInUse(options.projectDir)),\n });\n}\n","import { discoverAllPluginSkills } from \"../../plugins/index.js\";\nimport { isHomeDirectory } from \"../../installation/is-home-directory.js\";\n// loadSkillsFromDir lives in loading/ (a leaf) so both this module and\n// plugins/plugin-discovery can share it without an operations↔plugins cycle.\nimport { loadSkillsFromDir, type LoadedSkills } from \"../../loading/index.js\";\nimport { verbose } from \"../../../utils/logger.js\";\nimport { globalInstallRoot } from \"../../../consts.js\";\nimport {\n installBaseDir,\n providerInUse,\n skillsDir,\n skillsPathPrefix,\n} from \"../../installation/install-layout.js\";\nimport { typedEntries, typedKeys } from \"../../../utils/typed-object.js\";\nimport type { UnusableSkillMetadata } from \"../../loading/index.js\";\nimport type {\n SkillDefinition,\n SkillDefinitionMap,\n SkillId,\n SkillScope,\n} from \"../../../types/index.js\";\n\nexport type DiscoveredSkills = {\n allSkills: SkillDefinitionMap;\n totalSkillCount: number;\n pluginSkillCount: number;\n localSkillCount: number;\n globalPluginSkillCount: number;\n globalLocalSkillCount: number;\n /**\n * Installed skills whose metadata.yaml exists but describes no skill, from either\n * scope. Nothing was loaded for them; `compile` refuses the run over any entry\n * here rather than compile agents around a skill its metadata does not describe.\n */\n unusableMetadata: UnusableSkillMetadata[];\n};\n\n/** The result of a local-skill scan that was not performed. */\nconst NO_LOCAL_SKILLS: LoadedSkills = { skills: {}, unusableMetadata: [] };\n\n/**\n * Discovers the skills copied in rather than installed as plugins, at one scope of one project.\n *\n * **It composed `<rootDir>/.claude/skills` until 2026-09-22, for every provider**, which made this\n * the last Claude literal on the eject READ path: a Codex installation copies its skills to\n * `$CODEX_HOME/skills` and `<repo>/.agents/skills` — the WRITE path routes through the layout\n * already — and this read went on looking in a directory that host never writes to. Nothing failed:\n * the scan answered \"no skills\", which is the same answer an empty installation gives.\n *\n * The scope is a required argument rather than a defaulted one, for the reason C2 deleted\n * `DEFAULT_PROVIDER`: a default is invisible at the call site, and the two call sites below mean\n * different things by it. The provider is READ off the scope root the same way\n * `resolveInstallPaths` reads it, from one probe, so the directory and the prefix cannot name two\n * different installations.\n */\nexport async function discoverLocalProjectSkills(\n projectDir: string,\n scope: SkillScope,\n): Promise<LoadedSkills> {\n const provider = providerInUse(installBaseDir(projectDir, scope));\n\n return loadSkillsFromDir(skillsDir(provider, scope, projectDir), {\n pathPrefix: skillsPathPrefix(provider, scope, projectDir),\n requireMetadata: true,\n });\n}\n\n/** Where the global scope's copied-in skills are, for the diagnostic line that names them. */\nfunction globalSkillsRoot(): string {\n const home = globalInstallRoot();\n return skillsDir(providerInUse(home), \"global\", home);\n}\n\n/** The same, for whichever scope the project pass asked. */\nfunction projectSkillsRoot(projectDir: string, scope: SkillScope): string {\n return skillsDir(providerInUse(installBaseDir(projectDir, scope)), scope, projectDir);\n}\n\n/** Merges skill maps — later sources take precedence over earlier ones. */\nexport function mergeSkills(...skillSources: SkillDefinitionMap[]): SkillDefinitionMap {\n const merged: SkillDefinitionMap = {};\n\n for (const source of skillSources) {\n for (const [id, skill] of typedEntries<SkillId, SkillDefinition | undefined>(source)) {\n if (skill) {\n merged[id] = skill;\n }\n }\n }\n\n return merged;\n}\n\n/**\n * Discovers all installed skills for a project directory using a 4-way merge: the global scope's\n * plugins and copied-in skills, then the project's own of each, so the project wins on conflict.\n *\n * **Every one of the four is resolved per PROVIDER rather than spelled as a Claude path.** The\n * plugin halves go through `hostAt(...).listPlugins` and the copied-in halves through\n * {@link discoverLocalProjectSkills}; on Claude that is `~/.claude/{plugins,skills}` and\n * `<project>/.claude/{plugins,skills}` exactly as it always was, and on Codex it is the Codex\n * state root and the repository's own `.agents/skills`.\n *\n * Pure function — no user-facing logging. Callers add their own log messages.\n * Uses verbose() for diagnostic output only.\n */\nexport async function discoverInstalledSkills(projectDir: string): Promise<DiscoveredSkills> {\n const isGlobalProject = isHomeDirectory(projectDir);\n\n // 1. Global plugins\n const globalPluginSkills = isGlobalProject\n ? {}\n : await discoverAllPluginSkills(globalInstallRoot());\n const globalPluginSkillCount = typedKeys<SkillId>(globalPluginSkills).length;\n if (globalPluginSkillCount > 0) {\n verbose(` Found ${globalPluginSkillCount} skills from global plugins`);\n }\n\n // 2. Global local skills\n const globalLocal = isGlobalProject\n ? NO_LOCAL_SKILLS\n : await discoverLocalProjectSkills(projectDir, \"global\");\n const globalLocalSkillCount = typedKeys<SkillId>(globalLocal.skills).length;\n if (globalLocalSkillCount > 0) {\n verbose(` Found ${globalLocalSkillCount} global local skills from ${globalSkillsRoot()}`);\n }\n\n // 3. Project plugins\n const pluginSkills = await discoverAllPluginSkills(projectDir);\n const pluginSkillCount = typedKeys<SkillId>(pluginSkills).length;\n verbose(` Found ${pluginSkillCount} skills from installed plugins`);\n\n // 4. Project local skills.\n //\n // At the HOME root the two scopes are one installation, so the project pass asks the GLOBAL\n // scope — which is the same directory on Claude and is `$CODEX_HOME/skills` rather than\n // `<home>/.agents/skills` on Codex. Asking both and merging would double the local count on\n // every Claude run for no gain.\n const localScope: SkillScope = isGlobalProject ? \"global\" : \"project\";\n const local = await discoverLocalProjectSkills(projectDir, localScope);\n const localSkillCount = typedKeys<SkillId>(local.skills).length;\n verbose(\n ` Found ${localSkillCount} local skills from ${projectSkillsRoot(projectDir, localScope)}`,\n );\n\n // Merge: global first, project second — project wins on conflict\n const allSkills = mergeSkills(globalPluginSkills, globalLocal.skills, pluginSkills, local.skills);\n const totalSkillCount = typedKeys<SkillId>(allSkills).length;\n\n return {\n allSkills,\n totalSkillCount,\n pluginSkillCount: globalPluginSkillCount + pluginSkillCount,\n localSkillCount: globalLocalSkillCount + localSkillCount,\n globalPluginSkillCount,\n globalLocalSkillCount,\n unusableMetadata: [...globalLocal.unusableMetadata, ...local.unusableMetadata],\n };\n}\n","import { resolveInstallPaths } from \"../../installation/index.js\";\nimport { copySkillsToLocalFlattened, type CopiedSkill } from \"../../skills/index.js\";\nimport { ensureDir } from \"../../../utils/fs.js\";\nimport type { SkillConfig } from \"../../../types/config.js\";\nimport type { SourceLoadResult } from \"../../loading/source-loader.js\";\n\nexport type SkillCopyResult = {\n projectCopied: CopiedSkill[];\n globalCopied: CopiedSkill[];\n totalCopied: number;\n};\n\n/** Copies one scope's local skills into its skills directory. */\nasync function copyScopedLocalSkills(\n scopeSkills: SkillConfig[],\n skillsDir: string,\n sourceResult: SourceLoadResult,\n): Promise<CopiedSkill[]> {\n if (scopeSkills.length === 0) return [];\n\n await ensureDir(skillsDir);\n\n return copySkillsToLocalFlattened(\n scopeSkills.map((s) => s.id),\n skillsDir,\n sourceResult,\n );\n}\n\n/**\n * Copies local-source skills to their scope-appropriate directories.\n *\n * Splits skills by scope (project vs global), resolves install paths,\n * ensures directories exist, and copies from source.\n */\nexport async function copyLocalSkills(\n skills: SkillConfig[],\n projectDir: string,\n sourceResult: SourceLoadResult,\n): Promise<SkillCopyResult> {\n const projectLocalSkills = skills.filter((s) => s.scope !== \"global\");\n const globalLocalSkills = skills.filter((s) => s.scope === \"global\");\n\n const projectPaths = resolveInstallPaths(projectDir, \"project\");\n const globalPaths = resolveInstallPaths(projectDir, \"global\");\n\n const projectCopied = await copyScopedLocalSkills(\n projectLocalSkills,\n projectPaths.skillsDir,\n sourceResult,\n );\n const globalCopied = await copyScopedLocalSkills(\n globalLocalSkills,\n globalPaths.skillsDir,\n sourceResult,\n );\n\n return {\n projectCopied,\n globalCopied,\n totalCopied: projectCopied.length + globalCopied.length,\n };\n}\n","import { hostAt } from \"../../hosts/host-for.js\";\nimport { buildMarketplacePluginRef } from \"../../plugins/index.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\nimport type { SkillId } from \"../../../types/index.js\";\nimport type { SkillConfig, SkillScope } from \"../../../types/config.js\";\n\n/**\n * Where a plugin is looked for when the old config has no entry naming the skill at all.\n *\n * The scope translation swallowed this until C3 — an absent scope and a project one mapped to the\n * same Claude scope word — so the behaviour is unchanged and only the silence is gone. It is the\n * safe direction of the two: a project-scoped removal cannot take a plugin away from every other\n * project under one HOME.\n */\nconst SCOPE_OF_AN_UNRECORDED_SKILL: SkillScope = \"project\";\n\nexport type PluginUninstallResult = {\n /**\n * The skills whose plugin registration this run really dropped.\n *\n * OBSERVED rather than asked for: a host's `uninstallPlugin` answers `removed` or\n * `absent`, and until that answer was read this list held every id the caller named — so a\n * plugin the user had already removed themselves was reported as one `edit` had just taken\n * away. Neither is a failure, which is why the distinction cannot be an exception and has to be\n * the return value.\n */\n uninstalled: SkillId[];\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/**\n * Uninstalls skill plugins through the host this installation belongs to, using the scope the\n * old config filed each one under.\n *\n * Each plugin reference is qualified as `{skillId}@{marketplace}` to match\n * the form used at install time — bare skill IDs will not match the registry.\n */\nexport async function uninstallPluginSkills(\n skillIds: SkillId[],\n oldSkills: SkillConfig[],\n marketplace: string,\n projectDir: string,\n): Promise<PluginUninstallResult> {\n const host = hostAt(projectDir);\n const uninstalled: SkillId[] = [];\n const failed: PluginUninstallResult[\"failed\"] = [];\n\n for (const skillId of skillIds) {\n const oldSkill = oldSkills.find((s) => s.id === skillId);\n const pluginScope = oldSkill?.scope ?? SCOPE_OF_AN_UNRECORDED_SKILL;\n const pluginRef = buildMarketplacePluginRef(skillId, marketplace);\n try {\n const outcome = await host.uninstallPlugin(pluginRef, pluginScope, projectDir);\n if (outcome === \"removed\") uninstalled.push(skillId);\n } catch (error) {\n failed.push({ id: skillId, error: getErrorMessage(error) });\n }\n }\n\n return { uninstalled, failed };\n}\n","import type { MergedSkillsMatrix } from \"../../types\";\nimport { initializeMatrix, matrix } from \"../matrix/matrix-provider.js\";\nimport { loadSkillsMatrixFromSource } from \"./source-loader.js\";\n\n/**\n * Runs `body` with the skills catalogue seated for `projectDir`, hands it the catalogue\n * that was seated, and puts the caller's own seat back afterwards.\n *\n * A registered project's own local skills, and the skills of the marketplace ITS config\n * names, are in that project's catalogue and in nobody else's. Two things a fan-out does to\n * such a project read a catalogue, and both used to read the TRIGGERING command's:\n *\n * - The RENDER of a compiled agent, which reaches the catalogue through the module-level\n * singleton (`matrix` in `matrix-provider.ts`) that `statedUsageFor` and `liveCategoryOf`\n * in `stacks/stacks-loader.ts` read directly, so no argument reaches it. Rendered against\n * somebody else's seat, each of the project's own skills loses the `usageGuidance` it\n * states and falls back to the per-category placeholder.\n * - The DERIVATION of that project's `config-types.ts` unions, which looks each configured\n * skill's category up in the catalogue (`deriveCategories` / `deriveDomains`). Against\n * somebody else's, a skill only this project's catalogue carries resolves to nothing and\n * its category and domain leave the project's `Category` and `Domain` unions.\n *\n * Both have the same ending: the project's own next `compile` writes the value back from its\n * own catalogue, so the two commands undo each other for as long as they are both run.\n *\n * The catalogue is PASSED to the body as well as seated, so a derivation that can take one as\n * an argument does — a body reading the singleton it just asked to be seated cannot say which\n * seat it got, which is the distinction the whole helper exists to keep. `compile.ts`'s\n * `seatMatrixForPass` returns its catalogue for the same reason.\n *\n * The seat is restored rather than left standing because this is a side trip: the caller has\n * its own pass to finish — `init` and `edit` compile their own agents after the gate returns —\n * and would otherwise render them against the last registered project's catalogue.\n *\n * The load sits outside the `try` deliberately. It seats nothing when it throws, so there is\n * no seat to restore, and a project whose catalogue cannot be loaded is left to the caller's\n * own failure handling rather than silently processed against somebody else's — which is the\n * whole defect this exists to stop. Both callers count such a project as one they could not\n * reach and carry on with the rest.\n *\n * The load is an `\"upkeep\"` one: a fan-out rewrites a project that is already installed, so a\n * marketplace that has since lost its manifest does not leave the project naming global content\n * a change elsewhere just removed.\n */\nexport async function withCatalogueSeatedFor<T>(\n projectDir: string,\n body: (catalogue: MergedSkillsMatrix) => Promise<T>,\n): Promise<T> {\n const callersCatalogue = matrix;\n const { matrix: seated } = await loadSkillsMatrixFromSource({\n projectDir,\n purpose: \"upkeep\",\n skipExtraSources: true,\n matrixOnly: true,\n });\n try {\n return await body(seated);\n } finally {\n initializeMatrix(callersCatalogue);\n }\n}\n","import { compileAgents, type CompilationResult } from \"./compile-agents.js\";\nimport { loadAgentDefs } from \"./load-agent-defs.js\";\nimport { discoverInstalledSkills } from \"../skills/index.js\";\nimport { resolveInstallPaths } from \"../../installation/index.js\";\nimport { withCatalogueSeatedFor } from \"../../loading/catalogue-seat.js\";\nimport { getErrorMessage } from \"../../../utils/errors.js\";\n\n/**\n * Recompiles the PROJECT-scoped agents of a registered project after a global\n * config change was propagated into that project's `config.ts`.\n *\n * Propagation (`propagateGlobalChangesToProjects`) rewrites a registered\n * project's `config.ts` / `config-types.ts` but never touches its compiled\n * `.claude/agents/*.md`, so the compiled agents keep emitting whatever skill\n * reference form the OLD global data dictated. Run this per propagated project,\n * after propagation, to bring the compiled artifacts back in step.\n *\n * Scope: project only. The global agents were already recompiled by the\n * triggering operation's own pass; repeating a global pass per project would\n * rewrite `~/.claude/agents` once per registered project for no gain.\n *\n * Both inputs a compiled agent's bytes depend on are resolved from THIS\n * project's directory, and neither is inherited from the command that triggered\n * the fan-out: `skills` is passed explicitly, because without it\n * `recompileAgents` falls back to `discoverAllPluginSkills`, which sees plugin\n * skills only and would silently strip every global-local and project-local\n * skill; and the catalogue is seated by {@link withCatalogueSeatedFor}, because\n * the render reads it from a module-level singleton no argument reaches.\n *\n * Agent partials always come from the CLI itself (`getLocalAgentDefinitions`\n * returns `sourcePath: PROJECT_ROOT`), so no per-project marketplace source\n * resolution is needed.\n */\nexport async function recompileRegisteredProjectAgents(\n projectDir: string,\n): Promise<CompilationResult> {\n return withCatalogueSeatedFor(projectDir, async () => {\n const { allSkills } = await discoverInstalledSkills(projectDir);\n const { sourcePath } = await loadAgentDefs();\n\n return compileAgents({\n projectDir,\n sourcePath,\n skills: allSkills,\n scopeFilter: \"project\",\n outputDir: resolveInstallPaths(projectDir, \"project\").agentsDir,\n });\n });\n}\n\nexport type PropagatedRecompileSummary = {\n /** Projects where at least one compiled agent's content actually moved. */\n rewrittenCount: number;\n /**\n * Projects the fan-out reached whose agents all came back byte-identical. They\n * were visited and left alone, which is a different fact from being recompiled\n * and the one the old single count could not tell apart.\n */\n unchangedCount: number;\n failedCount: number;\n /** Per-project warnings in processing order — the caller surfaces them via warn(). */\n warnings: string[];\n};\n\n/**\n * Runs {@link recompileRegisteredProjectAgents} over every propagated project,\n * isolating per-project failures: one project's unreadable config or broken\n * template must not abort the loop or leave the remaining projects stale.\n * Projects are processed sequentially so the collected warnings keep a\n * deterministic per-project order.\n */\nexport async function recompilePropagatedProjectAgents(\n projectDirs: string[],\n): Promise<PropagatedRecompileSummary> {\n let rewrittenCount = 0;\n let unchangedCount = 0;\n let failedCount = 0;\n const warnings: string[] = [];\n\n for (const dir of projectDirs) {\n try {\n const result = await recompileRegisteredProjectAgents(dir);\n if (result.failed.length > 0) {\n failedCount++;\n warnings.push(...result.warnings);\n continue;\n }\n if (result.rewritten.length > 0) rewrittenCount++;\n else unchangedCount++;\n } catch (error) {\n failedCount++;\n warnings.push(`Could not recompile agents in ${dir}: ${getErrorMessage(error)}`);\n }\n }\n\n return { rewrittenCount, unchangedCount, failedCount, warnings };\n}\n"],"mappings":"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","names":["skillsDir"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/hooks/use-keyboard-navigation.ts"],"sourcesContent":["import type { Dispatch, SetStateAction } from \"react\";\nimport { useState, useCallback, useRef } from \"react\";\nimport { useInput, type Key } from \"ink\";\n\ntype KeyboardNavigationHandlers = {\n onEnter?: (focusedIndex: number) => void;\n onEscape?: () => void;\n};\n\ntype KeyboardNavigationOptions = {\n wrap?: boolean;\n vimKeys?: boolean;\n active?: boolean;\n};\n\nexport function useKeyboardNavigation(\n itemCount: number,\n handlers: KeyboardNavigationHandlers = {},\n options: KeyboardNavigationOptions = {},\n): {\n focusedIndex: number;\n setFocusedIndex: Dispatch<SetStateAction<number>>;\n} {\n const { onEnter, onEscape } = handlers;\n const { wrap = true, vimKeys = true, active = true } = options;\n\n const [focusedIndex, setRenderedIndex] = useState(0);\n // The focus the handlers read, written the moment it moves rather than once the move renders.\n // Keys that arrive in one chunk — a fast typist, a paste — are handled one after another with no\n // render between them, so a copy synced by an effect still held the focus from before the burst\n // when Enter read it: Down, Down, Enter on the dashboard ran Edit.\n const focusedIndexRef = useRef(focusedIndex);\n\n const setFocusedIndex = useCallback<Dispatch<SetStateAction<number>>>((action) => {\n const next = typeof action === \"function\" ? action(focusedIndexRef.current) : action;\n focusedIndexRef.current = next;\n setRenderedIndex(next);\n }, []);\n\n const moveUp = useCallback(() => {\n setFocusedIndex((prev) => {\n if (wrap) {\n return (prev - 1 + itemCount) % itemCount;\n }\n return Math.max(0, prev - 1);\n });\n }, [itemCount, wrap, setFocusedIndex]);\n\n const moveDown = useCallback(() => {\n setFocusedIndex((prev) => {\n if (wrap) {\n return (prev + 1) % itemCount;\n }\n return Math.min(itemCount - 1, prev + 1);\n });\n }, [itemCount, wrap, setFocusedIndex]);\n\n useInput(\n useCallback(\n (input: string, key: Key) => {\n if (key.escape) {\n onEscape?.();\n return;\n }\n\n if (key.return) {\n onEnter?.(focusedIndexRef.current);\n return;\n }\n\n if (key.upArrow || (vimKeys && input === \"k\")) {\n moveUp();\n return;\n }\n\n if (key.downArrow || (vimKeys && input === \"j\")) {\n moveDown();\n }\n },\n [onEnter, onEscape, vimKeys, moveUp, moveDown],\n ),\n { isActive: active },\n );\n\n return { focusedIndex, setFocusedIndex };\n}\n"],"mappings":";;;AACA,SAAS,UAAU,aAAa,cAAc;AAC9C,SAAS,gBAA0B;AAa5B,SAAS,sBACd,WACA,WAAuC,CAAC,GACxC,UAAqC,CAAC,GAItC;AACA,QAAM,EAAE,SAAS,SAAS,IAAI;AAC9B,QAAM,EAAE,OAAO,MAAM,UAAU,MAAM,SAAS,KAAK,IAAI;AAEvD,QAAM,CAAC,cAAc,gBAAgB,IAAI,SAAS,CAAC;AAKnD,QAAM,kBAAkB,OAAO,YAAY;AAE3C,QAAM,kBAAkB,YAA8C,CAAC,WAAW;AAChF,UAAM,OAAO,OAAO,WAAW,aAAa,OAAO,gBAAgB,OAAO,IAAI;AAC9E,oBAAgB,UAAU;AAC1B,qBAAiB,IAAI;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,QAAM,SAAS,YAAY,MAAM;AAC/B,oBAAgB,CAAC,SAAS;AACxB,UAAI,MAAM;AACR,gBAAQ,OAAO,IAAI,aAAa;AAAA,MAClC;AACA,aAAO,KAAK,IAAI,GAAG,OAAO,CAAC;AAAA,IAC7B,CAAC;AAAA,EACH,GAAG,CAAC,WAAW,MAAM,eAAe,CAAC;AAErC,QAAM,WAAW,YAAY,MAAM;AACjC,oBAAgB,CAAC,SAAS;AACxB,UAAI,MAAM;AACR,gBAAQ,OAAO,KAAK;AAAA,MACtB;AACA,aAAO,KAAK,IAAI,YAAY,GAAG,OAAO,CAAC;AAAA,IACzC,CAAC;AAAA,EACH,GAAG,CAAC,WAAW,MAAM,eAAe,CAAC;AAErC;AAAA,IACE;AAAA,MACE,CAAC,OAAe,QAAa;AAC3B,YAAI,IAAI,QAAQ;AACd,qBAAW;AACX;AAAA,QACF;AAEA,YAAI,IAAI,QAAQ;AACd,oBAAU,gBAAgB,OAAO;AACjC;AAAA,QACF;AAEA,YAAI,IAAI,WAAY,WAAW,UAAU,KAAM;AAC7C,iBAAO;AACP;AAAA,QACF;AAEA,YAAI,IAAI,aAAc,WAAW,UAAU,KAAM;AAC/C,mBAAS;AAAA,QACX;AAAA,MACF;AAAA,MACA,CAAC,SAAS,UAAU,SAAS,QAAQ,QAAQ;AAAA,IAC/C;AAAA,IACA,EAAE,UAAU,OAAO;AAAA,EACrB;AAEA,SAAO,EAAE,cAAc,gBAAgB;AACzC;","names":[]}
@@ -1,118 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- useRowScroll
4
- } from "./chunk-TTY6DPJN.js";
5
- import {
6
- KEY_SPACE
7
- } from "./chunk-WTJ3AY33.js";
8
- import {
9
- CLI_COLORS,
10
- UI_SYMBOLS
11
- } from "./chunk-ENGYJCTF.js";
12
-
13
- // src/cli/components/wizard/checkbox-grid.tsx
14
- import { Box, Text, useInput } from "ink";
15
- import { useRef, useState } from "react";
16
- import { jsx, jsxs } from "react/jsx-runtime";
17
- var CheckboxGrid = ({
18
- subtitle,
19
- items,
20
- selectedIds,
21
- availableHeight = 0,
22
- onToggle,
23
- onContinue,
24
- onBack,
25
- emptyMessage = "Please select at least one item"
26
- }) => {
27
- const totalItems = items.length + 1;
28
- const [focusedIndex, setRenderedIndex] = useState(0);
29
- const focusedIndexRef = useRef(focusedIndex);
30
- const focus = (index) => {
31
- focusedIndexRef.current = index;
32
- setRenderedIndex(index);
33
- };
34
- useInput((input, key) => {
35
- if (key.escape) {
36
- onBack();
37
- return;
38
- }
39
- if (key.upArrow || input === "k") {
40
- const prev = focusedIndexRef.current;
41
- focus(prev <= 0 ? totalItems - 1 : prev - 1);
42
- return;
43
- }
44
- if (key.downArrow || input === "j") {
45
- const prev = focusedIndexRef.current;
46
- focus(prev >= totalItems - 1 ? 0 : prev + 1);
47
- return;
48
- }
49
- if (key.return) {
50
- onContinue();
51
- return;
52
- }
53
- if (input === KEY_SPACE) {
54
- const item = items[focusedIndexRef.current];
55
- if (item) {
56
- onToggle(item.id);
57
- }
58
- }
59
- });
60
- const effectiveRow = focusedIndex >= items.length ? items.length - 1 : focusedIndex;
61
- const { scrollEnabled, scrollTop } = useRowScroll({
62
- focusedIndex: effectiveRow,
63
- itemCount: items.length,
64
- availableHeight
65
- });
66
- const itemElements = items.map((item, index) => {
67
- const isFocused = index === focusedIndex;
68
- const isSelected = selectedIds.includes(item.id);
69
- const checkbox = isSelected ? "[\u2713]" : "[ ]";
70
- const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;
71
- return /* @__PURE__ */ jsxs(Text, { children: [
72
- /* @__PURE__ */ jsx(Text, { ...isFocused && { color: CLI_COLORS.PRIMARY }, children: pointer }),
73
- /* @__PURE__ */ jsxs(Text, { ...(isSelected || isFocused) && { color: CLI_COLORS.PRIMARY }, bold: isFocused, children: [
74
- " ",
75
- checkbox,
76
- " ",
77
- item.label
78
- ] }),
79
- item.description && /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
80
- " ",
81
- item.description
82
- ] })
83
- ] }, item.id);
84
- });
85
- const footerElement = selectedIds.length > 0 ? /* @__PURE__ */ jsxs(Text, { children: [
86
- "\n",
87
- "Selected: ",
88
- /* @__PURE__ */ jsx(Text, { color: CLI_COLORS.WARNING, children: selectedIds.join(", ") })
89
- ] }) : emptyMessage ? /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
90
- "\n",
91
- emptyMessage
92
- ] }) : null;
93
- return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", children: [
94
- subtitle && /* @__PURE__ */ jsx(Text, { dimColor: true, children: subtitle }),
95
- /* @__PURE__ */ jsx(
96
- Box,
97
- {
98
- flexDirection: "column",
99
- ...scrollEnabled && { height: availableHeight, overflow: "hidden" },
100
- children: /* @__PURE__ */ jsx(
101
- Box,
102
- {
103
- flexDirection: "column",
104
- marginTop: scrollTop > 0 ? -scrollTop : 0,
105
- ...scrollEnabled && { flexShrink: 0 },
106
- children: itemElements
107
- }
108
- )
109
- }
110
- ),
111
- footerElement
112
- ] });
113
- };
114
-
115
- export {
116
- CheckboxGrid
117
- };
118
- //# sourceMappingURL=chunk-JQRJQ4SS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/checkbox-grid.tsx"],"sourcesContent":["import { Box, Text, useInput } from \"ink\";\nimport React, { useRef, useState } from \"react\";\nimport { CLI_COLORS, UI_SYMBOLS } from \"../../consts.js\";\nimport { useRowScroll } from \"../hooks/use-row-scroll.js\";\nimport { KEY_SPACE } from \"./hotkeys.js\";\n\nexport type CheckboxItem<T extends string = string> = {\n id: T;\n label: string;\n description: string;\n};\n\nexport type CheckboxGridProps<T extends string = string> = {\n subtitle?: string;\n items: CheckboxItem<T>[];\n selectedIds: T[];\n /** Available height in terminal lines for the scrollable viewport. 0 = no constraint. */\n availableHeight?: number;\n onToggle: (id: T) => void;\n onContinue: () => void;\n onBack: () => void;\n /** Message shown when nothing is selected */\n emptyMessage?: string;\n};\n\nexport const CheckboxGrid = <T extends string = string>({\n subtitle,\n items,\n selectedIds,\n availableHeight = 0,\n onToggle,\n onContinue,\n onBack,\n emptyMessage = \"Please select at least one item\",\n}: CheckboxGridProps<T>): React.ReactElement => {\n // Items + continue option at the end\n const totalItems = items.length + 1;\n const [focusedIndex, setRenderedIndex] = useState(0);\n // The focus Space reads, written the moment it moves rather than once the move renders: a Space\n // that follows a move in the same chunk is handled before that move renders.\n const focusedIndexRef = useRef(focusedIndex);\n\n const focus = (index: number): void => {\n focusedIndexRef.current = index;\n setRenderedIndex(index);\n };\n\n useInput((input, key) => {\n if (key.escape) {\n onBack();\n return;\n }\n\n if (key.upArrow || input === \"k\") {\n const prev = focusedIndexRef.current;\n focus(prev <= 0 ? totalItems - 1 : prev - 1);\n return;\n }\n\n if (key.downArrow || input === \"j\") {\n const prev = focusedIndexRef.current;\n focus(prev >= totalItems - 1 ? 0 : prev + 1);\n return;\n }\n\n if (key.return) {\n onContinue();\n return;\n }\n\n if (input === KEY_SPACE) {\n const item = items[focusedIndexRef.current];\n if (item) {\n onToggle(item.id);\n }\n }\n });\n\n // The Domains grid clips silently: `useRowScroll` exposes no hidden-line\n // counts and this view renders no `ScrollAffordance`, by owner decision — see\n // the hook's doc comment.\n // When focus is on continue (past items), scroll to show last items\n const effectiveRow = focusedIndex >= items.length ? items.length - 1 : focusedIndex;\n const { scrollEnabled, scrollTop } = useRowScroll({\n focusedIndex: effectiveRow,\n itemCount: items.length,\n availableHeight,\n });\n\n const itemElements = items.map((item, index) => {\n const isFocused = index === focusedIndex;\n const isSelected = selectedIds.includes(item.id);\n const checkbox = isSelected ? \"[\\u2713]\" : \"[ ]\";\n const pointer = isFocused ? UI_SYMBOLS.CHEVRON : UI_SYMBOLS.CHEVRON_SPACER;\n\n return (\n <Text key={item.id}>\n <Text {...(isFocused && { color: CLI_COLORS.PRIMARY })}>{pointer}</Text>\n <Text {...((isSelected || isFocused) && { color: CLI_COLORS.PRIMARY })} bold={isFocused}>\n {\" \"}\n {checkbox} {item.label}\n </Text>\n {item.description && (\n <Text dimColor>\n {\" \"}\n {item.description}\n </Text>\n )}\n </Text>\n );\n });\n\n const footerElement =\n selectedIds.length > 0 ? (\n <Text>\n {\"\\n\"}Selected: <Text color={CLI_COLORS.WARNING}>{selectedIds.join(\", \")}</Text>\n </Text>\n ) : emptyMessage ? (\n <Text dimColor>\n {\"\\n\"}\n {emptyMessage}\n </Text>\n ) : null;\n\n return (\n <Box flexDirection=\"column\">\n {subtitle && <Text dimColor>{subtitle}</Text>}\n <Box\n flexDirection=\"column\"\n {...(scrollEnabled && { height: availableHeight, overflow: \"hidden\" as const })}\n >\n <Box\n flexDirection=\"column\"\n marginTop={scrollTop > 0 ? -scrollTop : 0}\n {...(scrollEnabled && { flexShrink: 0 })}\n >\n {itemElements}\n </Box>\n </Box>\n {footerElement}\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,KAAK,MAAM,gBAAgB;AACpC,SAAgB,QAAQ,gBAAgB;AAgGhC,cACA,YADA;AAxED,IAAM,eAAe,CAA4B;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA,kBAAkB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,MAAgD;AAE9C,QAAM,aAAa,MAAM,SAAS;AAClC,QAAM,CAAC,cAAc,gBAAgB,IAAI,SAAS,CAAC;AAGnD,QAAM,kBAAkB,OAAO,YAAY;AAE3C,QAAM,QAAQ,CAAC,UAAwB;AACrC,oBAAgB,UAAU;AAC1B,qBAAiB,KAAK;AAAA,EACxB;AAEA,WAAS,CAAC,OAAO,QAAQ;AACvB,QAAI,IAAI,QAAQ;AACd,aAAO;AACP;AAAA,IACF;AAEA,QAAI,IAAI,WAAW,UAAU,KAAK;AAChC,YAAM,OAAO,gBAAgB;AAC7B,YAAM,QAAQ,IAAI,aAAa,IAAI,OAAO,CAAC;AAC3C;AAAA,IACF;AAEA,QAAI,IAAI,aAAa,UAAU,KAAK;AAClC,YAAM,OAAO,gBAAgB;AAC7B,YAAM,QAAQ,aAAa,IAAI,IAAI,OAAO,CAAC;AAC3C;AAAA,IACF;AAEA,QAAI,IAAI,QAAQ;AACd,iBAAW;AACX;AAAA,IACF;AAEA,QAAI,UAAU,WAAW;AACvB,YAAM,OAAO,MAAM,gBAAgB,OAAO;AAC1C,UAAI,MAAM;AACR,iBAAS,KAAK,EAAE;AAAA,MAClB;AAAA,IACF;AAAA,EACF,CAAC;AAMD,QAAM,eAAe,gBAAgB,MAAM,SAAS,MAAM,SAAS,IAAI;AACvE,QAAM,EAAE,eAAe,UAAU,IAAI,aAAa;AAAA,IAChD,cAAc;AAAA,IACd,WAAW,MAAM;AAAA,IACjB;AAAA,EACF,CAAC;AAED,QAAM,eAAe,MAAM,IAAI,CAAC,MAAM,UAAU;AAC9C,UAAM,YAAY,UAAU;AAC5B,UAAM,aAAa,YAAY,SAAS,KAAK,EAAE;AAC/C,UAAM,WAAW,aAAa,aAAa;AAC3C,UAAM,UAAU,YAAY,WAAW,UAAU,WAAW;AAE5D,WACE,qBAAC,QACC;AAAA,0BAAC,QAAM,GAAI,aAAa,EAAE,OAAO,WAAW,QAAQ,GAAK,mBAAQ;AAAA,MACjE,qBAAC,QAAM,IAAK,cAAc,cAAc,EAAE,OAAO,WAAW,QAAQ,GAAI,MAAM,WAC3E;AAAA;AAAA,QACA;AAAA,QAAS;AAAA,QAAE,KAAK;AAAA,SACnB;AAAA,MACC,KAAK,eACJ,qBAAC,QAAK,UAAQ,MACX;AAAA;AAAA,QACA,KAAK;AAAA,SACR;AAAA,SAVO,KAAK,EAYhB;AAAA,EAEJ,CAAC;AAED,QAAM,gBACJ,YAAY,SAAS,IACnB,qBAAC,QACE;AAAA;AAAA,IAAK;AAAA,IAAU,oBAAC,QAAK,OAAO,WAAW,SAAU,sBAAY,KAAK,IAAI,GAAE;AAAA,KAC3E,IACE,eACF,qBAAC,QAAK,UAAQ,MACX;AAAA;AAAA,IACA;AAAA,KACH,IACE;AAEN,SACE,qBAAC,OAAI,eAAc,UAChB;AAAA,gBAAY,oBAAC,QAAK,UAAQ,MAAE,oBAAS;AAAA,IACtC;AAAA,MAAC;AAAA;AAAA,QACC,eAAc;AAAA,QACb,GAAI,iBAAiB,EAAE,QAAQ,iBAAiB,UAAU,SAAkB;AAAA,QAE7E;AAAA,UAAC;AAAA;AAAA,YACC,eAAc;AAAA,YACd,WAAW,YAAY,IAAI,CAAC,YAAY;AAAA,YACvC,GAAI,iBAAiB,EAAE,YAAY,EAAE;AAAA,YAErC;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,IACC;AAAA,KACH;AAEJ;","names":[]}
@@ -1,59 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- getDomainDisplayName
4
- } from "./chunk-QHDPLLK6.js";
5
- import {
6
- CheckboxGrid
7
- } from "./chunk-JQRJQ4SS.js";
8
- import {
9
- useWizardStore
10
- } from "./chunk-7JNJ52CD.js";
11
- import {
12
- matrix,
13
- typedEntries
14
- } from "./chunk-V5WXIM2F.js";
15
- import {
16
- DOMAIN_DESCRIPTIONS,
17
- orderDomains
18
- } from "./chunk-ENGYJCTF.js";
19
-
20
- // src/cli/components/wizard/domain-selection.tsx
21
- import { useMemo } from "react";
22
- import { unique } from "remeda";
23
- import { jsx } from "react/jsx-runtime";
24
- var DomainSelection = () => {
25
- const { selectedDomains, toggleDomain, setStep, setApproach, selectStack, goBack, history } = useWizardStore();
26
- const availableDomains = useMemo(() => {
27
- const matrixDomains = unique(
28
- typedEntries(matrix.categories).map(([, cat]) => cat?.domain).filter((d) => d != null)
29
- );
30
- const ordered = orderDomains(matrixDomains);
31
- return ordered.map((domain) => ({
32
- id: domain,
33
- label: getDomainDisplayName(domain),
34
- description: DOMAIN_DESCRIPTIONS[domain]
35
- }));
36
- }, []);
37
- const handleBack = () => {
38
- if (history.length === 0) return;
39
- setApproach(null);
40
- selectStack(null);
41
- goBack();
42
- };
43
- return /* @__PURE__ */ jsx(
44
- CheckboxGrid,
45
- {
46
- items: availableDomains,
47
- selectedIds: selectedDomains,
48
- onToggle: toggleDomain,
49
- onContinue: () => setStep("build"),
50
- onBack: handleBack,
51
- emptyMessage: "Please select at least one domain"
52
- }
53
- );
54
- };
55
-
56
- export {
57
- DomainSelection
58
- };
59
- //# sourceMappingURL=chunk-LFWLEDUG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/domain-selection.tsx"],"sourcesContent":["import { DOMAIN_DESCRIPTIONS } from \"@workspace/matrix\";\nimport React, { useMemo } from \"react\";\nimport { unique } from \"remeda\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { matrix } from \"../../lib/matrix/matrix-provider.js\";\nimport type { Domain } from \"../../types/index.js\";\nimport { typedEntries } from \"../../utils/typed-object.js\";\nimport { CheckboxGrid, type CheckboxItem } from \"./checkbox-grid.js\";\nimport { getDomainDisplayName, orderDomains } from \"./utils.js\";\n\nexport const DomainSelection: React.FC = () => {\n const { selectedDomains, toggleDomain, setStep, setApproach, selectStack, goBack, history } =\n useWizardStore();\n\n const availableDomains = useMemo((): CheckboxItem<Domain>[] => {\n const matrixDomains = unique(\n typedEntries(matrix.categories)\n // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- typedEntries/Object.entries launders the `| undefined` a Partial<Record> admits out of its result type, so this guard reads as dead while still covering an explicitly-undefined slot\n .map(([, cat]) => cat?.domain)\n .filter((d): d is Domain => d != null),\n );\n\n const ordered = orderDomains(matrixDomains);\n\n return ordered.map((domain) => ({\n id: domain,\n label: getDomainDisplayName(domain),\n description: DOMAIN_DESCRIPTIONS[domain],\n }));\n // `matrix` is a module-level value, not reactive state — mutating it never\n // re-renders anything, so listing it promised a recomputation that cannot\n // happen. It is initialised once before the wizard mounts.\n }, []);\n\n // Going back means going back to the stack choice, so it clears the choice on\n // the way. When this step is the wizard's first — a source offering no stacks\n // has no stack step to return to — there is no choice to clear and nowhere to\n // go, and clearing anyway would wipe the selections in place.\n const handleBack = () => {\n if (history.length === 0) return;\n setApproach(null);\n selectStack(null);\n goBack();\n };\n\n return (\n <CheckboxGrid\n items={availableDomains}\n selectedIds={selectedDomains}\n onToggle={toggleDomain}\n onContinue={() => setStep(\"build\")}\n onBack={handleBack}\n emptyMessage=\"Please select at least one domain\"\n />\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,SAAgB,eAAe;AAC/B,SAAS,cAAc;AA4CnB;AApCG,IAAM,kBAA4B,MAAM;AAC7C,QAAM,EAAE,iBAAiB,cAAc,SAAS,aAAa,aAAa,QAAQ,QAAQ,IACxF,eAAe;AAEjB,QAAM,mBAAmB,QAAQ,MAA8B;AAC7D,UAAM,gBAAgB;AAAA,MACpB,aAAa,OAAO,UAAU,EAE3B,IAAI,CAAC,CAAC,EAAE,GAAG,MAAM,KAAK,MAAM,EAC5B,OAAO,CAAC,MAAmB,KAAK,IAAI;AAAA,IACzC;AAEA,UAAM,UAAU,aAAa,aAAa;AAE1C,WAAO,QAAQ,IAAI,CAAC,YAAY;AAAA,MAC9B,IAAI;AAAA,MACJ,OAAO,qBAAqB,MAAM;AAAA,MAClC,aAAa,oBAAoB,MAAM;AAAA,IACzC,EAAE;AAAA,EAIJ,GAAG,CAAC,CAAC;AAML,QAAM,aAAa,MAAM;AACvB,QAAI,QAAQ,WAAW,EAAG;AAC1B,gBAAY,IAAI;AAChB,gBAAY,IAAI;AAChB,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,MACP,aAAa;AAAA,MACb,UAAU;AAAA,MACV,YAAY,MAAM,QAAQ,OAAO;AAAA,MACjC,QAAQ;AAAA,MACR,cAAa;AAAA;AAAA,EACf;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/skill-agent-summary.tsx"],"sourcesContent":["import { Box, Text } from \"ink\";\nimport React from \"react\";\nimport { CLI_COLORS, EJECT_SOURCE, UI_SYMBOLS } from \"../../consts.js\";\nimport { getSkillDisplayName } from \"../../lib/matrix/matrix-provider.js\";\nimport { computeScopeDiff } from \"../../lib/wizard/index.js\";\nimport type { AgentDiffRow, DiffRowStatus, SkillDiffRow } from \"../../lib/wizard/index.js\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config.js\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\n\nexport type SkillAgentSummaryProps = {\n skillConfigs: SkillConfig[];\n agentConfigs: AgentScopeConfig[];\n};\n\nconst TableHeader: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n <Text bold color={CLI_COLORS.WARNING}>\n {children}\n </Text>\n);\n\nconst ScopeLabel: React.FC<{ children: string }> = ({ children }) => (\n <Text color={CLI_COLORS.WHITE} backgroundColor={CLI_COLORS.LABEL_BG}>\n {` ${children} `}\n </Text>\n);\n\nconst EjectIcon: React.FC = () => <Text color={CLI_COLORS.WARNING}> {UI_SYMBOLS.EJECT}</Text>;\n\nconst DIFF_PREFIX: Record<DiffRowStatus, string> = {\n added: `${UI_SYMBOLS.ADDED} `,\n \"mode-changed\": \"~ \",\n removed: `${UI_SYMBOLS.REMOVED} `,\n unchanged: `${UI_SYMBOLS.BULLET} `,\n};\n\nconst DIFF_COLOR: Record<DiffRowStatus, string> = {\n added: CLI_COLORS.SUCCESS,\n \"mode-changed\": CLI_COLORS.WARNING,\n removed: CLI_COLORS.ERROR,\n unchanged: CLI_COLORS.NEUTRAL,\n};\n\nconst SkillRow: React.FC<{ row: SkillDiffRow }> = ({ row }) => (\n <Box width=\"50%\" flexDirection=\"row\">\n <Text color={DIFF_COLOR[row.status]}>\n {DIFF_PREFIX[row.status]}\n {getSkillDisplayName(row.id)}\n </Text>\n {row.source === EJECT_SOURCE && <EjectIcon />}\n </Box>\n);\n\nconst AgentRow: React.FC<{ row: AgentDiffRow }> = ({ row }) => (\n <Text color={DIFF_COLOR[row.status]}>\n {DIFF_PREFIX[row.status]}\n {row.name}\n </Text>\n);\n\nconst skillRowKey = (row: SkillDiffRow): string =>\n row.status === \"removed\" ? `removed-${row.id}` : row.id;\n\nconst agentRowKey = (row: AgentDiffRow): string =>\n row.status === \"removed\" ? `removed-${row.name}` : row.name;\n\nexport const SkillAgentSummary: React.FC<SkillAgentSummaryProps> = ({\n skillConfigs,\n agentConfigs,\n}) => {\n const installedSkillConfigs = useWizardStore((s) => s.installedSkillConfigs);\n const installedAgentConfigs = useWizardStore((s) => s.installedAgentConfigs);\n const isInitMode = useWizardStore((s) => s.isInitMode);\n\n const diff = computeScopeDiff({\n currentSkills: skillConfigs,\n currentAgents: agentConfigs,\n installedSkillConfigs,\n installedAgentConfigs,\n isInitMode,\n });\n\n if (!diff.hasContent) return null;\n\n return (\n <Box flexDirection=\"row\" width=\"100%\">\n <Box\n flexDirection=\"column\"\n borderStyle=\"single\"\n flexGrow={2}\n flexBasis={0}\n borderRight={true}\n borderTop={false}\n borderBottom={false}\n borderLeft={false}\n borderColor={CLI_COLORS.NEUTRAL}\n borderRightDimColor\n >\n <TableHeader>Skills</TableHeader>\n {diff.projectSkillRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Project</ScopeLabel>\n <Box flexWrap=\"wrap\">\n {diff.projectSkillRows.map((row) => (\n <SkillRow key={skillRowKey(row)} row={row} />\n ))}\n </Box>\n </Box>\n )}\n {diff.globalSkillRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Global</ScopeLabel>\n <Box flexWrap=\"wrap\">\n {diff.globalSkillRows.map((row) => (\n <SkillRow key={skillRowKey(row)} row={row} />\n ))}\n </Box>\n </Box>\n )}\n </Box>\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0} marginLeft={1} paddingLeft={1}>\n <TableHeader>Agents</TableHeader>\n {diff.projectAgentRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Project</ScopeLabel>\n <Box flexDirection=\"column\">\n {diff.projectAgentRows.map((row) => (\n <AgentRow key={agentRowKey(row)} row={row} />\n ))}\n </Box>\n </Box>\n )}\n {diff.globalAgentRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Global</ScopeLabel>\n <Box flexDirection=\"column\">\n {diff.globalAgentRows.map((row) => (\n <AgentRow key={agentRowKey(row)} row={row} />\n ))}\n </Box>\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n"],"mappings":"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","names":[]}
@@ -1,92 +0,0 @@
1
- #!/usr/bin/env node
2
- import {
3
- useMeasuredHeight
4
- } from "./chunk-TSIU7DME.js";
5
- import {
6
- CategoryGrid
7
- } from "./chunk-SXVHSOTH.js";
8
- import {
9
- buildCategoriesForDomain,
10
- useWizardStore
11
- } from "./chunk-7JNJ52CD.js";
12
-
13
- // src/cli/components/wizard/step-build.tsx
14
- import { Box, useInput } from "ink";
15
- import { useCallback, useMemo as useMemo2 } from "react";
16
-
17
- // src/cli/components/hooks/use-category-rows.ts
18
- import { useMemo } from "react";
19
- function useCategoryRows({
20
- domain,
21
- allSelections,
22
- installedSkillIds,
23
- skillConfigs
24
- }) {
25
- return useMemo(
26
- () => buildCategoriesForDomain(domain, allSelections, installedSkillIds, skillConfigs),
27
- [domain, allSelections, installedSkillIds, skillConfigs]
28
- );
29
- }
30
-
31
- // src/cli/components/wizard/step-build.tsx
32
- import { jsx } from "react/jsx-runtime";
33
- var StepBuild = ({
34
- domain: activeDomain,
35
- allSelections,
36
- showLabels,
37
- installedSkillIds,
38
- onToggle,
39
- onToggleLabels,
40
- onContinue,
41
- onBack
42
- }) => {
43
- const { ref: gridRef, measuredHeight: gridHeight } = useMeasuredHeight();
44
- const skillConfigs = useWizardStore((s) => s.skillConfigs);
45
- const handleFocusedSkillChange = useCallback(
46
- (id) => useWizardStore.getState().setFocusedSkillId(id),
47
- []
48
- );
49
- const categories = useCategoryRows({
50
- domain: activeDomain,
51
- allSelections,
52
- ...installedSkillIds !== void 0 && { installedSkillIds },
53
- skillConfigs
54
- });
55
- const { initialRow, initialCol } = useMemo2(() => {
56
- const skillId = useWizardStore.getState().focusedSkillId;
57
- if (!skillId) return { initialRow: 0, initialCol: 0 };
58
- const row = categories.findIndex((cat) => cat.options.some((o) => o.id === skillId));
59
- const focusedCategory = categories[row];
60
- if (!focusedCategory) return { initialRow: 0, initialCol: 0 };
61
- return {
62
- initialRow: row,
63
- initialCol: focusedCategory.options.findIndex((o) => o.id === skillId)
64
- };
65
- }, [categories]);
66
- useInput((_input, key) => {
67
- if (key.return) {
68
- onContinue();
69
- } else if (key.escape) {
70
- onBack();
71
- }
72
- });
73
- return /* @__PURE__ */ jsx(Box, { flexDirection: "column", width: "100%", flexGrow: 1, flexBasis: 0, children: /* @__PURE__ */ jsx(Box, { ref: gridRef, flexGrow: 1, flexBasis: 0, children: /* @__PURE__ */ jsx(
74
- CategoryGrid,
75
- {
76
- categories,
77
- availableHeight: gridHeight,
78
- showLabels,
79
- defaultFocusedRow: initialRow,
80
- defaultFocusedCol: initialCol,
81
- onToggle,
82
- onToggleLabels,
83
- onFocusedSkillChange: handleFocusedSkillChange
84
- },
85
- activeDomain
86
- ) }) });
87
- };
88
-
89
- export {
90
- StepBuild
91
- };
92
- //# sourceMappingURL=chunk-MPTNC32T.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/components/wizard/step-build.tsx","../src/cli/components/hooks/use-category-rows.ts"],"sourcesContent":["import { Box, useInput } from \"ink\";\nimport React, { useCallback, useMemo } from \"react\";\nimport type { Domain, SkillId, Category } from \"../../types/index.js\";\nimport { useCategoryRows } from \"../hooks/use-category-rows.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport { CategoryGrid } from \"./category-grid.js\";\n\nexport type StepBuildProps = {\n domain: Domain;\n selectedDomains: Domain[];\n allSelections: SkillId[];\n showLabels: boolean;\n /** Skill IDs already installed on disk, shown with a dimmed checkmark */\n installedSkillIds?: SkillId[] | undefined;\n onToggle: (categoryId: Category, technologyId: SkillId) => void;\n onToggleLabels: () => void;\n onContinue: () => void;\n onBack: () => void;\n};\n\nexport const StepBuild: React.FC<StepBuildProps> = ({\n domain: activeDomain,\n allSelections,\n showLabels,\n installedSkillIds,\n onToggle,\n onToggleLabels,\n onContinue,\n onBack,\n}) => {\n const { ref: gridRef, measuredHeight: gridHeight } = useMeasuredHeight();\n const skillConfigs = useWizardStore((s) => s.skillConfigs);\n\n const handleFocusedSkillChange = useCallback(\n (id: SkillId | null) => useWizardStore.getState().setFocusedSkillId(id),\n [],\n );\n\n const categories = useCategoryRows({\n domain: activeDomain,\n allSelections,\n ...(installedSkillIds !== undefined && { installedSkillIds }),\n skillConfigs,\n });\n\n const { initialRow, initialCol } = useMemo(() => {\n const skillId = useWizardStore.getState().focusedSkillId;\n if (!skillId) return { initialRow: 0, initialCol: 0 };\n const row = categories.findIndex((cat) => cat.options.some((o) => o.id === skillId));\n const focusedCategory = categories[row];\n if (!focusedCategory) return { initialRow: 0, initialCol: 0 };\n return {\n initialRow: row,\n initialCol: focusedCategory.options.findIndex((o) => o.id === skillId),\n };\n }, [categories]);\n\n useInput((_input, key) => {\n if (key.return) {\n onContinue();\n } else if (key.escape) {\n onBack();\n }\n });\n\n return (\n <Box flexDirection=\"column\" width=\"100%\" flexGrow={1} flexBasis={0}>\n <Box ref={gridRef} flexGrow={1} flexBasis={0}>\n <CategoryGrid\n key={activeDomain}\n categories={categories}\n availableHeight={gridHeight}\n showLabels={showLabels}\n defaultFocusedRow={initialRow}\n defaultFocusedCol={initialCol}\n onToggle={onToggle}\n onToggleLabels={onToggleLabels}\n onFocusedSkillChange={handleFocusedSkillChange}\n />\n </Box>\n </Box>\n );\n};\n","import { useMemo } from \"react\";\nimport type { Domain, SkillId } from \"../../types/index.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport { buildCategoriesForDomain } from \"../../lib/wizard/index.js\";\nimport type { CategoryRow } from \"../wizard/category-grid.js\";\n\ntype UseCategoryRowsOptions = {\n domain: Domain;\n allSelections: SkillId[];\n installedSkillIds?: SkillId[];\n skillConfigs?: SkillConfig[];\n};\n\n/** The build-step grid's rows for `domain`, rebuilt only when an input changes. */\nexport function useCategoryRows({\n domain,\n allSelections,\n installedSkillIds,\n skillConfigs,\n}: UseCategoryRowsOptions): CategoryRow[] {\n return useMemo(\n () => buildCategoriesForDomain(domain, allSelections, installedSkillIds, skillConfigs),\n [domain, allSelections, installedSkillIds, skillConfigs],\n );\n}\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,KAAK,gBAAgB;AAC9B,SAAgB,aAAa,WAAAA,gBAAe;;;ACD5C,SAAS,eAAe;AAcjB,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0C;AACxC,SAAO;AAAA,IACL,MAAM,yBAAyB,QAAQ,eAAe,mBAAmB,YAAY;AAAA,IACrF,CAAC,QAAQ,eAAe,mBAAmB,YAAY;AAAA,EACzD;AACF;;;AD6CQ;AAhDD,IAAM,YAAsC,CAAC;AAAA,EAClD,QAAQ;AAAA,EACR;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MAAM;AACJ,QAAM,EAAE,KAAK,SAAS,gBAAgB,WAAW,IAAI,kBAAkB;AACvE,QAAM,eAAe,eAAe,CAAC,MAAM,EAAE,YAAY;AAEzD,QAAM,2BAA2B;AAAA,IAC/B,CAAC,OAAuB,eAAe,SAAS,EAAE,kBAAkB,EAAE;AAAA,IACtE,CAAC;AAAA,EACH;AAEA,QAAM,aAAa,gBAAgB;AAAA,IACjC,QAAQ;AAAA,IACR;AAAA,IACA,GAAI,sBAAsB,UAAa,EAAE,kBAAkB;AAAA,IAC3D;AAAA,EACF,CAAC;AAED,QAAM,EAAE,YAAY,WAAW,IAAIC,SAAQ,MAAM;AAC/C,UAAM,UAAU,eAAe,SAAS,EAAE;AAC1C,QAAI,CAAC,QAAS,QAAO,EAAE,YAAY,GAAG,YAAY,EAAE;AACpD,UAAM,MAAM,WAAW,UAAU,CAAC,QAAQ,IAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,CAAC;AACnF,UAAM,kBAAkB,WAAW,GAAG;AACtC,QAAI,CAAC,gBAAiB,QAAO,EAAE,YAAY,GAAG,YAAY,EAAE;AAC5D,WAAO;AAAA,MACL,YAAY;AAAA,MACZ,YAAY,gBAAgB,QAAQ,UAAU,CAAC,MAAM,EAAE,OAAO,OAAO;AAAA,IACvE;AAAA,EACF,GAAG,CAAC,UAAU,CAAC;AAEf,WAAS,CAAC,QAAQ,QAAQ;AACxB,QAAI,IAAI,QAAQ;AACd,iBAAW;AAAA,IACb,WAAW,IAAI,QAAQ;AACrB,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,SACE,oBAAC,OAAI,eAAc,UAAS,OAAM,QAAO,UAAU,GAAG,WAAW,GAC/D,8BAAC,OAAI,KAAK,SAAS,UAAU,GAAG,WAAW,GACzC;AAAA,IAAC;AAAA;AAAA,MAEC;AAAA,MACA,iBAAiB;AAAA,MACjB;AAAA,MACA,mBAAmB;AAAA,MACnB,mBAAmB;AAAA,MACnB;AAAA,MACA;AAAA,MACA,sBAAsB;AAAA;AAAA,IARjB;AAAA,EASP,GACF,GACF;AAEJ;","names":["useMemo","useMemo"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/cli/lib/installation/provider-flag.ts"],"sourcesContent":["/**\n * `--provider`: the one flag that names an installation this release cannot read off a folder.\n *\n * **The folder is the record, and this flag is not a second one.** There is no `provider` field in\n * `config.ts`, nothing in a shared payload carries one and a share id encodes none — which is what\n * keeps one saved configuration installable onto either provider and every existing id working.\n * So after an install the folder answers, `providerInUse` reads it, and no command needs a flag.\n * Two questions survive that, and both are the absence of a folder rather than a doubt about one:\n *\n * 1. **A greenfield `init --from <id> --provider codex`** — the folder does not exist yet, so\n * there is nothing to read. This is the flag's whole purpose, and it is why the flag is\n * meaningless without `--from`: the provider is chosen in the web app, so the only run that can\n * be told one is the run that installs what the app produced (D15). A wizard walked to the end\n * and then refused would have spent the user's time before saying so, and there is no wizard\n * step to choose a provider in.\n * 2. **A scope holding BOTH folders** — the disk has two answers, `providerInUse` resolves them by\n * roster order, and a command that acted on the roster's first answer would act on a user's\n * other installation with nothing on screen saying so. `edit`, `uninstall`, `share`, `eject`,\n * `compile` and `update` refuse instead, naming this flag; `list` takes it too and, given no\n * flag, names both installations above the one it is showing —\n * {@link otherInstallationsInThisScope}. **`compile`, `update` and `list` were outside this from C7b\n * until 2026-09-23**, on the reading that a command reading the provider off the FOLDER needs\n * no flag. True of a folder, false of a SCOPE: a scope holds up to one installation per\n * provider, and `providerInUse` then answers by roster order — so the two that write rewrote\n * one of a user's two in silence and the one that reports showed one of them.\n *\n * **The refusal and the selection are one module, deliberately.** A refusal naming a flag that\n * does nothing is worse than neither: the user reads the sentence, types the flag, and the command\n * refuses again or — worse — acts on whichever installation it was going to act on anyway.\n * {@link refuseAnAmbiguousInstallation} is the refusal and {@link chooseProviderForThisRun} is\n * what the flag it names does, and neither can be added without the other.\n *\n * **It was hidden through C6 and is on the help screens from C7b.** Between C4 and C5 a Codex\n * install compiled no sub-agents, so the flag was a user-reachable surface for a provider that\n * was not finished. Hiding it was never disabling it — oclif parses a hidden flag exactly as it\n * parses any other, which is what let the e2e suite drive it throughout and is why no behavioural\n * spec reddened when the hiding came off. The one surface that can tell a shipped flag from an\n * undiscoverable one is help output, so that is where the claim lives:\n * `e2e/commands/provider-is-on-every-help-screen.e2e.test.ts` asserts each command that declares\n * it advertises it with both provider names, and that `doctor` — which reports on every\n * installation in the scope rather than acting on one — does not.\n */\n\nimport os from \"os\";\n\nimport { Flags } from \"@oclif/core\";\n\nimport { PROVIDERS, EDITOR_URL, CLI_INVOKE_COMMAND, type Provider } from \"../../consts.js\";\nimport { detectInstallations, type DetectedInstallation } from \"./detect-installations.js\";\nimport { chooseProviderForThisRun } from \"./install-layout.js\";\n\n/**\n * The flag itself, declared once and built into each command's own `static flags`.\n *\n * `options` is what makes the roster closed: oclif refuses an unlisted value with exit 2 and a\n * message naming every provider there is, so a user who typed one wrong is told the spelling of\n * the one they wanted rather than that something was invalid.\n *\n * A FACTORY rather than a shared constant, for the reason `agentCodec` and\n * `claudeOfferedPlacements` each give: every command declaring it would otherwise hold one object\n * by identity, oclif writes onto a flag definition while building a command's flag map, and\n * nothing in the types says either thing.\n */\nexport function providerFlag() {\n return Flags.string({\n description: \"Which provider's installation this run is about\",\n helpValue: `<${PROVIDERS.join(\"|\")}>`,\n options: [...PROVIDERS],\n });\n}\n\n/**\n * The parsed flag as a {@link Provider}, or `undefined` for a run that named none.\n *\n * oclif has already refused anything outside the roster by the time this is reached — `options`\n * above is checked during `parse` — so the guard here is a narrowing rather than a second\n * validation, and it is written as a membership test rather than a cast because a cast would\n * survive the roster growing a member this switch has never seen.\n */\nexport function providerNamedBy(flagValue: string | undefined): Provider | undefined {\n if (flagValue === undefined) return undefined;\n return PROVIDERS.find((provider) => provider === flagValue);\n}\n\n/**\n * What `init` says when it is handed a provider and no configuration to install.\n *\n * Both halves are load-bearing. `--from` is what the flag needs, and the EDITOR is where an id\n * comes from — a user told only that `--from` is missing has no way to produce one, and the CLI\n * has no step that mints it. The `/editor` segment rather than the apex, because the apex is a\n * landing page that knows nothing about a configuration.\n */\nexport function providerNeedsAConfigurationToInstall(): string {\n return (\n `--provider names which installation to create and needs the configuration to create it ` +\n `from, so it is only meaningful beside --from. Build one at ${EDITOR_URL}, then run ` +\n `'${CLI_INVOKE_COMMAND} init --from <id> --provider <provider>'.`\n );\n}\n\n/**\n * What a command says when the scope it is about holds an installation of each provider.\n *\n * It names both, because \"there is more than one\" leaves the user to go and look; and it names the\n * flag, because the sentence is only worth printing if it says how to answer.\n */\nfunction ambiguousInstallation(\n subject: string,\n providers: readonly Provider[],\n scopeRoot: string,\n): string {\n return (\n `${scopeRoot} holds ${providers.length} installations — ${providers.join(\" and \")} — so ` +\n `${subject} cannot tell which one you mean. Name it with --provider <${providers.join(\"|\")}>. ` +\n `Nothing has been changed.`\n );\n}\n\n/** One scope's installations: the directory they are under, and which providers are there. */\ntype InstallationsInPlay = {\n scopeRoot: string;\n providers: Provider[];\n};\n\n/**\n * The installations a run from `cwd` could act on, and which providers they belong to.\n *\n * The project's own first and the global only when the project has none, which is the fallback\n * every command already walks — a project installation is the subject of a command run inside it,\n * and the global is what a run with no project installation is about. Answering over both at once\n * would refuse a Claude project on a machine whose HOME happens to carry two installations, which\n * is a fact about the machine rather than about this run.\n */\nasync function installationsInPlay(cwd: string): Promise<InstallationsInPlay> {\n const found = await detectInstallations(cwd);\n const inTheProject = atScope(found, \"project\");\n\n if (inTheProject.length > 0) return { scopeRoot: cwd, providers: providersOf(inTheProject) };\n // `os.homedir()` rather than a path derived from a config file, because it is the root\n // `detectInstallations` itself looked under — so the directory the message names is the\n // directory that was read, under a pinned HOME as much as under a real one.\n return { scopeRoot: os.homedir(), providers: providersOf(atScope(found, \"global\")) };\n}\n\n/** The installations one scope root holds. */\nfunction atScope(\n found: readonly DetectedInstallation[],\n scope: DetectedInstallation[\"scope\"],\n): DetectedInstallation[] {\n return found.filter((installation) => installation.scope === scope);\n}\n\n/** Which providers a set of installations belongs to, in the roster order discovery answered in. */\nfunction providersOf(installations: readonly DetectedInstallation[]): Provider[] {\n return installations.map((installation) => installation.provider);\n}\n\n/**\n * Settles which installation a command acts on, and refuses rather than guessing.\n *\n * Three endings, and the middle one is the whole point:\n *\n * - a run TOLD a provider commits to it for every path it builds, through\n * {@link chooseProviderForThisRun}. That is what makes the refusal below actionable.\n * - a scope holding two installations and no flag is refused by `onAmbiguous`, which never\n * returns: half of this — a refusal naming a flag that selects nothing — is worse than neither.\n * - anything else is left exactly as it was, so a scope holding one installation needs no flag and\n * every existing invocation keeps working.\n *\n * `onAmbiguous` is the command's own `this.error`, so the exit code and the rendering are oclif's\n * rather than this module's; it is typed `never` so a caller cannot forget to stop.\n */\nexport async function refuseAnAmbiguousInstallation(\n cwd: string,\n subject: string,\n named: Provider | undefined,\n onAmbiguous: (message: string) => never,\n): Promise<void> {\n if (named !== undefined) {\n chooseProviderForThisRun(named);\n return;\n }\n\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n if (providers.length <= 1) return;\n\n onAmbiguous(ambiguousInstallation(subject, providers, scopeRoot));\n}\n\n/**\n * The same question asked without refusing, for `doctor` — which changes nothing and therefore\n * reports rather than stops.\n *\n * A read-only command that refused would leave a user whose scope holds two installations unable\n * to LOOK at either, which is the one state they most need to see.\n */\nexport async function ambiguityFinding(cwd: string): Promise<string | null> {\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n if (providers.length <= 1) return null;\n\n return ambiguousInstallation(\"every command that acts on one\", providers, scopeRoot);\n}\n\n/**\n * The same question for a command that REPORTS one of the installations — `list`.\n *\n * A third sentence rather than either of the two above, because `list` is in neither of their\n * positions. It writes nothing, so refusing would leave a user unable to LOOK at what they have;\n * and it does not describe the whole scope the way `doctor` does, so \"every command that acts on\n * one\" would be a sentence about other commands printed above a report of one installation. What\n * it owes is the fact its own report omits: there is a second installation here, this is not it,\n * and here is how to ask for the other.\n *\n * `null` where the scope holds one installation, so the ordinary case prints nothing at all.\n */\nexport async function otherInstallationsInThisScope(\n cwd: string,\n showing: Provider,\n): Promise<string | null> {\n const { scopeRoot, providers } = await installationsInPlay(cwd);\n const others = providers.filter((provider) => provider !== showing);\n if (others.length === 0) return null;\n\n return (\n `${scopeRoot} holds ${providers.length} installations — ${providers.join(\" and \")} — and this ` +\n `is the ${showing} one. Show another with --provider <${providers.join(\"|\")}>.`\n );\n}\n"],"mappings":";;;;;;;;;;;;AA2CA,OAAO,QAAQ;AAEf,SAAS,aAAa;AAkBf,SAAS,eAAe;AAC7B,SAAO,MAAM,OAAO;AAAA,IAClB,aAAa;AAAA,IACb,WAAW,IAAI,UAAU,KAAK,GAAG,CAAC;AAAA,IAClC,SAAS,CAAC,GAAG,SAAS;AAAA,EACxB,CAAC;AACH;AAUO,SAAS,gBAAgB,WAAqD;AACnF,MAAI,cAAc,OAAW,QAAO;AACpC,SAAO,UAAU,KAAK,CAAC,aAAa,aAAa,SAAS;AAC5D;AAUO,SAAS,uCAA+C;AAC7D,SACE,qJAC8D,UAAU,eACpE,kBAAkB;AAE1B;AAQA,SAAS,sBACP,SACA,WACA,WACQ;AACR,SACE,GAAG,SAAS,UAAU,UAAU,MAAM,yBAAoB,UAAU,KAAK,OAAO,CAAC,cAC9E,OAAO,6DAA6D,UAAU,KAAK,GAAG,CAAC;AAG9F;AAiBA,eAAe,oBAAoB,KAA2C;AAC5E,QAAM,QAAQ,MAAM,oBAAoB,GAAG;AAC3C,QAAM,eAAe,QAAQ,OAAO,SAAS;AAE7C,MAAI,aAAa,SAAS,EAAG,QAAO,EAAE,WAAW,KAAK,WAAW,YAAY,YAAY,EAAE;AAI3F,SAAO,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,YAAY,QAAQ,OAAO,QAAQ,CAAC,EAAE;AACrF;AAGA,SAAS,QACP,OACA,OACwB;AACxB,SAAO,MAAM,OAAO,CAAC,iBAAiB,aAAa,UAAU,KAAK;AACpE;AAGA,SAAS,YAAY,eAA4D;AAC/E,SAAO,cAAc,IAAI,CAAC,iBAAiB,aAAa,QAAQ;AAClE;AAiBA,eAAsB,8BACpB,KACA,SACA,OACA,aACe;AACf,MAAI,UAAU,QAAW;AACvB,6BAAyB,KAAK;AAC9B;AAAA,EACF;AAEA,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,MAAI,UAAU,UAAU,EAAG;AAE3B,cAAY,sBAAsB,SAAS,WAAW,SAAS,CAAC;AAClE;AASA,eAAsB,iBAAiB,KAAqC;AAC1E,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,MAAI,UAAU,UAAU,EAAG,QAAO;AAElC,SAAO,sBAAsB,kCAAkC,WAAW,SAAS;AACrF;AAcA,eAAsB,8BACpB,KACA,SACwB;AACxB,QAAM,EAAE,WAAW,UAAU,IAAI,MAAM,oBAAoB,GAAG;AAC9D,QAAM,SAAS,UAAU,OAAO,CAAC,aAAa,aAAa,OAAO;AAClE,MAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,SACE,GAAG,SAAS,UAAU,UAAU,MAAM,yBAAoB,UAAU,KAAK,OAAO,CAAC,2BACvE,OAAO,uCAAuC,UAAU,KAAK,GAAG,CAAC;AAE/E;","names":[]}