agents-inc 0.153.0 → 0.155.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.
- package/CHANGELOG.md +65 -0
- package/dist/chunk-2H7UWE2G.js +246 -0
- package/dist/chunk-2H7UWE2G.js.map +1 -0
- package/dist/{chunk-ZNDLUWWD.js → chunk-4A4L3YIW.js} +5 -5
- package/dist/chunk-4G2YHZIM.js +132 -0
- package/dist/chunk-4G2YHZIM.js.map +1 -0
- package/dist/{chunk-WDAO3RUY.js → chunk-5F2YR5XV.js} +3 -3
- package/dist/{chunk-JFAUQDZM.js → chunk-5OKLCVM4.js} +3 -3
- package/dist/{chunk-REKOWTIB.js → chunk-5QZAK6J7.js} +44 -10
- package/dist/chunk-5QZAK6J7.js.map +1 -0
- package/dist/{chunk-VECFAKM5.js → chunk-6RLV45HN.js} +10 -10
- package/dist/{chunk-VECFAKM5.js.map → chunk-6RLV45HN.js.map} +1 -1
- package/dist/{chunk-K7PJDWER.js → chunk-CLFHC2DK.js} +15 -106
- package/dist/chunk-CLFHC2DK.js.map +1 -0
- package/dist/chunk-D2CAV7MG.js +61 -0
- package/dist/chunk-D2CAV7MG.js.map +1 -0
- package/dist/{chunk-NXGMM5YN.js → chunk-F2AMBBIA.js} +6 -6
- package/dist/{chunk-NXGMM5YN.js.map → chunk-F2AMBBIA.js.map} +1 -1
- package/dist/{chunk-HEBPKK5L.js → chunk-F5T6TV4Z.js} +213 -92
- package/dist/chunk-F5T6TV4Z.js.map +1 -0
- package/dist/{chunk-K3O3YQYG.js → chunk-G47TDUK3.js} +2 -2
- package/dist/{chunk-U2DNAHFE.js → chunk-GS2NZ3GD.js} +8 -8
- package/dist/chunk-GS2NZ3GD.js.map +1 -0
- package/dist/{chunk-ORJ5Y222.js → chunk-H6UTKTLK.js} +176 -256
- package/dist/chunk-H6UTKTLK.js.map +1 -0
- package/dist/{chunk-M5HSTNYU.js → chunk-HG4JPXJT.js} +11 -29
- package/dist/chunk-HG4JPXJT.js.map +1 -0
- package/dist/{chunk-VGEBYCQZ.js → chunk-HTYH7CKN.js} +4 -15
- package/dist/chunk-HTYH7CKN.js.map +1 -0
- package/dist/{chunk-JC7DBPRD.js → chunk-HXKOIWLU.js} +2 -2
- package/dist/chunk-HXKOIWLU.js.map +1 -0
- package/dist/{chunk-NSJ2S7R5.js → chunk-ILUVL7WM.js} +2 -2
- package/dist/{chunk-R54KIGN2.js → chunk-IO5YBKHV.js} +13 -2
- package/dist/chunk-IO5YBKHV.js.map +1 -0
- package/dist/chunk-IXRZAHZF.js +53 -0
- package/dist/chunk-IXRZAHZF.js.map +1 -0
- package/dist/chunk-JCPANDNR.js +35 -0
- package/dist/chunk-JCPANDNR.js.map +1 -0
- package/dist/{chunk-R4SEU3DF.js → chunk-LJCNUP6M.js} +2 -2
- package/dist/{chunk-FRWKCE6R.js → chunk-MHRC3KRX.js} +5 -5
- package/dist/chunk-MHRC3KRX.js.map +1 -0
- package/dist/chunk-MO5FGLVS.js +142 -0
- package/dist/chunk-MO5FGLVS.js.map +1 -0
- package/dist/{chunk-Q5FLW4JG.js → chunk-OKH64JZE.js} +2 -2
- package/dist/{chunk-WG6V6VJV.js → chunk-PCC4LBKB.js} +2 -2
- package/dist/chunk-PMUABBPG.js +258 -0
- package/dist/chunk-PMUABBPG.js.map +1 -0
- package/dist/{chunk-EFU6P3B7.js → chunk-PNMM5HNX.js} +5 -5
- package/dist/{chunk-4VYALFQZ.js → chunk-QWVXOCXO.js} +6 -6
- package/dist/{chunk-35VOK7XE.js → chunk-RWOYPOMR.js} +4365 -4355
- package/dist/chunk-RWOYPOMR.js.map +1 -0
- package/dist/{chunk-IO4VEW5U.js → chunk-SY4X2LND.js} +4 -4
- package/dist/{chunk-XGMOXMS4.js → chunk-TBOVYLQJ.js} +2 -2
- package/dist/{chunk-BMGBA6HJ.js → chunk-TNGMF4UX.js} +20 -20
- package/dist/{chunk-BMGBA6HJ.js.map → chunk-TNGMF4UX.js.map} +1 -1
- package/dist/{chunk-TY6CAOL7.js → chunk-UMH2YZKG.js} +14 -5
- package/dist/chunk-UMH2YZKG.js.map +1 -0
- package/dist/{chunk-6CNRMCFM.js → chunk-VPASBA7P.js} +2 -2
- package/dist/{chunk-NXQAY5U7.js → chunk-WCAUUBHO.js} +5860 -5126
- package/dist/chunk-WCAUUBHO.js.map +1 -0
- package/dist/{chunk-V3ENMW7G.js → chunk-WFRTHH3A.js} +3 -3
- package/dist/{chunk-2HC2SNRP.js → chunk-WTJ3AY33.js} +1 -5
- package/dist/chunk-WTJ3AY33.js.map +1 -0
- package/dist/{chunk-F7Z5I6GU.js → chunk-WUQ3MTPF.js} +11 -5
- package/dist/{chunk-F7Z5I6GU.js.map → chunk-WUQ3MTPF.js.map} +1 -1
- package/dist/{chunk-U2YSGBHA.js → chunk-XAXJWXI4.js} +93 -43
- package/dist/chunk-XAXJWXI4.js.map +1 -0
- package/dist/{chunk-ACKC577F.js → chunk-Y5Y7XHVU.js} +4 -4
- package/dist/{chunk-X5XJ6WKO.js → chunk-YO2LTXB4.js} +107 -16
- package/dist/chunk-YO2LTXB4.js.map +1 -0
- package/dist/{chunk-FIHTAFST.js → chunk-ZUAZHDKP.js} +64 -65
- package/dist/chunk-ZUAZHDKP.js.map +1 -0
- package/dist/commands/build/marketplace.js +98 -120
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -8
- package/dist/commands/compile.js +57 -24
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +220 -79
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +608 -100
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +26 -21
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +41 -39
- package/dist/commands/list.js +11 -11
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +243 -0
- package/dist/commands/new/marketplace.js.map +1 -0
- package/dist/commands/search.js +34 -24
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +67 -0
- package/dist/commands/share.js.map +1 -0
- package/dist/commands/uninstall.js +234 -196
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +9 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/prompt-confirm.js +1 -1
- package/dist/components/common/removal-plan-confirm.js +10 -0
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/wizard/category-grid.js +5 -5
- package/dist/components/wizard/checkbox-grid.js +5 -5
- package/dist/components/wizard/domain-selection.js +11 -11
- package/dist/components/wizard/run-wizard-session.js +29 -28
- package/dist/components/wizard/scroll-affordance.js +2 -2
- package/dist/components/wizard/skill-agent-summary.js +6 -6
- package/dist/components/wizard/source-grid.js +6 -6
- package/dist/components/wizard/stack-selection.js +8 -8
- package/dist/components/wizard/step-agents.js +10 -11
- package/dist/components/wizard/step-build.js +9 -9
- package/dist/components/wizard/step-confirm.js +10 -10
- package/dist/components/wizard/step-sources.js +10 -10
- package/dist/components/wizard/step-stack.js +9 -9
- package/dist/components/wizard/summary-panel.js +9 -9
- package/dist/components/wizard/toast.js +2 -2
- package/dist/components/wizard/wizard-layout.js +14 -14
- package/dist/components/wizard/wizard-tabs.js +2 -2
- package/dist/components/wizard/wizard.js +27 -27
- package/dist/copy-local-skills-NSUTBVLJ.js +14 -0
- package/dist/hooks/init.js +42 -62
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-X4E57I2U.js +15 -0
- package/dist/{loader-4U7UCE2Y.js → loader-G6BFG2VA.js} +3 -3
- package/dist/recompile-project-agents-JE4MM72I.js +20 -0
- package/dist/{source-loader-ZNSYJJCI.js → source-loader-3DL3NYUX.js} +7 -5
- package/dist/source-loader-3DL3NYUX.js.map +1 -0
- package/dist/src/agents/developer/ai-developer/critical-reminders.md +1 -1
- package/dist/src/agents/developer/ai-developer/critical-requirements.md +1 -1
- package/dist/src/agents/developer/ai-developer/identity.md +1 -1
- package/dist/src/agents/developer/ai-developer/playbook.md +1 -1
- package/dist/src/agents/developer/api-developer/identity.md +1 -1
- package/dist/src/agents/developer/cli-developer/identity.md +1 -1
- package/dist/src/agents/developer/web-developer/identity.md +1 -1
- package/dist/src/agents/meta/codex-keeper/identity.md +1 -1
- package/dist/src/agents/meta/convention-keeper/identity.md +1 -1
- package/dist/src/agents/meta/skill-summoner/identity.md +1 -1
- package/dist/src/agents/researcher/ai-researcher/identity.md +1 -1
- package/dist/src/agents/researcher/api-researcher/identity.md +1 -1
- package/dist/src/agents/researcher/cli-researcher/identity.md +1 -1
- package/dist/src/agents/researcher/web-researcher/identity.md +1 -1
- package/dist/src/agents/reviewer/reviewer/playbook.md +1 -1
- package/dist/src/agents/tester/ai-tester/identity.md +1 -1
- package/dist/src/agents/tester/api-tester/critical-reminders.md +1 -1
- package/dist/src/agents/tester/api-tester/critical-requirements.md +1 -1
- package/dist/src/agents/tester/api-tester/identity.md +2 -2
- package/dist/src/agents/tester/cli-tester/identity.md +1 -1
- package/dist/src/agents/tester/web-tester/identity.md +3 -3
- package/dist/stores/wizard-store.js +7 -5
- package/package.json +10 -7
- package/src/agents/developer/ai-developer/critical-reminders.md +1 -1
- package/src/agents/developer/ai-developer/critical-requirements.md +1 -1
- package/src/agents/developer/ai-developer/identity.md +1 -1
- package/src/agents/developer/ai-developer/playbook.md +1 -1
- package/src/agents/developer/api-developer/identity.md +1 -1
- package/src/agents/developer/cli-developer/identity.md +1 -1
- package/src/agents/developer/web-developer/identity.md +1 -1
- package/src/agents/meta/codex-keeper/identity.md +1 -1
- package/src/agents/meta/convention-keeper/identity.md +1 -1
- package/src/agents/meta/skill-summoner/identity.md +1 -1
- package/src/agents/researcher/ai-researcher/identity.md +1 -1
- package/src/agents/researcher/api-researcher/identity.md +1 -1
- package/src/agents/researcher/cli-researcher/identity.md +1 -1
- package/src/agents/researcher/web-researcher/identity.md +1 -1
- package/src/agents/reviewer/reviewer/playbook.md +1 -1
- package/src/agents/tester/ai-tester/identity.md +1 -1
- package/src/agents/tester/api-tester/critical-reminders.md +1 -1
- package/src/agents/tester/api-tester/critical-requirements.md +1 -1
- package/src/agents/tester/api-tester/identity.md +2 -2
- package/src/agents/tester/cli-tester/identity.md +1 -1
- package/src/agents/tester/web-tester/identity.md +3 -3
- package/src/schemas/custom-metadata.schema.json +3 -0
- package/src/schemas/metadata.schema.json +3 -0
- package/src/schemas/plugin.schema.json +3 -0
- package/src/schemas/project-config.schema.json +4 -8
- package/src/schemas/project-source-config.schema.json +2 -2
- package/dist/chunk-2HC2SNRP.js.map +0 -1
- package/dist/chunk-35VOK7XE.js.map +0 -1
- package/dist/chunk-FIHTAFST.js.map +0 -1
- package/dist/chunk-FRWKCE6R.js.map +0 -1
- package/dist/chunk-HEBPKK5L.js.map +0 -1
- package/dist/chunk-JC7DBPRD.js.map +0 -1
- package/dist/chunk-K7PJDWER.js.map +0 -1
- package/dist/chunk-KET3EVGX.js +0 -41
- package/dist/chunk-KET3EVGX.js.map +0 -1
- package/dist/chunk-M5HSTNYU.js.map +0 -1
- package/dist/chunk-NXQAY5U7.js.map +0 -1
- package/dist/chunk-OJJLYHM3.js +0 -34
- package/dist/chunk-OJJLYHM3.js.map +0 -1
- package/dist/chunk-ORJ5Y222.js.map +0 -1
- package/dist/chunk-R54KIGN2.js.map +0 -1
- package/dist/chunk-REKOWTIB.js.map +0 -1
- package/dist/chunk-TY6CAOL7.js.map +0 -1
- package/dist/chunk-U2DNAHFE.js.map +0 -1
- package/dist/chunk-U2YSGBHA.js.map +0 -1
- package/dist/chunk-VGEBYCQZ.js.map +0 -1
- package/dist/chunk-X5XJ6WKO.js.map +0 -1
- package/dist/copy-local-skills-KF2RAVD3.js +0 -14
- package/dist/load-agent-defs-DGXGBU3Q.js +0 -15
- package/dist/recompile-project-agents-CJVBAWDJ.js +0 -20
- /package/dist/{chunk-ZNDLUWWD.js.map → chunk-4A4L3YIW.js.map} +0 -0
- /package/dist/{chunk-WDAO3RUY.js.map → chunk-5F2YR5XV.js.map} +0 -0
- /package/dist/{chunk-JFAUQDZM.js.map → chunk-5OKLCVM4.js.map} +0 -0
- /package/dist/{chunk-K3O3YQYG.js.map → chunk-G47TDUK3.js.map} +0 -0
- /package/dist/{chunk-NSJ2S7R5.js.map → chunk-ILUVL7WM.js.map} +0 -0
- /package/dist/{chunk-R4SEU3DF.js.map → chunk-LJCNUP6M.js.map} +0 -0
- /package/dist/{chunk-Q5FLW4JG.js.map → chunk-OKH64JZE.js.map} +0 -0
- /package/dist/{chunk-WG6V6VJV.js.map → chunk-PCC4LBKB.js.map} +0 -0
- /package/dist/{chunk-EFU6P3B7.js.map → chunk-PNMM5HNX.js.map} +0 -0
- /package/dist/{chunk-4VYALFQZ.js.map → chunk-QWVXOCXO.js.map} +0 -0
- /package/dist/{chunk-IO4VEW5U.js.map → chunk-SY4X2LND.js.map} +0 -0
- /package/dist/{chunk-XGMOXMS4.js.map → chunk-TBOVYLQJ.js.map} +0 -0
- /package/dist/{chunk-6CNRMCFM.js.map → chunk-VPASBA7P.js.map} +0 -0
- /package/dist/{chunk-V3ENMW7G.js.map → chunk-WFRTHH3A.js.map} +0 -0
- /package/dist/{chunk-ACKC577F.js.map → chunk-Y5Y7XHVU.js.map} +0 -0
- /package/dist/{copy-local-skills-KF2RAVD3.js.map → components/common/removal-plan-confirm.js.map} +0 -0
- /package/dist/{load-agent-defs-DGXGBU3Q.js.map → copy-local-skills-NSUTBVLJ.js.map} +0 -0
- /package/dist/{loader-4U7UCE2Y.js.map → load-agent-defs-X4E57I2U.js.map} +0 -0
- /package/dist/{recompile-project-agents-CJVBAWDJ.js.map → loader-G6BFG2VA.js.map} +0 -0
- /package/dist/{source-loader-ZNSYJJCI.js.map → recompile-project-agents-JE4MM72I.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/init.tsx","../src/cli/lib/permission-checker.tsx"],"sourcesContent":["import React from \"react\";\n\nimport { Flags, type Interfaces } from \"@oclif/core\";\nimport { Box, Text, useApp } from \"ink\";\nimport { render } from \"../components/render.js\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { type WizardResultV2 } from \"../components/wizard/wizard.js\";\nimport { runWizardSession } from \"../components/wizard/run-wizard-session.js\";\nimport { useTerminalDimensions } from \"../components/hooks/use-terminal-dimensions.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport {\n loadSource,\n loadAgentDefs,\n copyLocalSkills,\n writeProjectConfig,\n compileAgentsAllScopes,\n type CompilationResult,\n type SkillCopyResult,\n discoverInstalledSkills,\n} from \"../lib/operations/index.js\";\nimport { fetchSeedConfig } from \"../lib/seed/fetch-seed.js\";\nimport {\n registerExternalSkills,\n writeExternalSkills,\n type ExternalSkillInstall,\n} from \"../lib/seed/external-skills.js\";\nimport { seedToWizardResult, type SeedMapping } from \"../lib/seed/seed-to-wizard.js\";\nimport { getInstallationInfo } from \"../lib/plugins/plugin-info.js\";\nimport { loadProjectConfig } from \"../lib/configuration/project-config.js\";\nimport {\n type InstallMode,\n detectInstallation,\n detectGlobalInstallation,\n detectProjectInstallation,\n deriveInstallMode,\n resolveInstallPaths,\n buildAgentScopeMap,\n isHomeDirectory,\n INSTALL_MODE_LABELS,\n INSTALL_MODE_DESCRIPTIONS,\n} from \"../lib/installation/index.js\";\nimport { checkPermissions } from \"../lib/permission-checker.js\";\nimport {\n ASCII_LOGO,\n CLAUDE_SRC_DIR,\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n EDIT_PROJECT_SETUP_FLAG,\n EJECT_SOURCE,\n STANDARD_FILES,\n} from \"../consts.js\";\nimport { clearTerminalScreen } from \"../utils/terminal.js\";\nimport { SelectList, type SelectListItem } from \"../components/common/select-list.js\";\nimport { promptValue } from \"../components/common/prompt-confirm.js\";\nimport { Spinner } from \"../components/common/spinner.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport type { AgentName, MergedSkillsMatrix, SkillScope } from \"../types/index.js\";\nimport { type StartupMessage } from \"../utils/logger.js\";\nimport {\n SUCCESS_MESSAGES,\n STATUS_MESSAGES,\n carriedSkillsWritten,\n globalScopedAgentsHint,\n sharedConfigExistingInstall,\n sharedConfigGlobalInstall,\n skippedUnknownAgents,\n skippedUnknownSkills,\n} from \"../utils/messages.js\";\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\nconst DASHBOARD_OPTIONS = [\n { label: \"Edit\", value: \"edit\" },\n { label: \"Compile\", value: \"compile\" },\n { label: \"Doctor\", value: \"doctor\" },\n { label: \"List\", value: \"list\" },\n] as const satisfies readonly SelectListItem<string>[];\n\n/** The commands offered by the project dashboard (single source: DASHBOARD_OPTIONS). */\nexport type DashboardCommand = (typeof DASHBOARD_OPTIONS)[number][\"value\"];\n\ntype DashboardProps = {\n onSelect: (command: DashboardCommand) => void;\n onCancel: () => void;\n};\n\nconst Dashboard: React.FC<DashboardProps> = ({ onSelect, onCancel }) => {\n const { exit } = useApp();\n const { rows: terminalHeight } = useTerminalDimensions();\n\n return (\n <Box flexDirection=\"column\" height={terminalHeight}>\n <Box marginBottom={1}>\n <Text>{ASCII_LOGO}</Text>\n </Box>\n <SelectList\n items={DASHBOARD_OPTIONS}\n onSelect={(command) => {\n onSelect(command);\n exit();\n }}\n onCancel={() => {\n onCancel();\n exit();\n }}\n />\n </Box>\n );\n};\n\n/** Formats the dashboard summary as plain text lines (for non-interactive/test output). */\nexport function formatDashboardText(data: DashboardData): string {\n const modeLabel = INSTALL_MODE_LABELS[data.mode];\n const lines = [\n DEFAULT_BRANDING.NAME,\n \"\",\n ` Skills: ${data.skillCount} installed`,\n ` Agents: ${data.agentCount} compiled`,\n ` Mode: ${modeLabel}`,\n ];\n if (data.source) {\n lines.push(` Marketplace: ${data.source}`);\n }\n lines.push(\"\");\n lines.push(` [Edit] [Compile] [Doctor] [List]`);\n return lines.join(\"\\n\");\n}\n\n/**\n * Shows the project dashboard and returns the selected command (or null if cancelled).\n * In non-interactive environments (no TTY), prints the summary text and returns null.\n */\nexport async function showDashboard(\n projectDir: string,\n log?: (message: string) => void,\n): Promise<DashboardCommand | null> {\n const data = await getDashboardData(projectDir);\n\n // Non-interactive: print text summary and exit (CI, piped, tests)\n if (!process.stdin.isTTY) {\n const output = log ?? console.log;\n output(formatDashboardText(data));\n return null;\n }\n\n // First-wins resolution via promptValue; clearOnResolve repaints a clean\n // terminal before unmount (dashboard occupies the full height).\n const selectedCommand = await promptValue<DashboardCommand | null>(\n (resolve) => (\n <Dashboard onSelect={(command) => resolve(command)} onCancel={() => resolve(null)} />\n ),\n { onExit: null, clearOnResolve: true },\n );\n\n clearTerminalScreen();\n\n return selectedCommand;\n}\n\n/**\n * Why the dashboard is on screen.\n *\n * `\"init\"` — the user ran `cc init` in an already-installed directory. That is a request\n * to set this project up, so choosing Edit continues the setup: it must materialise the\n * project even if the wizard changes nothing.\n *\n * `\"standalone\"` — the bare `cc` dashboard. Edit is just an editor there; a pass with no\n * changes is an inspection and must leave the filesystem untouched.\n */\nexport type DashboardOrigin = \"init\" | \"standalone\";\n\n/** The extra argv a dashboard selection needs to carry its origin into the command. */\nfunction dashboardCommandArgv(command: DashboardCommand, origin: DashboardOrigin): string[] {\n if (command !== \"edit\" || origin !== \"init\") return [];\n return [`--${EDIT_PROJECT_SETUP_FLAG}`];\n}\n\n/**\n * Shared dashboard entry: when the project is already initialized, shows the\n * dashboard and runs the chosen command. Returns true when the project was\n * initialized (dashboard shown), false otherwise. Never exits the process —\n * callers decide (the init hook exits SUCCESS at its own call site).\n */\nexport async function runDashboardFlow(\n projectDir: string,\n config: Interfaces.Config,\n origin: DashboardOrigin,\n log?: (message: string) => void,\n): Promise<boolean> {\n const installation = await detectInstallation(projectDir);\n if (!installation) return false;\n\n const selectedCommand = await showDashboard(projectDir, log);\n if (selectedCommand) {\n await config.runCommand(selectedCommand, dashboardCommandArgv(selectedCommand, origin));\n }\n return true;\n}\n\n/**\n * What `init` decided to install, and the little each producer knows that the shared spine does\n * not. Keeping these on the value rather than branching on a flag downstream is what stops the\n * two paths growing separate copies of the install sequence.\n */\n/**\n * The marketplace this run was pointed at, as oclif hands it over.\n *\n * `marketplace` is a required key holding `string | undefined` rather than\n * `marketplace?: string` because that is what oclif produces: a non-required flag still gets\n * its key written on the parse result, set to `undefined` when it was not passed. Under\n * `exactOptionalPropertyTypes` the two are different types, and `?` would be describing a\n * producer that never omits the key.\n */\ntype SourceFlags = { marketplace: string | undefined };\n\ntype Selection = {\n result: WizardResultV2;\n sourceResult: SourceLoadResult;\n /**\n * The marketplace this selection was actually loaded from, which the shared spine records in\n * the written config. Carried on the value because a shared id may name one the command line\n * did not, and the install has to record where its skills really came from either way.\n */\n sourceFlags: SourceFlags;\n /** Whether a person is at the terminal, so the permission notice may wait for them. */\n interactive: boolean;\n /** What to say if the selection turns out to be empty — only the producer knows why it is. */\n emptyMessage: string;\n};\n\n/**\n * Whether a decoded selection would write anything into the user's own ~/.claude. Skills and\n * sub-agents are asked separately because either can be globally scoped on its own: a shared\n * configuration can pin every skill to the project and still send a sub-agent home, and the\n * reverse.\n */\nfunction writesGlobalContent(result: WizardResultV2): boolean {\n return (\n result.skills.some((skill) => skill.scope === \"global\") ||\n result.agentConfigs.some((agent) => agent.scope === \"global\")\n );\n}\n\n/**\n * Which marketplace a shared configuration installs from.\n *\n * A payload names the one its skills were fetched from, because a skill id carries whose skill it\n * is and never where that repository lives — so without the ref the load walks on to the default\n * public catalogue and installs a different repository's skill under the same id.\n *\n * `--marketplace` still outranks it: naming one is an instruction about THIS install, while the\n * payload's ref is a record of where the sharer's came from. A payload that names none leaves the\n * flag undefined, which puts the load back on the rungs it has always walked.\n */\nfunction sharedConfigSourceFlags(flags: SourceFlags, payload: SeedPayload): SourceFlags {\n return { marketplace: flags.marketplace ?? payload.marketplace };\n}\n\nexport default class Init extends BaseCommand {\n static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;\n static description =\n \"Interactive wizard to set up skills and agents. Supports Plugin Mode (native install) and Eject Mode (copy to .claude/).\";\n\n static examples = [\n {\n description: \"Start the setup wizard\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Initialize from a custom marketplace\",\n command: \"<%= config.bin %> <%= command.id %> --marketplace github:org/marketplace\",\n },\n ];\n\n static flags = {\n marketplace: Flags.string({\n char: \"m\",\n description: \"Skills marketplace path or URL\",\n required: false,\n }),\n from: Flags.string({\n description: \"Install a configuration shared from agentsinc.sh by its id, without the wizard\",\n helpValue: \"<id>\",\n }),\n };\n\n /**\n * One spine, two producers. The wizard and a shared id differ only in *where the selection\n * comes from* — everything after it (the empty guard, the install pipeline) is identical, so it\n * lives here once rather than being written twice and drifting.\n */\n async run(): Promise<void> {\n const { flags } = await this.parse(Init);\n const projectDir = process.cwd();\n\n // Every route below reads the configs first — to show a dashboard, to refuse a shared id, or\n // to inline the global one. One that exists but cannot be read is recreated, not installed\n // over, and saying so here is what keeps the raw loader error off the screen.\n await this.ensureConfigReadable(projectDir);\n\n // Only a bare `init` is diverted to the dashboard. An id is an explicit instruction to install\n // *that* configuration, so it overrides an existing installation instead.\n if (!flags.from && (await this.showDashboardIfInitialized(projectDir))) return;\n\n const selection = flags.from\n ? await this.selectionFromSharedConfig(flags.from, flags, projectDir)\n : await this.selectionFromWizard(flags, projectDir);\n\n if (!selection) this.exit(EXIT_CODES.CANCELLED);\n\n // On the spine rather than in either producer: a broken constraint is a fact about the\n // selection, not about where it came from, and `edit` reports the same fact the same way\n // the moment the wizard hands it one. Both producers run the same validator over the same\n // matrix — the wizard over what was chosen, `--from` over what survived the decode — so\n // what is said here is this catalog's verdict either way.\n this.reportValidationErrors(selection.result.validation);\n\n // A sub-agent is installable on its own — it has front-matter, a prompt and a compiled file\n // without owning a single skill — so only a selection with neither is nothing to install.\n if (selection.result.skills.length === 0 && selection.result.selectedAgents.length === 0) {\n // The producer supplies the wording because only it knows why empty means what it means:\n // nothing chosen, versus a payload this catalog cannot install.\n this.error(selection.emptyMessage, { exit: EXIT_CODES.ERROR });\n }\n\n await this.handleInstallation(\n selection.result,\n selection.sourceResult,\n selection.sourceFlags,\n selection.interactive,\n );\n }\n\n /** The interactive producer: load the source, run the wizard, return what was chosen. */\n private async selectionFromWizard(\n flags: SourceFlags,\n projectDir: string,\n ): Promise<Selection | null> {\n // The blank global config is created by writeProjectConfig() once the\n // wizard succeeds, never before it renders: a cancelled init must leave no\n // artifact that the next run could mistake for an existing installation.\n const isGlobalRoot = isHomeDirectory(projectDir);\n\n const { sourceResult, startupMessages } = await this.loadWizardInputsUnderSpinner(flags);\n\n const result = await this.runWizard(startupMessages, isGlobalRoot);\n if (!result) return null;\n\n return {\n result,\n sourceResult,\n sourceFlags: flags,\n // A person is already at the terminal, so the permission notice can wait for them.\n interactive: true,\n emptyMessage: \"No skills selected\",\n };\n }\n\n /**\n * Everything the wizard needs, loaded behind a spinner that comes down whichever way the\n * await ends.\n *\n * The cleanup is a `finally` because a source that cannot be loaded refuses the run from\n * inside this await, and oclif would otherwise paint its error under an Ink tree still\n * repainting over it. Never a `catch`: the throw reaches oclif untouched, or both the\n * error rendering and the exit code change with it.\n */\n private async loadWizardInputsUnderSpinner(flags: SourceFlags): Promise<{\n sourceResult: SourceLoadResult;\n startupMessages: StartupMessage[];\n }> {\n const { unmount, clear: clearSpinner } = render(\n <Spinner label={STATUS_MESSAGES.LOADING_SKILLS} />,\n );\n try {\n return await this.loadSourceOrFail(flags);\n } finally {\n clearSpinner();\n unmount();\n }\n }\n\n /**\n * The `--from <id>` producer: fetch and map, no wizard. Nothing here may assume a TTY — running\n * headless is most of why the flag exists.\n *\n * It is also greenfield-only, which is what two of the three refusals are: a shared\n * configuration is installed whole, so anything it would have to install over has to be\n * uninstalled first. The third is about the LOCATION rather than what is already in it — a\n * global installation holds only global-scoped content, and this is the one producer that never\n * asked. All three fire before anything is written.\n */\n private async selectionFromSharedConfig(\n id: string,\n flags: SourceFlags,\n projectDir: string,\n ): Promise<Selection> {\n await this.refuseInstalledProject(projectDir);\n\n this.log(`Fetching configuration ${id}...`);\n const fetched = await fetchSeedConfig(id);\n if (!fetched.ok) {\n this.error(fetched.error, { exit: EXIT_CODES.ERROR });\n }\n\n const sourceFlags = sharedConfigSourceFlags(flags, fetched.payload);\n const { sourceResult } = await this.loadSourceOrFail(sourceFlags);\n // Before the decode, because a skill the payload CARRIES answers to no catalogue: unseated,\n // its id is skipped like any other unknown one and its content is never read.\n const carriedSkills = this.registerExternalSkillsOrFail(\n fetched.payload,\n sourceResult.matrix,\n projectDir,\n );\n const { result, skippedSkillIds, skippedAgentNames } = this.decodeSeedOrFail(\n fetched.payload,\n sourceResult.matrix,\n );\n\n // The location refusal is `BaseCommand`'s, because `edit --from` reaches the same\n // contradiction through the other door and an invariant enforced on one producer is enforced\n // nowhere. It runs before {@link refuseBlockingGlobalInstall} because it needs no filesystem\n // probe to answer: where the install root is, and what the payload said, is all of it.\n this.refuseProjectScopedContentAtHome(result, projectDir);\n await this.refuseBlockingGlobalInstall(result);\n\n // After the refusals and before the install: every refusal on this path fires with nothing\n // written, and the copy step that follows finds these skills already where they belong.\n await this.writeCarriedSkills(carriedSkills);\n\n // Named, not counted. \"3 skills were skipped\" cannot be acted on; the ids can, and this is the\n // one moment the user can tell whether what they shared is what they are getting. Worded once,\n // in `messages.ts`, because `edit --from` reports the same skips about the same wire.\n if (skippedSkillIds.length > 0) this.warn(skippedUnknownSkills(skippedSkillIds));\n if (skippedAgentNames.length > 0) this.warn(skippedUnknownAgents(skippedAgentNames));\n\n if (result.skills.length > 0) {\n this.log(\n `Installing ${result.skills.length} skill(s) across ${result.selectedAgents.length} sub-agent(s)\\n`,\n );\n }\n\n return {\n result,\n sourceResult,\n sourceFlags,\n interactive: false,\n emptyMessage: `Configuration '${id}' contains no skills this catalog can install.`,\n };\n }\n\n /**\n * Refuses to install a shared configuration into a directory that already has one.\n *\n * Project-scoped detection rather than `detectInstallation`, whose global fallback would refuse\n * every clean project on a machine with a global install — including for a payload that never\n * goes near it. Whether a global install is in the way is a question about the PAYLOAD, and\n * {@link refuseBlockingGlobalInstall} is where it is asked.\n *\n * This runs before the fetch: there is nothing to learn from the network about a directory that\n * is already spoken for.\n */\n private async refuseInstalledProject(projectDir: string): Promise<void> {\n const installation = await detectProjectInstallation(projectDir);\n if (!installation) return;\n\n this.error(sharedConfigExistingInstall(installation.configPath), { exit: EXIT_CODES.ERROR });\n }\n\n /**\n * The other half of the same rule. A payload carrying global-scoped skills or sub-agents writes\n * into the user's own ~/.claude, so an installation there is in its way even when this project\n * is spotless. A payload with nothing global cannot reach that far and is never refused for it.\n */\n private async refuseBlockingGlobalInstall(result: WizardResultV2): Promise<void> {\n if (!writesGlobalContent(result)) return;\n\n const globalInstallation = await detectGlobalInstallation();\n if (!globalInstallation) return;\n\n this.error(sharedConfigGlobalInstall(globalInstallation.configPath), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n /**\n * The decode refuses a payload the config model has nowhere to write (see `seedToWizardResult`).\n * That is a failure of this command, reported with this command's exit code rather than left to\n * surface as an unhandled throw.\n */\n private decodeSeedOrFail(payload: SeedPayload, matrix: MergedSkillsMatrix): SeedMapping {\n try {\n return seedToWizardResult(payload, matrix);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Seats the catalogue entries the payload carries with it, or refuses the run.\n *\n * The refusal is `registerExternalSkills`' own — a carried skill asked for as a plugin, which\n * no marketplace serves — and is reported with this command's exit code for the same reason the\n * decode's is.\n */\n private registerExternalSkillsOrFail(\n payload: SeedPayload,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n ): ExternalSkillInstall[] {\n try {\n return registerExternalSkills(payload, matrix, projectDir);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /** Writes the skills the payload brought with it, and says which they were. */\n private async writeCarriedSkills(carried: ExternalSkillInstall[]): Promise<void> {\n if (carried.length === 0) return;\n\n await writeExternalSkills(carried);\n // Named rather than counted, like the skips: these are the entries no catalogue can explain,\n // so this line is the only place the user learns what arrived with the configuration itself.\n this.log(carriedSkillsWritten(carried.map((skill) => skill.id)));\n }\n\n private async showDashboardIfInitialized(projectDir: string): Promise<boolean> {\n return runDashboardFlow(projectDir, this.config, \"init\", (msg) => this.log(msg));\n }\n\n private async loadSourceOrFail(\n flags: SourceFlags,\n ): Promise<{ sourceResult: SourceLoadResult; startupMessages: StartupMessage[] }> {\n try {\n const loaded = await loadSource({\n // The one load that may CHOOSE a marketplace rather than read the stored one.\n caller: \"init\",\n ...(flags.marketplace !== undefined && { sourceFlag: flags.marketplace }),\n projectDir: process.cwd(),\n captureStartupMessages: true,\n });\n return { sourceResult: loaded.sourceResult, startupMessages: loaded.startupMessages };\n } catch (error) {\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n /**\n * `init`'s wizard opens on an empty selection, and can open on nothing else: it is reached\n * only once {@link showDashboardIfInitialized} has found no installation, and that check\n * falls back to the home directory — so a global roster to hydrate from would have diverted\n * this run to the dashboard before the wizard was built. Hydrating a saved selection is\n * `edit`'s job, and `Edit.runEditWizard` is where it happens.\n */\n private async runWizard(\n startupMessages: StartupMessage[],\n isGlobalRoot: boolean,\n ): Promise<WizardResultV2 | null> {\n return runWizardSession({\n hydrate: { isEditingFromGlobalScope: isGlobalRoot },\n props: {\n version: this.config.version,\n logo: ASCII_LOGO,\n startupMessages,\n },\n onCancel: () => this.log(\"Setup cancelled\"),\n clearTerminal: () => this.clearTerminal(),\n });\n }\n\n private async handleInstallation(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: SourceFlags,\n /**\n * Whether the caller can hold the terminal. The permission notice is an Ink app with no exit\n * of its own, so `waitUntilExit()` only ever resolves because a person is there to end it —\n * which is fine after the wizard and a hang everywhere else. `--from` sets this false: it has\n * to complete over a pipe and in CI.\n */\n interactive = true,\n ): Promise<void> {\n const projectDir = process.cwd();\n const activeSkills = result.skills.filter((s) => !s.excluded);\n const installMode = deriveInstallMode(activeSkills);\n const ejectedSkills = activeSkills.filter((s) => s.origin === EJECT_SOURCE);\n const pluginSkills = activeSkills.filter((s) => s.origin !== EJECT_SOURCE);\n\n this.logInstallPlan(installMode, ejectedSkills, pluginSkills);\n\n // Resolve marketplace up front — BEFORE any filesystem mutation. If\n // resolution fails in mixed mode, the hard-error must fire before\n // `copyEjectSkillsStep` copies anything to `.claude/skills/`, otherwise\n // we leave an orphaned half-install with no config.ts to recognise it.\n const resolvedMarketplace =\n pluginSkills.length > 0\n ? await this.requireMarketplaceOrExit(\n sourceResult,\n \"install plugin skills\",\n (marketplace) => this.log(`Registering marketplace \"${marketplace}\"...`),\n )\n : null;\n\n const copyResult =\n installMode === \"eject\" || installMode === \"mixed\"\n ? await this.copyEjectSkillsStep(ejectedSkills, projectDir, sourceResult, installMode)\n : null;\n\n if (resolvedMarketplace !== null) {\n await this.installPluginSkillsReported(\n pluginSkills,\n resolvedMarketplace,\n projectDir,\n sourceResult.matrix,\n );\n }\n // The shared install reporter hard-errors on any failure, so reaching here with\n // a resolved marketplace means plugin mode fully succeeded.\n const pluginModeSucceeded = resolvedMarketplace !== null;\n\n try {\n const { configResult, compileResult, agentScopeMap } = await this.writeConfigAndCompile(\n result,\n sourceResult,\n flags,\n );\n this.reportSuccess(\n configResult,\n compileResult,\n agentScopeMap,\n installMode,\n pluginModeSucceeded,\n copyResult,\n );\n\n await this.showPermissionNotice(projectDir, interactive);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * The permission notice, where there is one to show. It is an Ink app with no exit of its own,\n * so `waitUntilExit()` only ever resolves because a person is there to end it — which is fine\n * after the wizard and a hang everywhere else. Without a terminal to hold, one frame is\n * rendered and let go: the notice is information, not a prompt, so there is nothing to answer\n * and nothing to wait for.\n */\n private async showPermissionNotice(projectDir: string, interactive: boolean): Promise<void> {\n const permissionWarning = await checkPermissions(projectDir);\n if (!permissionWarning) return;\n\n if (!interactive) {\n const { unmount } = render(permissionWarning);\n unmount();\n return;\n }\n\n const { waitUntilExit } = render(permissionWarning);\n await waitUntilExit();\n }\n\n private logInstallPlan(\n installMode: InstallMode,\n ejectedSkills: WizardResultV2[\"skills\"],\n pluginSkills: WizardResultV2[\"skills\"],\n ): void {\n this.log(\"\\n\");\n this.log(`Selected ${ejectedSkills.length + pluginSkills.length} skills`);\n this.log(\n `Install mode: ${\n installMode === \"mixed\"\n ? `${INSTALL_MODE_LABELS.mixed} (${ejectedSkills.length} eject, ${pluginSkills.length} plugin)`\n : INSTALL_MODE_DESCRIPTIONS[installMode]\n }`,\n );\n }\n\n private async copyEjectSkillsStep(\n localSkills: WizardResultV2[\"skills\"],\n projectDir: string,\n sourceResult: SourceLoadResult,\n installMode: InstallMode,\n ): Promise<SkillCopyResult> {\n this.log(\"Copying skills to local directory...\");\n const copyResult = await copyLocalSkills(localSkills, projectDir, sourceResult);\n\n if (installMode === \"mixed\") {\n if (copyResult.projectCopied.length > 0 && copyResult.globalCopied.length > 0) {\n this.log(\n `Copied ${copyResult.totalCopied} local skills (${copyResult.projectCopied.length} project, ${copyResult.globalCopied.length} global)`,\n );\n } else if (copyResult.globalCopied.length > 0) {\n this.log(`Copied ${copyResult.globalCopied.length} local skills to ~/.claude/skills/`);\n } else {\n this.log(`Copied ${copyResult.projectCopied.length} local skills to .claude/skills/`);\n }\n } else {\n this.log(`Copied ${copyResult.totalCopied} skills to .claude/skills/\\n`);\n }\n\n return copyResult;\n }\n\n private async writeConfigAndCompile(\n result: WizardResultV2,\n sourceResult: SourceLoadResult,\n flags: SourceFlags,\n ): Promise<{\n configResult: Awaited<ReturnType<typeof writeProjectConfig>>;\n compileResult: CompilationResult;\n agentScopeMap: Map<AgentName, SkillScope>;\n }> {\n this.log(\"Generating configuration...\");\n const configResult = await writeProjectConfig({\n wizardResult: result,\n sourceResult,\n projectDir: process.cwd(),\n ...(flags.marketplace !== undefined && { sourceFlag: flags.marketplace }),\n });\n\n if (configResult.wasMerged) {\n this.log(`Merged with existing config at ${configResult.existingConfigPath}`);\n }\n\n this.log(`Configuration saved (${configResult.config.agents.length} agents)\\n`);\n this.reportUnassignedSkills(configResult.config);\n\n this.log(STATUS_MESSAGES.COMPILING_AGENTS);\n const cwd = process.cwd();\n const agentDefs = await loadAgentDefs();\n const { allSkills } = await discoverInstalledSkills(cwd);\n const agentScopeMap = buildAgentScopeMap(configResult.config);\n const compileResult = await compileAgentsAllScopes({\n projectDir: cwd,\n sourcePath: agentDefs.sourcePath,\n skills: allSkills,\n agentScopeMap,\n });\n this.log(`Compiled ${compileResult.compiled.length} agents\\n`);\n\n this.reportPropagatedRecompile(configResult.propagation);\n\n return { configResult, compileResult, agentScopeMap };\n }\n\n private reportSuccess(\n configResult: Awaited<ReturnType<typeof writeProjectConfig>>,\n compileResult: CompilationResult,\n agentScopeMap: Map<AgentName, SkillScope>,\n installMode: InstallMode,\n pluginModeSucceeded: boolean,\n copyResult: SkillCopyResult | null,\n ): void {\n this.log(`${SUCCESS_MESSAGES.INIT_SUCCESS}\\n`);\n\n const isEjectOutput =\n installMode === \"eject\" || (installMode === \"mixed\" && !pluginModeSucceeded);\n if (isEjectOutput && copyResult && copyResult.totalCopied > 0) {\n this.reportSkillsCopied(copyResult);\n }\n this.reportAgentsCompiled(compileResult.compiled, agentScopeMap);\n this.reportConfiguration(configResult.configPath, agentScopeMap);\n }\n\n /**\n * Names the config that actually holds this install's assignments, and where a\n * recompile of them has to be run from.\n *\n * Split by the same `agentScopeMap` the two reporters above split on, because the\n * same scope decides both. A project config's `stack` is filtered down to\n * project-scoped agents on the way out, so a wholly GLOBAL install leaves it\n * carrying no assignment at all — naming it sends the user to a file with nothing\n * in it — and `compile` in this cwd runs the PROJECT pass, which recompiles no\n * global agent. At the home root both scopes resolve to one file and one pass, so\n * there is nothing to split and the project wording stands.\n */\n private reportConfiguration(\n projectConfigPath: string,\n agentScopeMap: Map<AgentName, SkillScope>,\n ): void {\n const cwd = process.cwd();\n const paths = {\n global: resolveInstallPaths(cwd, \"global\").configPath,\n project: projectConfigPath,\n };\n const split = splitAgentScopes(cwd, agentScopeMap);\n\n this.log(\"Configuration:\");\n for (const configPath of configsHoldingAssignments(split, paths)) {\n this.log(` ${configPath}`);\n }\n this.log(\"\");\n\n this.log(\"To customize agent-skill assignments:\");\n for (const [index, step] of customizationSteps(split, paths.global).entries()) {\n this.log(` ${index + 1}. ${step}`);\n }\n this.log(\"\");\n }\n\n /**\n * Reports where the skills actually landed. `copyLocalSkills` splits by scope,\n * so a default install driven from a project directory writes every skill\n * under HOME — reporting the project path there names a directory that was\n * never written.\n *\n * This block is a filesystem listing, so the entries are the on-disk directory\n * names — skill ids, not display names. `copySkillsToLocalFlattened` names each\n * destination directory after `skill.id`, so a user can copy any line and `cd`\n * into it.\n */\n private reportSkillsCopied(copyResult: SkillCopyResult): void {\n const cwd = process.cwd();\n const groups = isHomeDirectory(cwd)\n ? [\n {\n dir: resolveInstallPaths(cwd, \"project\").skillsDir,\n copied: [...copyResult.globalCopied, ...copyResult.projectCopied],\n },\n ]\n : [\n { dir: resolveInstallPaths(cwd, \"global\").skillsDir, copied: copyResult.globalCopied },\n { dir: resolveInstallPaths(cwd, \"project\").skillsDir, copied: copyResult.projectCopied },\n ].filter((group) => group.copied.length > 0);\n\n for (const group of groups) {\n this.log(\"Skills copied to:\");\n this.log(` ${group.dir}`);\n for (const copied of group.copied) {\n this.log(` ${copied.skillId}/`);\n }\n this.log(\"\");\n }\n }\n\n /**\n * Reports where the agents actually landed, mirroring the scope split\n * `compileAgentsAllScopes` performs: one pass at the home root, otherwise a\n * global pass under HOME and a project pass under the project directory.\n */\n private reportAgentsCompiled(\n compiled: AgentName[],\n agentScopeMap: Map<AgentName, SkillScope>,\n ): void {\n const cwd = process.cwd();\n const groups = isHomeDirectory(cwd)\n ? [{ dir: resolveInstallPaths(cwd, \"project\").agentsDir, agents: compiled }]\n : [\n {\n dir: resolveInstallPaths(cwd, \"global\").agentsDir,\n agents: compiled.filter((name) => agentScopeMap.get(name) === \"global\"),\n },\n {\n dir: resolveInstallPaths(cwd, \"project\").agentsDir,\n agents: compiled.filter((name) => agentScopeMap.get(name) !== \"global\"),\n },\n ].filter((group) => group.agents.length > 0);\n\n for (const group of groups) {\n this.log(\"Agents compiled to:\");\n this.log(` ${group.dir}`);\n for (const agentName of group.agents) {\n this.log(` ${agentName}.md`);\n }\n this.log(\"\");\n }\n }\n}\n\n/** The two config files an install can write, as the closing block refers to them. */\ntype ConfigPaths = { global: string; project: string };\n\n/** How this install's sub-agents fall across the two scopes, seen from the directory it ran in. */\ntype AgentScopeSplit = { globalAgentCount: number; isGlobalOnly: boolean };\n\n/**\n * At the home root the two scopes resolve to ONE config file and ONE compile pass, so there\n * is nothing to split and the split reports none — which is what leaves the project wording\n * standing there unchanged. Same fork `reportAgentsCompiled` makes over the same question.\n */\nfunction splitAgentScopes(cwd: string, agentScopeMap: Map<AgentName, SkillScope>): AgentScopeSplit {\n if (isHomeDirectory(cwd)) return { globalAgentCount: 0, isGlobalOnly: false };\n\n const scopes = [...agentScopeMap.values()];\n const globalAgentCount = scopes.filter((scope) => scope === \"global\").length;\n return {\n globalAgentCount,\n isGlobalOnly: globalAgentCount > 0 && globalAgentCount === scopes.length,\n };\n}\n\n/**\n * The config file(s) this install's assignments actually landed in. A wholly global install\n * has none in the project file — the writer filters its `stack` down to project-scoped\n * agents — so naming it would send the user to a file with nothing in it.\n */\nfunction configsHoldingAssignments(split: AgentScopeSplit, paths: ConfigPaths): string[] {\n if (split.isGlobalOnly) return [paths.global];\n if (split.globalAgentCount > 0) return [paths.global, paths.project];\n return [paths.project];\n}\n\n/**\n * What changing an assignment takes, in the order it takes it. The compile step is the half\n * that has to be scope-aware: `compile` run in a project directory performs the PROJECT pass\n * only, so it recompiles no global agent — which `globalScopedAgentsHint` already says, in\n * the words `compile` itself says it in when it lands in the mirror image of this state.\n */\nfunction customizationSteps(split: AgentScopeSplit, globalConfigPath: string): string[] {\n if (split.isGlobalOnly) {\n return [`Edit ${globalConfigPath}`, globalScopedAgentsHint(split.globalAgentCount)];\n }\n\n return [\n `Edit ${CLAUDE_SRC_DIR}/${STANDARD_FILES.CONFIG_TS}`,\n `Run '${CLI_INVOKE_COMMAND} compile' to regenerate agents`,\n ...(split.globalAgentCount > 0 ? [globalScopedAgentsHint(split.globalAgentCount)] : []),\n ];\n}\n\nexport type DashboardData = {\n skillCount: number;\n agentCount: number;\n mode: InstallMode;\n source?: string;\n};\n\n/**\n * Gathers dashboard data from the installation and project config.\n *\n * Both counts come from the same scope-aware installation so the summary cannot\n * mix a project-only figure with a global one — a default install driven from a\n * project directory puts every skill and agent under HOME.\n */\nexport async function getDashboardData(projectDir: string): Promise<DashboardData> {\n const [info, loaded] = await Promise.all([getInstallationInfo(), loadProjectConfig(projectDir)]);\n\n const activeSkills = loaded?.config.skills.filter((s) => !s.excluded);\n const skillCount = info?.skillCount ?? 0;\n const agentCount = info?.agentCount ?? 0;\n const mode = info?.mode ?? (activeSkills ? deriveInstallMode(activeSkills) : \"eject\");\n const source = loaded?.config.marketplace;\n\n return { skillCount, agentCount, mode, ...(source !== undefined && { source }) };\n}\n","import React from \"react\";\nimport { z } from \"zod\";\n\nimport { Text, Box } from \"ink\";\nimport path from \"path\";\n\nimport { CLAUDE_DIR, CLI_COLORS, MAX_CONFIG_FILE_SIZE, STANDARD_FILES } from \"../consts\";\nimport { fileExists, readFileSafe } from \"../utils/fs\";\nimport { warn } from \"../utils/logger\";\nimport { settingsFileSchema } from \"./schemas\";\n\ntype SettingsFile = z.infer<typeof settingsFileSchema>;\ntype PermissionConfig = NonNullable<SettingsFile[\"permissions\"]>;\n\n/**\n * Reads one settings file's permissions block; undefined when absent, malformed, or empty.\n *\n * settings.json belongs to Claude Code, which adds keys on its own release schedule. This CLI\n * consumes `permissions` and owns nothing else in the file, so it stays silent about every other\n * field rather than warning about settings it has no standing to judge (D-304).\n */\nasync function readSettingsPermissions(filePath: string): Promise<PermissionConfig | undefined> {\n if (!(await fileExists(filePath))) return undefined;\n try {\n const content = await readFileSafe(filePath, MAX_CONFIG_FILE_SIZE);\n const raw: unknown = JSON.parse(content);\n const result = settingsFileSchema.safeParse(raw);\n const parsed: SettingsFile = result.success ? result.data : {};\n return parsed.permissions;\n } catch {\n warn(`Malformed settings file at '${filePath}' — skipping`);\n return undefined;\n }\n}\n\n/** Permissions from the first settings file that defines them — settings.local.json wins. */\nasync function loadPermissions(projectRoot: string): Promise<PermissionConfig | undefined> {\n const settingsPath = path.join(projectRoot, CLAUDE_DIR, STANDARD_FILES.SETTINGS_JSON);\n const localSettingsPath = path.join(projectRoot, CLAUDE_DIR, STANDARD_FILES.SETTINGS_LOCAL_JSON);\n\n for (const filePath of [localSettingsPath, settingsPath]) {\n const permissions = await readSettingsPermissions(filePath);\n if (permissions) return permissions;\n }\n return undefined;\n}\n\nexport async function checkPermissions(projectRoot: string): Promise<React.ReactElement | null> {\n const permissions = await loadPermissions(projectRoot);\n\n if (!permissions) {\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={CLI_COLORS.WARNING} padding={1}>\n <Text bold color={CLI_COLORS.WARNING}>\n Permission Notice\n </Text>\n <Text>No permissions configured in .claude/settings.json</Text>\n <Text>Agents will prompt for approval on each tool use.</Text>\n <Text> </Text>\n <Text>For autonomous operation, add to .claude/settings.json:</Text>\n <Text> </Text>\n <Text color={CLI_COLORS.DIM}>{\"{\"}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"permissions\": {'}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"allow\": ['}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"Read(*)\",'}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"Bash(git *)\",'}</Text>\n <Text color={CLI_COLORS.DIM}>{' \"Bash(bun *)\"'}</Text>\n <Text color={CLI_COLORS.DIM}>{\" ]\"}</Text>\n <Text color={CLI_COLORS.DIM}>{\" }\"}</Text>\n <Text color={CLI_COLORS.DIM}>{\"}\"}</Text>\n </Box>\n );\n }\n\n const hasRestrictiveBash = permissions.deny?.some(\n (rule) => rule === \"Bash(*)\" || rule === \"Bash\",\n );\n const hasNoAllows = !permissions.allow || permissions.allow.length === 0;\n\n if (hasRestrictiveBash || hasNoAllows) {\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor={CLI_COLORS.WARNING} padding={1}>\n <Text bold color={CLI_COLORS.WARNING}>\n Permission Warnings\n </Text>\n {hasRestrictiveBash && (\n <Text>\n ⚠ Bash is denied in permissions. Some agents require Bash for git, testing, and build\n commands.\n </Text>\n )}\n {hasNoAllows && (\n <Text>⚠ No allow rules configured. Agents will prompt for each tool use.</Text>\n )}\n </Box>\n );\n }\n\n return null;\n}\n"],"mappings":"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","names":["Box","Text","jsx","jsxs","Box","Text"]}
|
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
SummaryPanel
|
|
4
|
+
} from "./chunk-6RLV45HN.js";
|
|
2
5
|
import {
|
|
3
6
|
Toast
|
|
4
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ILUVL7WM.js";
|
|
5
8
|
import {
|
|
6
9
|
WizardTabs,
|
|
7
10
|
wizardTabsFor
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import {
|
|
10
|
-
SummaryPanel
|
|
11
|
-
} from "./chunk-VECFAKM5.js";
|
|
11
|
+
} from "./chunk-HXKOIWLU.js";
|
|
12
12
|
import {
|
|
13
13
|
getDomainDisplayName,
|
|
14
14
|
getStackName
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-5OKLCVM4.js";
|
|
16
16
|
import {
|
|
17
17
|
HOTKEY_INFO,
|
|
18
18
|
HOTKEY_SCOPE,
|
|
19
|
-
HOTKEY_SET_ALL_LOCAL,
|
|
20
|
-
HOTKEY_SET_ALL_PLUGIN,
|
|
21
19
|
HOTKEY_TOGGLE_LABELS,
|
|
22
20
|
KEY_LABEL_ENTER,
|
|
23
21
|
KEY_LABEL_ESC,
|
|
24
22
|
KEY_LABEL_SPACE,
|
|
25
23
|
isInfoPanelAvailable
|
|
26
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-WTJ3AY33.js";
|
|
27
25
|
import {
|
|
28
26
|
getActiveStepFlow,
|
|
29
27
|
orderDomains,
|
|
30
28
|
useWizardStore
|
|
31
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-F5T6TV4Z.js";
|
|
32
30
|
import {
|
|
33
31
|
formatTerminalTooSmallMessage,
|
|
34
32
|
isTerminalLargeEnough
|
|
35
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-G47TDUK3.js";
|
|
36
34
|
import {
|
|
37
35
|
CLI_COLORS,
|
|
38
36
|
FALLBACK_DOMAIN,
|
|
39
37
|
LOGO_MIN_TERMINAL_ROWS
|
|
40
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-IO5YBKHV.js";
|
|
41
39
|
|
|
42
40
|
// src/cli/components/wizard/wizard-layout.tsx
|
|
43
41
|
import { Box, Text } from "ink";
|
|
@@ -204,22 +202,6 @@ var WizardLayout = ({
|
|
|
204
202
|
isVisible: (store.step === "build" || store.step === "agents") && !store.isEditingFromGlobalScope
|
|
205
203
|
}
|
|
206
204
|
),
|
|
207
|
-
/* @__PURE__ */ jsx(
|
|
208
|
-
DefinitionItem,
|
|
209
|
-
{
|
|
210
|
-
label: "Set all local",
|
|
211
|
-
values: [HOTKEY_SET_ALL_LOCAL.label],
|
|
212
|
-
isVisible: store.step === "sources"
|
|
213
|
-
}
|
|
214
|
-
),
|
|
215
|
-
/* @__PURE__ */ jsx(
|
|
216
|
-
DefinitionItem,
|
|
217
|
-
{
|
|
218
|
-
label: "Set all plugin",
|
|
219
|
-
values: [HOTKEY_SET_ALL_PLUGIN.label],
|
|
220
|
-
isVisible: store.step === "sources"
|
|
221
|
-
}
|
|
222
|
-
),
|
|
223
205
|
/* @__PURE__ */ jsx(
|
|
224
206
|
DefinitionItem,
|
|
225
207
|
{
|
|
@@ -239,4 +221,4 @@ export {
|
|
|
239
221
|
useTerminalDimensions,
|
|
240
222
|
WizardLayout
|
|
241
223
|
};
|
|
242
|
-
//# sourceMappingURL=chunk-
|
|
224
|
+
//# sourceMappingURL=chunk-HG4JPXJT.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/wizard-layout.tsx","../src/cli/components/hooks/use-terminal-dimensions.ts"],"sourcesContent":["import { Box, Text } from \"ink\";\nimport React, { Fragment } from \"react\";\nimport { CLI_COLORS, FALLBACK_DOMAIN, LOGO_MIN_TERMINAL_ROWS } from \"../../consts.js\";\nimport type { StartupMessage } from \"../../utils/logger.js\";\nimport { formatTerminalTooSmallMessage, isTerminalLargeEnough } from \"../../utils/terminal.js\";\nimport { getActiveStepFlow, useWizardStore, type WizardStep } from \"../../stores/wizard-store.js\";\nimport { useTerminalDimensions } from \"../hooks/use-terminal-dimensions.js\";\nimport { SummaryPanel } from \"./summary-panel.js\";\nimport { Toast } from \"./toast.js\";\nimport {\n HOTKEY_INFO,\n HOTKEY_SCOPE,\n HOTKEY_TOGGLE_LABELS,\n KEY_LABEL_ENTER,\n KEY_LABEL_ESC,\n KEY_LABEL_SPACE,\n isInfoPanelAvailable,\n} from \"./hotkeys.js\";\nimport {\n WizardTabs,\n wizardTabsFor,\n type DomainNavProps,\n type TabDropdownProps,\n} from \"./wizard-tabs.js\";\nimport { getDomainDisplayName, getStackName, orderDomains } from \"./utils.js\";\n\ntype KeyHintProps = {\n isVisible?: boolean;\n label: string;\n values: readonly string[];\n};\n\nconst DefinitionItem: React.FC<KeyHintProps> = ({ isVisible = true, label, values }) => {\n if (!isVisible) {\n return null;\n }\n\n return (\n <Text>\n {values.map((value) => (\n <Fragment key={value}>\n <Text backgroundColor={CLI_COLORS.LABEL_BG} color={CLI_COLORS.UNFOCUSED}>\n {\" \"}\n {value}{\" \"}\n </Text>{\" \"}\n </Fragment>\n ))}\n <Text>{label}</Text>\n </Text>\n );\n};\n\nconst HOT_KEYS = [\n { label: \"select\", values: [KEY_LABEL_SPACE] },\n { label: \"continue\", values: [KEY_LABEL_ENTER] },\n { label: \"back\", values: [KEY_LABEL_ESC] },\n] as const satisfies readonly { label: string; values: readonly string[] }[];\n\nconst WizardFooter = () => {\n return (\n <Box\n columnGap={2}\n borderTop\n borderRight={false}\n borderBottom\n borderLeft={false}\n borderColor=\"blackBright\"\n borderStyle=\"single\"\n paddingLeft={1}\n paddingRight={1}\n >\n {HOT_KEYS.map((hotkey) => (\n <DefinitionItem {...hotkey} key={hotkey.label} />\n ))}\n </Box>\n );\n};\n\ntype WizardLayoutProps = {\n version?: string | undefined;\n logo?: string | undefined;\n startupMessages?: StartupMessage[] | undefined;\n children: React.ReactNode;\n};\n\n/**\n * How many buffered messages the band paints before it counts the rest instead.\n * A source that cannot resolve its own relationships warns once per unresolved\n * name — thousands, for a source with a broken `skill-rules.ts` — and every line\n * is a row taken from the step below it.\n *\n * Two budgets, because a row is worth more at some heights than others: a\n * terminal short enough that the logo is already dropped for starving the\n * content cannot spare four rows for news either, and there it paints the first\n * message and counts the rest. The first is the one that matters — the fetch\n * speaks before anything is parsed, so an unreachable source is message one.\n */\nconst MAX_PAINTED_STARTUP_MESSAGES = 3;\nconst MAX_PAINTED_STARTUP_MESSAGES_CRAMPED = 1;\n\nfunction paintedStartupMessageCount(terminalHeight: number): number {\n return terminalHeight >= LOGO_MIN_TERMINAL_ROWS\n ? MAX_PAINTED_STARTUP_MESSAGES\n : MAX_PAINTED_STARTUP_MESSAGES_CRAMPED;\n}\n\nconst STARTUP_MESSAGE_COLOR = {\n info: CLI_COLORS.NEUTRAL,\n warn: CLI_COLORS.WARNING,\n error: CLI_COLORS.ERROR,\n} as const satisfies Record<StartupMessage[\"level\"], string>;\n\n/**\n * What the load said before Ink took the terminal.\n *\n * `warn()` writes to stderr, which the wizard's own `clearTerminal` would wipe,\n * so a load that opens a wizard buffers instead (`lib/operations/source/load-source.ts`)\n * and hands the buffer here. This band is the only place those lines are ever\n * seen — the source-unreachable warning among them.\n *\n * It sits above the step rather than over it, and does not shrink: a warning\n * compressed by Yoga overprints into an unreadable row, which is worse than the\n * row it would have cost the step.\n */\nconst StartupMessages: React.FC<{ messages: StartupMessage[]; terminalHeight: number }> = ({\n messages,\n terminalHeight,\n}) => {\n if (messages.length === 0) return null;\n\n const painted = messages.slice(0, paintedStartupMessageCount(terminalHeight));\n const counted = messages.length - painted.length;\n\n return (\n <Box flexDirection=\"column\" flexShrink={0} paddingX={1}>\n {painted.map((message, index) => (\n <Text key={index} color={STARTUP_MESSAGE_COLOR[message.level]}>\n {message.text}\n </Text>\n ))}\n {counted > 0 && <Text color={CLI_COLORS.NEUTRAL}>{`... and ${counted} more`}</Text>}\n </Box>\n );\n};\n\n/**\n * The subtitle each step is headed with. Every entry is A SCREEN SENTINEL:\n * `e2e/pages/constants.ts` `STEP_TEXT` duplicates each one exactly and every E2E step\n * page object waits on it, so a subtitle that moves without it hangs each wizard spec for\n * the full wizard-load budget instead of failing. `wizard-layout.test.tsx` catches a\n * PRODUCT-side move in under a second and cannot see a mirror-side one;\n * `scripts/check-screen-sentinels.ts` compares the two literals directly, which is the\n * half that was missing. Its wording mirrors the step's tab in `wizard-tabs.tsx`.\n */\nconst STEP_DROPDOWN_LABEL: Partial<Record<WizardStep, string>> = {\n stack: \"Choose a stack\",\n domains: \"Select domains\",\n sources: \"Customize skill sources\",\n agents: \"Select agents\",\n};\n\n/**\n * What the wizard paints instead of itself while the terminal is below\n * `MIN_TERMINAL_SIZE` (consts.ts). It REPLACES the wizard tree rather than\n * covering it: Ink lays a still-mounted tree out at the small size regardless of\n * what is drawn on top, so an overlay leaves the squeezed content bleeding\n * underneath.\n */\nconst TerminalTooSmall: React.FC<{ columns: number }> = ({ columns }) => (\n <Box paddingX={1} paddingY={1}>\n <Text color={CLI_COLORS.WARNING}>{formatTerminalTooSmallMessage(columns)}</Text>\n </Box>\n);\n\nfunction resolveDropdownLabel(\n step: WizardStep,\n selectedStackId: string | null,\n): string | undefined {\n if (step === \"confirm\") {\n const stackName = getStackName(selectedStackId);\n return stackName ? `Ready to install ${stackName}` : \"Ready to install your custom stack\";\n }\n return STEP_DROPDOWN_LABEL[step];\n}\n\nexport const WizardLayout: React.FC<WizardLayoutProps> = ({\n version,\n logo,\n startupMessages = [],\n children,\n}) => {\n const store = useWizardStore();\n const { columns: terminalWidth, rows: terminalHeight } = useTerminalDimensions();\n\n // The startup gate cannot catch a terminal that shrinks after launch, and\n // `useTerminalDimensions` already re-renders on resize — so the same check\n // lives here, on the value that hook returns.\n if (!isTerminalLargeEnough(terminalWidth, terminalHeight)) {\n return <TerminalTooSmall columns={terminalWidth} />;\n }\n\n const { completedSteps, skippedSteps } = store.getStepProgress();\n\n const domainNav: DomainNavProps | undefined =\n store.step === \"build\" && store.selectedDomains.length > 0\n ? {\n domains: orderDomains(store.selectedDomains),\n activeDomain: store.getCurrentDomain() || store.selectedDomains[0] || FALLBACK_DOMAIN,\n getDomainLabel: getDomainDisplayName,\n }\n : undefined;\n\n // The logo is decoration; the stack list is the content. Below the threshold\n // its six rows starve that list's viewport until the shared scroll gate stops\n // clipping and the rows bleed over the footer.\n const terminalHasRoomForLogo = terminalHeight >= LOGO_MIN_TERMINAL_ROWS;\n const shouldRenderLogo = !!logo && store.step === \"stack\" && terminalHasRoomForLogo;\n\n const dropdownLabel = resolveDropdownLabel(store.step, store.selectedStackId);\n const dropdowns: Partial<Record<WizardStep, TabDropdownProps>> = dropdownLabel\n ? { [store.step]: { items: [{ id: dropdownLabel, label: dropdownLabel }] } }\n : {};\n\n return (\n <Box flexDirection=\"column\" paddingX={1} height={terminalHeight}>\n {shouldRenderLogo && (\n <Box flexDirection=\"row\" marginTop={1} columnGap={1}>\n <Text>{logo}</Text>\n </Box>\n )}\n <WizardTabs\n steps={wizardTabsFor(getActiveStepFlow())}\n currentStep={store.step}\n completedSteps={completedSteps}\n skippedSteps={skippedSteps}\n version={version}\n domainNav={domainNav}\n dropdowns={dropdowns}\n />\n <StartupMessages messages={startupMessages} terminalHeight={terminalHeight} />\n {store.showInfo ? (\n <>\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0} marginTop={1}>\n <SummaryPanel />\n </Box>\n <WizardFooter />\n </>\n ) : (\n <>\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0} marginTop={1}>\n {children}\n </Box>\n <Box paddingX={1} columnGap={2} marginTop={2}>\n <DefinitionItem\n label=\"Labels\"\n values={[HOTKEY_TOGGLE_LABELS.label]}\n isVisible={store.step === \"build\"}\n />\n <DefinitionItem\n label=\"Scope\"\n values={[HOTKEY_SCOPE.label]}\n isVisible={\n (store.step === \"build\" || store.step === \"agents\") &&\n !store.isEditingFromGlobalScope\n }\n />\n <DefinitionItem\n label=\"Info\"\n values={[HOTKEY_INFO.label]}\n isVisible={isInfoPanelAvailable(store.step)}\n />\n </Box>\n <WizardFooter />\n {store.toastMessage && (\n <Box position=\"absolute\" marginTop={terminalHeight - 4}>\n <Toast>{store.toastMessage}</Toast>\n </Box>\n )}\n </>\n )}\n </Box>\n );\n};\n","import { useState, useEffect } from \"react\";\nimport { useStdout } from \"ink\";\n\nconst DEFAULT_COLUMNS = 80;\nconst DEFAULT_ROWS = 24;\n\nexport type TerminalDimensions = {\n /** Terminal width in columns */\n columns: number;\n /** Terminal height in rows */\n rows: number;\n};\n\n/**\n * Tracks terminal dimensions reactively. Re-renders on resize.\n *\n * Falls back to DEFAULT_COLUMNS x DEFAULT_ROWS when stdout is not a TTY\n * (e.g., piped output, CI environments, tests).\n */\nexport function useTerminalDimensions(): TerminalDimensions {\n const { stdout } = useStdout();\n\n const [dimensions, setDimensions] = useState<TerminalDimensions>(() => ({\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n }));\n\n useEffect(() => {\n const handleResize = () => {\n setDimensions({\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n });\n };\n\n stdout.on(\"resize\", handleResize);\n return () => {\n stdout.off(\"resize\", handleResize);\n };\n }, [stdout]);\n\n return dimensions;\n}\n"],"mappings":"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","names":["Fragment"]}
|
|
@@ -2,18 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
SourceGrid,
|
|
4
4
|
isRowInert
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-GS2NZ3GD.js";
|
|
6
6
|
import {
|
|
7
7
|
useMeasuredHeight
|
|
8
8
|
} from "./chunk-TSIU7DME.js";
|
|
9
|
-
import {
|
|
10
|
-
HOTKEY_SET_ALL_LOCAL,
|
|
11
|
-
HOTKEY_SET_ALL_PLUGIN,
|
|
12
|
-
isHotkey
|
|
13
|
-
} from "./chunk-2HC2SNRP.js";
|
|
14
9
|
import {
|
|
15
10
|
useWizardStore
|
|
16
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-F5T6TV4Z.js";
|
|
17
12
|
|
|
18
13
|
// src/cli/components/wizard/step-sources.tsx
|
|
19
14
|
import { Box, useInput } from "ink";
|
|
@@ -29,13 +24,7 @@ var StepSources = ({ onContinue, onBack }) => {
|
|
|
29
24
|
},
|
|
30
25
|
[store]
|
|
31
26
|
);
|
|
32
|
-
useInput((
|
|
33
|
-
if (isHotkey(input, HOTKEY_SET_ALL_LOCAL)) {
|
|
34
|
-
store.setAllSourcesEject();
|
|
35
|
-
}
|
|
36
|
-
if (isHotkey(input, HOTKEY_SET_ALL_PLUGIN)) {
|
|
37
|
-
store.setAllSourcesPlugin();
|
|
38
|
-
}
|
|
27
|
+
useInput((_input, key) => {
|
|
39
28
|
if (key.return) {
|
|
40
29
|
onContinue();
|
|
41
30
|
}
|
|
@@ -56,4 +45,4 @@ var StepSources = ({ onContinue, onBack }) => {
|
|
|
56
45
|
export {
|
|
57
46
|
StepSources
|
|
58
47
|
};
|
|
59
|
-
//# sourceMappingURL=chunk-
|
|
48
|
+
//# sourceMappingURL=chunk-HTYH7CKN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/step-sources.tsx"],"sourcesContent":["import { Box, useInput } from \"ink\";\nimport React, { useCallback } from \"react\";\nimport { useWizardStore } from \"../../stores/wizard-store.js\";\nimport type { InstallMode, SkillId } from \"../../types/index.js\";\nimport { useMeasuredHeight } from \"../hooks/use-measured-height.js\";\nimport { isRowInert, SourceGrid } from \"./source-grid.js\";\n\nexport type StepSourcesProps = {\n onContinue: () => void;\n onBack: () => void;\n};\n\nexport const StepSources: React.FC<StepSourcesProps> = ({ onContinue, onBack }) => {\n const store = useWizardStore();\n const { ref: gridRef, measuredHeight: gridHeight } = useMeasuredHeight();\n\n const handleGridSelect = useCallback(\n (skillId: SkillId, mode: Exclude<InstallMode, \"mixed\">) => {\n // Thread the acting scope from the editable Sources row: a dual-scope skill renders only\n // its project row here, so the switch targets the project entry and leaves the masked\n // global tombstone untouched. SourceGrid only fires onSelect for non-inert rows, so the\n // sole editable row for this skill carries the acting scope.\n const actingRow = store\n .buildSourceRows()\n .find((row) => row.skillId === skillId && !isRowInert(row));\n store.setInstallMode(skillId, mode, actingRow?.scope);\n },\n [store],\n );\n\n // No character hotkeys. The step's only install-mode surface is SourceGrid's per-row\n // SPACE, which returns on an inert row — so a locked global row cannot be committed\n // from here at all. The withdrawn bulk keys `l` / `p` had no such containment.\n useInput((_input, key) => {\n if (key.return) {\n onContinue();\n }\n if (key.escape) {\n onBack();\n }\n });\n\n return (\n <Box ref={gridRef} flexGrow={1} flexBasis={0}>\n <SourceGrid\n rows={store.buildSourceRows()}\n availableHeight={gridHeight}\n onSelect={handleGridSelect}\n />\n </Box>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAAA,SAAS,KAAK,gBAAgB;AAC9B,SAAgB,mBAAmB;AA2C7B;AAhCC,IAAM,cAA0C,CAAC,EAAE,YAAY,OAAO,MAAM;AACjF,QAAM,QAAQ,eAAe;AAC7B,QAAM,EAAE,KAAK,SAAS,gBAAgB,WAAW,IAAI,kBAAkB;AAEvE,QAAM,mBAAmB;AAAA,IACvB,CAAC,SAAkB,SAAwC;AAKzD,YAAM,YAAY,MACf,gBAAgB,EAChB,KAAK,CAAC,QAAQ,IAAI,YAAY,WAAW,CAAC,WAAW,GAAG,CAAC;AAC5D,YAAM,eAAe,SAAS,MAAM,WAAW,KAAK;AAAA,IACtD;AAAA,IACA,CAAC,KAAK;AAAA,EACR;AAKA,WAAS,CAAC,QAAQ,QAAQ;AACxB,QAAI,IAAI,QAAQ;AACd,iBAAW;AAAA,IACb;AACA,QAAI,IAAI,QAAQ;AACd,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AAED,SACE,oBAAC,OAAI,KAAK,SAAS,UAAU,GAAG,WAAW,GACzC;AAAA,IAAC;AAAA;AAAA,MACC,MAAM,MAAM,gBAAgB;AAAA,MAC5B,iBAAiB;AAAA,MACjB,UAAU;AAAA;AAAA,EACZ,GACF;AAEJ;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CLI_COLORS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IO5YBKHV.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/components/wizard/wizard-tabs.tsx
|
|
7
7
|
import { Box, Text } from "ink";
|
|
@@ -169,4 +169,4 @@ export {
|
|
|
169
169
|
formatStepLabel,
|
|
170
170
|
WizardTabs
|
|
171
171
|
};
|
|
172
|
-
//# sourceMappingURL=chunk-
|
|
172
|
+
//# sourceMappingURL=chunk-HXKOIWLU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/wizard/wizard-tabs.tsx"],"sourcesContent":["import { Box, Text } from \"ink\";\nimport React from \"react\";\nimport { CLI_COLORS } from \"../../consts.js\";\nimport type { WizardStep } from \"../../stores/wizard-store.js\";\nimport type { Domain } from \"../../types/index.js\";\n\ntype WizardTabStep = {\n id: WizardStep;\n label: string;\n};\n\nexport type TabDropdownItem = {\n id: string;\n label: string;\n};\n\nexport type TabDropdownProps = {\n items: TabDropdownItem[];\n activeId?: string | undefined;\n isSubNav?: boolean | undefined;\n inline?: boolean | undefined;\n};\n\nexport type DomainNavProps = {\n domains: Domain[];\n activeDomain: Domain;\n getDomainLabel: (domain: Domain) => string;\n};\n\nexport type WizardTabsProps = {\n steps: WizardTabStep[];\n currentStep: WizardStep;\n completedSteps: WizardStep[];\n skippedSteps?: WizardStep[] | undefined;\n version?: string | undefined;\n domainNav?: DomainNavProps | undefined;\n dropdowns?: Partial<Record<WizardStep, TabDropdownProps>>;\n};\n\n/**\n * Display label per wizard step. Step ORDER has a single source: WIZARD_STEP_ORDER.\n *\n * The `sources` step is where a user picks where each skill comes from, so that is what\n * its tab is called. `e2e/pages/constants.ts` `WIZARD_TAB_LABELS` mirrors the whole set,\n * so a label moves in both places or in neither.\n */\nconst WIZARD_STEP_LABELS = {\n stack: \"Stack\",\n domains: \"Domains\",\n build: \"Skills\",\n sources: \"Sources\",\n agents: \"Agents\",\n confirm: \"Confirm\",\n} as const satisfies Record<WizardStep, string>;\n\n/**\n * The tabs for a step flow — one per step that flow runs, in its order.\n *\n * A function of the flow rather than a constant over `WIZARD_STEP_ORDER`: a\n * source that ships no stacks gives the wizard no stack step (see\n * `getActiveStepFlow`), and a bar drawn from every step the wizard HAS would\n * paint a Stack tab for a step this run never opens.\n */\nexport function wizardTabsFor(flow: WizardStep[]): WizardTabStep[] {\n return flow.map((id) => ({ id, label: WIZARD_STEP_LABELS[id] }));\n}\n\n/** Tab label for a wizard step. */\nexport function formatStepLabel(stepId: WizardStep): string {\n return WIZARD_STEP_LABELS[stepId];\n}\n\ntype StepState = \"completed\" | \"current\" | \"pending\" | \"skipped\";\n\nconst getStepState = (\n stepId: WizardStep,\n currentStep: WizardStep,\n completedSteps: WizardStep[],\n skippedSteps: WizardStep[],\n): StepState => {\n if (completedSteps.includes(stepId)) return \"completed\";\n if (stepId === currentStep) return \"current\";\n if (skippedSteps.includes(stepId)) return \"skipped\";\n return \"pending\";\n};\n\ntype TabProps = {\n step: WizardTabStep;\n state: StepState;\n};\n\nconst Tab: React.FC<TabProps> = ({ step, state }) => {\n const label = step.label;\n\n switch (state) {\n case \"current\":\n return (\n <Text color={CLI_COLORS.BLACK} backgroundColor={CLI_COLORS.WARNING} bold>\n {\" \"}\n {label}{\" \"}\n </Text>\n );\n case \"completed\":\n return <Text>{label}</Text>;\n case \"skipped\":\n return <Text dimColor>{label}</Text>;\n case \"pending\":\n return <Text color={CLI_COLORS.UNFOCUSED}>{label}</Text>;\n default: {\n const _exhaustive: never = state;\n return _exhaustive;\n }\n }\n};\n\nconst TabDropdown: React.FC<TabDropdownProps> = ({ items, activeId, isSubNav = false, inline }) => (\n <Box\n {...(inline ? {} : { position: \"absolute\" as const, marginTop: 2 })}\n flexDirection=\"row\"\n columnGap={0}\n paddingLeft={1}\n paddingRight={1}\n borderStyle=\"single\"\n borderColor=\"blackBright\"\n flexWrap=\"wrap\"\n >\n {items.map((item) => {\n const isActive = item.id === activeId;\n return (\n <Text\n key={item.id}\n dimColor={!isSubNav}\n bold={isSubNav && isActive}\n color={isActive ? CLI_COLORS.WARNING : CLI_COLORS.UNFOCUSED}\n >\n {\" \"}\n {item.label}{\" \"}\n </Text>\n );\n })}\n </Box>\n);\n\nconst DomainNav: React.FC<DomainNavProps & { inline?: boolean }> = ({\n domains,\n activeDomain,\n getDomainLabel,\n inline,\n}) => (\n <TabDropdown\n items={domains.map((d) => ({ id: d, label: getDomainLabel(d) }))}\n activeId={activeDomain}\n isSubNav\n inline={inline}\n />\n);\n\nconst DOMAIN_NAV_CHAR_THRESHOLD = 25;\n\nconst getStepJustifyContent = (stepId: WizardStep): \"flex-start\" | \"flex-end\" | \"center\" => {\n if (stepId === \"stack\") return \"flex-start\";\n if (stepId === \"confirm\") return \"flex-end\";\n return \"center\";\n};\n\nconst isDomainNavOverThreshold = (domainNav: DomainNavProps): boolean =>\n domainNav.domains.reduce((sum, d) => sum + domainNav.getDomainLabel(d).length, 0) >\n DOMAIN_NAV_CHAR_THRESHOLD;\n\nexport const WizardTabs: React.FC<WizardTabsProps> = ({\n steps,\n currentStep,\n completedSteps,\n skippedSteps = [],\n version,\n domainNav,\n dropdowns,\n}) => {\n const shouldHoistDomainNav = domainNav ? isDomainNavOverThreshold(domainNav) : false;\n\n return (\n <>\n <Box\n flexDirection=\"row\"\n columnGap={2}\n borderColor=\"blackBright\"\n borderStyle=\"single\"\n paddingX={1}\n alignItems=\"center\"\n marginBottom={shouldHoistDomainNav ? 0 : 3}\n >\n {steps.map((step) => {\n const state = getStepState(step.id, currentStep, completedSteps, skippedSteps);\n\n if (step.id === \"build\" && domainNav && !shouldHoistDomainNav) {\n return (\n <Box\n key={step.id}\n position=\"relative\"\n display=\"flex\"\n justifyContent={getStepJustifyContent(step.id)}\n >\n <Tab step={step} state={state} />\n <DomainNav {...domainNav} />\n </Box>\n );\n }\n\n // Generic dropdown for any step\n const dropdown = dropdowns?.[step.id];\n if (dropdown) {\n return (\n <Box\n key={step.id}\n position=\"relative\"\n display=\"flex\"\n justifyContent={getStepJustifyContent(step.id)}\n >\n <Tab step={step} state={state} />\n <TabDropdown {...dropdown} />\n </Box>\n );\n }\n\n return <Tab key={step.id} step={step} state={state} />;\n })}\n <Box flexGrow={1} justifyContent=\"flex-end\">\n <Text dimColor>{`v${version}`}</Text>\n </Box>\n </Box>\n {domainNav && shouldHoistDomainNav && (\n <Box>\n <DomainNav {...domainNav} inline />\n </Box>\n )}\n </>\n );\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
CLI_COLORS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IO5YBKHV.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/components/wizard/toast.tsx
|
|
7
7
|
import { Box, Text } from "ink";
|
|
@@ -25,4 +25,4 @@ var Toast = ({ children }) => {
|
|
|
25
25
|
export {
|
|
26
26
|
Toast
|
|
27
27
|
};
|
|
28
|
-
//# sourceMappingURL=chunk-
|
|
28
|
+
//# sourceMappingURL=chunk-ILUVL7WM.js.map
|
|
@@ -15,6 +15,8 @@ var PLUGINS_SUBDIR = "plugins";
|
|
|
15
15
|
var PLUGIN_MANIFEST_DIR = ".claude-plugin";
|
|
16
16
|
var PLUGIN_MANIFEST_FILE = "plugin.json";
|
|
17
17
|
var MARKETPLACE_JSON = "marketplace.json";
|
|
18
|
+
var CATALOG_JSON = "catalog.json";
|
|
19
|
+
var GENERATED_AT_BUILD = "build";
|
|
18
20
|
var PLUGINS_DIST_PATH = "dist/plugins";
|
|
19
21
|
function marketplaceManifestPath(dir) {
|
|
20
22
|
return path.join(dir, PLUGIN_MANIFEST_DIR, MARKETPLACE_JSON);
|
|
@@ -24,6 +26,9 @@ var GLOBAL_INSTALL_ROOT = os.homedir();
|
|
|
24
26
|
var CACHE_DIR = path.join(os.homedir(), ".cache", DEFAULT_PLUGIN_NAME);
|
|
25
27
|
var CLI_INVOKE_COMMAND = "npx agents-inc";
|
|
26
28
|
var EDITOR_URL = "https://agentsinc.sh";
|
|
29
|
+
function editorConfigUrl(id) {
|
|
30
|
+
return `${EDITOR_URL}/?fromId=${encodeURIComponent(id)}`;
|
|
31
|
+
}
|
|
27
32
|
var EDIT_PROJECT_SETUP_FLAG = "project-setup";
|
|
28
33
|
var SKILL_CATEGORIES_PATH = "config/skill-categories.ts";
|
|
29
34
|
var SKILL_RULES_PATH = "config/skill-rules.ts";
|
|
@@ -61,7 +66,8 @@ var STANDARD_FILES = {
|
|
|
61
66
|
CRITICAL_REQUIREMENTS_MD: "critical-requirements.md",
|
|
62
67
|
CRITICAL_REMINDERS_MD: "critical-reminders.md",
|
|
63
68
|
SETTINGS_JSON: "settings.json",
|
|
64
|
-
SETTINGS_LOCAL_JSON: "settings.local.json"
|
|
69
|
+
SETTINGS_LOCAL_JSON: "settings.local.json",
|
|
70
|
+
PACKAGE_JSON: "package.json"
|
|
65
71
|
};
|
|
66
72
|
var STANDARD_DIRS = {
|
|
67
73
|
EXAMPLES: "examples",
|
|
@@ -151,6 +157,7 @@ var DEFAULT_BRANDING = {
|
|
|
151
157
|
TAGLINE: "AI-powered development tools"
|
|
152
158
|
};
|
|
153
159
|
var DEFAULT_PUBLIC_SOURCE_NAME = DEFAULT_PLUGIN_NAME;
|
|
160
|
+
var PUBLIC_CATALOGUE_PACKAGE = "@agents-inc/skills";
|
|
154
161
|
var SOURCE_DISPLAY_NAMES = {
|
|
155
162
|
public: "Public",
|
|
156
163
|
eject: "Eject",
|
|
@@ -200,6 +207,8 @@ export {
|
|
|
200
207
|
PLUGIN_MANIFEST_DIR,
|
|
201
208
|
PLUGIN_MANIFEST_FILE,
|
|
202
209
|
MARKETPLACE_JSON,
|
|
210
|
+
CATALOG_JSON,
|
|
211
|
+
GENERATED_AT_BUILD,
|
|
203
212
|
PLUGINS_DIST_PATH,
|
|
204
213
|
marketplaceManifestPath,
|
|
205
214
|
DEFAULT_PLUGIN_NAME,
|
|
@@ -207,6 +216,7 @@ export {
|
|
|
207
216
|
CACHE_DIR,
|
|
208
217
|
CLI_INVOKE_COMMAND,
|
|
209
218
|
EDITOR_URL,
|
|
219
|
+
editorConfigUrl,
|
|
210
220
|
EDIT_PROJECT_SETUP_FLAG,
|
|
211
221
|
SKILL_CATEGORIES_PATH,
|
|
212
222
|
SKILL_RULES_PATH,
|
|
@@ -240,6 +250,7 @@ export {
|
|
|
240
250
|
LOGO_MIN_TERMINAL_ROWS,
|
|
241
251
|
DEFAULT_BRANDING,
|
|
242
252
|
DEFAULT_PUBLIC_SOURCE_NAME,
|
|
253
|
+
PUBLIC_CATALOGUE_PACKAGE,
|
|
243
254
|
INSTALL_MODES,
|
|
244
255
|
INSTALL_MODE_CELL_LABELS,
|
|
245
256
|
formatSourceDisplayName,
|
|
@@ -249,4 +260,4 @@ export {
|
|
|
249
260
|
FALLBACK_DOMAIN,
|
|
250
261
|
ASCII_LOGO
|
|
251
262
|
};
|
|
252
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-IO5YBKHV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/consts.ts"],"sourcesContent":["import os from \"os\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { Domain, InstallMode } from \"./types/index.js\";\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\n// After tsup build, dist/ is flat, so we go up one level from dist/ to get CLI root\n// In development (src/cli/consts.ts), we go up two levels\nconst isInDist = __dirname.includes(\"/dist\");\nconst CLI_ROOT = isInDist ? path.resolve(__dirname, \"..\") : path.resolve(__dirname, \"../..\");\nexport const PROJECT_ROOT = CLI_ROOT;\n\nexport const CLAUDE_DIR = \".claude\";\nexport const CLAUDE_SRC_DIR = \".claude-src\";\nexport const PLUGINS_SUBDIR = \"plugins\";\nexport const PLUGIN_MANIFEST_DIR = \".claude-plugin\";\nexport const PLUGIN_MANIFEST_FILE = \"plugin.json\";\nexport const MARKETPLACE_JSON = \"marketplace.json\";\n\n/**\n * The catalogue a marketplace publishes beside its manifest — its whole matrix\n * as JSON, in the shape `@workspace/matrix`'s `matrixSchema` describes.\n *\n * `marketplace.json` lists what a marketplace installs; this lists what it\n * OFFERS — every skill, category and stack, with the relationships resolved. The\n * editor fetches it directly and parses it with that schema, so nothing between\n * the two transforms it.\n */\nexport const CATALOG_JSON = \"catalog.json\";\n\n/**\n * What `generatedAt` says on a matrix that was WRITTEN to disk rather than built\n * in memory — a fixed word where the live matrix carries an ISO timestamp.\n *\n * A moment recorded in a committed artefact makes every regeneration a diff even\n * when nothing about the matrix moved, which costs the vendored\n * `types/generated/matrix.ts` a pull request of pure noise and costs\n * {@link CATALOG_JSON} its cache: the editor fetches the catalogue directly, and\n * a file whose bytes always change can never answer a conditional request.\n * Nothing reads the field back, so there is nothing a real timestamp would buy.\n *\n * Both emitters — `scripts/generate-source-types.ts` and `build marketplace` —\n * stamp this, and they are the only two places a matrix becomes a file.\n */\nexport const GENERATED_AT_BUILD = \"build\";\n\n/** Compiled plugin output directory, relative to a marketplace root */\nexport const PLUGINS_DIST_PATH = \"dist/plugins\";\n\n/** Path to the marketplace manifest inside a marketplace/source root. */\nexport function marketplaceManifestPath(dir: string): string {\n return path.join(dir, PLUGIN_MANIFEST_DIR, MARKETPLACE_JSON);\n}\nexport const DEFAULT_PLUGIN_NAME = \"agents-inc\";\n\n/** Home directory used as the root for global installations */\nexport const GLOBAL_INSTALL_ROOT = os.homedir();\n\nexport const CACHE_DIR = path.join(os.homedir(), \".cache\", DEFAULT_PLUGIN_NAME);\n\n/**\n * Promoted invocation prefix shown in user-facing messages (e.g. \"Run '<CLI_INVOKE_COMMAND> init'\").\n *\n * `bin` in package.json registers BOTH names — `agents-inc` (primary, matching this constant and\n * the package name) and `agentsinc` (kept so existing global installs keep working). A global\n * install therefore answers to either spelling.\n *\n * `agents-inc` rather than `agentsinc` because it is the published package name, so `npx\n * agents-inc` resolves with nothing installed, and it is what agentsinc.sh hands people when they\n * copy an install command.\n *\n * CONVENTION: every user-facing instruction in this repo — messages, docs, code comments, agent\n * playbooks — writes commands in this `npx agents-inc <cmd>` form. Prose that merely names a\n * command (\"the `agents-inc list` table\") does not.\n */\nexport const CLI_INVOKE_COMMAND = \"npx agents-inc\";\n\n/**\n * The editor — the web half of the product, where a configuration is built without the wizard\n * and handed to `init --from <id>`. `agentsinc.sh` is the editor Worker's custom domain\n * (`apps/editor/wrangler.jsonc`); the config store it posts to is the sibling\n * `api.agentsinc.sh`, spelled once in `lib/seed/fetch-seed.ts` because that one is\n * overridable for tests and this one is not.\n */\nexport const EDITOR_URL = \"https://agentsinc.sh\";\n\n/**\n * Where a shared configuration opens in the editor — the form the editor's own Share button\n * copies, so a link the CLI prints and one the web app hands out are the same link.\n *\n * Exported before it had a second caller, and now it has two: `share` prints it, and\n * `edit --ui` hands it to a browser. Two surfaces each building their own query string is\n * exactly how one of them ends up pointing at a page the other never opens.\n */\nexport function editorConfigUrl(id: string): string {\n return `${EDITOR_URL}/?fromId=${encodeURIComponent(id)}`;\n}\n\n/**\n * Internal `edit` flag marking the invocation as the project-setup half of a `cc init`\n * that routed through the dashboard. Not part of the documented CLI surface (declared\n * `hidden`): `init` is the only caller, and it passes the flag so `edit` can tell\n * \"set this project up\" apart from a bare inspection.\n */\nexport const EDIT_PROJECT_SETUP_FLAG = \"project-setup\";\n\nexport const SKILL_CATEGORIES_PATH = \"config/skill-categories.ts\";\nexport const SKILL_RULES_PATH = \"config/skill-rules.ts\";\nexport const STACKS_FILE_PATH = \"config/stacks.ts\";\n/** Source root directory inside a marketplace/source repo (holds skills/, agents/, etc.). */\nexport const SOURCE_SRC_DIR = \"src\";\nexport const SKILLS_DIR_PATH = `${SOURCE_SRC_DIR}/skills`;\nexport const LOCAL_SKILLS_PATH = \".claude/skills\";\n\n/** Synthetic source name for skills copied into the project (ejected) rather than installed as plugins. */\nexport const EJECT_SOURCE = \"eject\";\n\n/** Pseudo-category assigned to local skills — not a `Category` union member; category traversals skip it. */\nexport const LOCAL_PSEUDO_CATEGORY = \"local\";\n\nexport const DIRS = {\n agents: \"src/agents\",\n skills: SKILLS_DIR_PATH,\n stacks: \"src/stacks\",\n templates: \"src/agents/_templates\",\n commands: \"src/commands\",\n} as const;\n\n/** Single source for the metadata file name shared by skill and agent metadata. */\nconst METADATA_YAML_FILE = \"metadata.yaml\";\n\nexport const STANDARD_FILES = {\n SKILL_MD: \"SKILL.md\",\n METADATA_YAML: METADATA_YAML_FILE,\n METADATA_JSON: \"metadata.json\",\n CONFIG_YAML: \"config.yaml\",\n SKILL_CATEGORIES_TS: \"skill-categories.ts\",\n SKILL_RULES_TS: \"skill-rules.ts\",\n AGENT_METADATA_YAML: METADATA_YAML_FILE,\n PLUGIN_JSON: PLUGIN_MANIFEST_FILE,\n CONFIG_TS: \"config.ts\",\n CONFIG_TYPES_TS: \"config-types.ts\",\n CLAUDE_MD: \"CLAUDE.md\",\n README_MD: \"README.md\",\n REFERENCE_MD: \"reference.md\",\n IDENTITY_MD: \"identity.md\",\n PLAYBOOK_MD: \"playbook.md\",\n OUTPUT_MD: \"output.md\",\n CRITICAL_REQUIREMENTS_MD: \"critical-requirements.md\",\n CRITICAL_REMINDERS_MD: \"critical-reminders.md\",\n SETTINGS_JSON: \"settings.json\",\n SETTINGS_LOCAL_JSON: \"settings.local.json\",\n PACKAGE_JSON: \"package.json\",\n} as const;\n\nexport const STANDARD_DIRS = {\n EXAMPLES: \"examples\",\n SCRIPTS: \"scripts\",\n SKILLS: \"skills\",\n AGENTS: \"agents\",\n COMMANDS: \"commands\",\n /** Legacy per-project template override directory (`.claude/templates`). */\n TEMPLATES: \"templates\",\n} as const;\n\nexport const DEFAULT_VERSION = \"1.0.0\";\n\n// \"0.0.0\" indicates no version was explicitly set\nexport const DEFAULT_DISPLAY_VERSION = \"0.0.0\";\n\n// JSON Schema URLs for yaml-language-server $schema comments.\n// Uses raw.githubusercontent.com so schemas resolve without requiring the CLI as a dependency.\n// The prefix encodes two things that have each moved once: the repository name (renamed to\n// agents-inc/agents-inc on 2026-08-04, when it stopped being only the CLI) and this package's\n// location inside it (packages/cli, since the monorepo merge). If either moves again this must\n// move with it, or every generated $schema comment 404s. GitHub redirects the old forms — files\n// written before each move still resolve, verified two renames deep — but a redirect is a\n// courtesy, so what we emit should be the current address rather than rely on one.\nconst SCHEMA_PKG_PREFIX =\n \"https://raw.githubusercontent.com/agents-inc/agents-inc/main/packages/cli/src/schemas\";\n\nexport const SCHEMA_PATHS = {\n agent: `${SCHEMA_PKG_PREFIX}/agent.schema.json`,\n metadata: `${SCHEMA_PKG_PREFIX}/metadata.schema.json`,\n customMetadata: `${SCHEMA_PKG_PREFIX}/custom-metadata.schema.json`,\n marketplace: `${SCHEMA_PKG_PREFIX}/marketplace.schema.json`,\n projectConfig: `${SCHEMA_PKG_PREFIX}/project-config.schema.json`,\n projectSourceConfig: `${SCHEMA_PKG_PREFIX}/project-source-config.schema.json`,\n stacks: `${SCHEMA_PKG_PREFIX}/stacks.schema.json`,\n} as const;\n\nexport const YAML_FORMATTING = {\n INDENT: 2,\n LINE_WIDTH: 120,\n /** lineWidth: 0 disables wrapping — used for metadata files */\n LINE_WIDTH_NONE: 0,\n} as const;\n\n// Shared glyphs: SELECTED/CHECK render the same checkmark; SKIPPED/DISABLED the\n// same en-dash. Both keys are kept so call sites express intent, but the value\n// has a single source.\nconst CHECK_GLYPH = \"\\u2713\";\nconst EN_DASH_GLYPH = \"\\u2013\";\n\nexport const UI_SYMBOLS = {\n CHECKBOX_CHECKED: \"[x]\",\n CHECKBOX_UNCHECKED: \"[ ]\",\n CHEVRON: \"\\u276F\",\n CHEVRON_SPACER: \" \",\n SELECTED: CHECK_GLYPH,\n UNSELECTED: \"\\u25CB\",\n CURRENT: \"\\u25CF\",\n SKIPPED: EN_DASH_GLYPH,\n DISCOURAGED: \"!\",\n DISABLED: EN_DASH_GLYPH,\n LOCK: \"\\uD83D\\uDD12\",\n EJECT: \"\\u23CF\",\n BULLET: \"\\u2022\",\n SCROLL_UP: \"\\u25B2\",\n SCROLL_DOWN: \"\\u25BC\",\n CHECK: CHECK_GLYPH,\n CROSS: \"\\u2717\",\n /** Removed/pending-removal diff marker (ASCII hyphen). Info panel + Sources tab share it. */\n REMOVED: \"-\",\n /** Added/newly-selected diff marker (ASCII plus). Info panel + Sources tab share it. */\n ADDED: \"+\",\n} as const;\n\nexport const GITHUB_SOURCE = {\n HTTPS_PREFIX: \"https://github.com/\",\n GITHUB_PREFIX: \"github:\",\n GH_PREFIX: \"gh:\",\n} as const;\n\n/** Name written into a global-scope config's `name` field (`~/.claude-src/config.ts`). */\nexport const GLOBAL_CONFIG_NAME = \"global\";\n\n/** Strict kebab-case: starts with letter, segments separated by single hyphens, no trailing hyphens */\nexport const KEBAB_CASE_PATTERN = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;\n\n/** Author handle format: `@` followed by a lowercase-led alphanumeric-hyphen slug. */\nexport const AUTHOR_HANDLE_PATTERN = /^@[a-z][a-z0-9-]*$/;\n\nexport const HASH_PREFIX_LENGTH = 7;\n\n/** Hex chars from SHA-256 hash used in cache directory names (64 bits of collision resistance) */\nexport const CACHE_HASH_LENGTH = 16;\n\n/** Max chars of human-readable prefix in cache directory names (for debugging) */\nexport const CACHE_READABLE_PREFIX_LENGTH = 32;\n\n// File size limits for parsing boundaries (DoS prevention)\nconst ONE_MB = 1024 * 1024;\nexport const MAX_MARKETPLACE_FILE_SIZE = 10 * ONE_MB;\nexport const MAX_PLUGIN_FILE_SIZE = ONE_MB;\nexport const MAX_CONFIG_FILE_SIZE = ONE_MB;\n\nexport const MAX_JSON_NESTING_DEPTH = 10;\nexport const MAX_MARKETPLACE_PLUGINS = 10_000;\n\nexport const SCROLL_VIEWPORT = {\n /** Height of the \"N more above\" scroll indicator */\n SCROLL_INDICATOR_HEIGHT: 1,\n /** Estimated lines per category name row (including top margin) */\n CATEGORY_NAME_LINES: 2,\n /** Margin between category sections (marginTop on CategorySection) */\n CATEGORY_MARGIN_LINES: 1,\n /** Minimum rows to show at least 1 category before enabling scroll */\n MIN_VIEWPORT_ROWS: 5,\n} as const;\n\n/**\n * The terminal geometry every command refuses to run below. This is the only\n * minimum-size gate there is: `BaseCommand.ensureTerminalSize` reads it and\n * blocks until the terminal is at least this big, so raising `ROWS` raises the\n * bar for the whole CLI, tests included.\n *\n * `ROWS: 20` is measured, not guessed. Driving the real binary to the build\n * step — the binding constraint, since it is the tallest step — gives:\n * 15/16/17 corrupt (overlapping card borders, unreadable); 18 the first clean\n * render (one complete category card, correctly clipped); 20 clean with one\n * full card plus the next category heading; 24 comfortable. 18 is the hard\n * correctness floor because it is where {@link SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS}\n * starts being satisfied — below it the shared scroll gate stops clipping and\n * the grid bleeds over its borders. 20 buys two rows of margin above that floor\n * while staying under the 24-row default of common terminals.\n */\nexport const MIN_TERMINAL_SIZE = {\n COLS: 80,\n ROWS: 20,\n} as const;\n\n/**\n * The terminal height at or above which the stack step paints the six-row ASCII\n * logo. Below it the logo is dropped — it is decoration, and the stack list is\n * the content.\n *\n * This is NOT a second size gate. {@link MIN_TERMINAL_SIZE} decides whether a\n * command runs at all; this decides only whether one decorative element renders\n * inside a terminal that already cleared that gate. Conflating them would be a\n * regression in both directions: raising `MIN_TERMINAL_SIZE.ROWS` to 26 would\n * refuse to run in the 24-row terminal that is still a common default, and\n * lowering this to 20 brings back the bleed below.\n *\n * 26 is measured against the real binary at 100 columns, on the stack step:\n *\n * | rows | stack step with the logo rendered |\n * | ---- | ----------------------------------------------------------------- |\n * | 20 | bleeds — stack rows paint over the \"Start from scratch\" row |\n * | 24 | bleeds — stack rows paint through the hotkey row and the footer |\n * | 26 | clean |\n * | 27 | clean |\n * | 28 | clean |\n *\n * The mechanism: the logo eats six rows of the stack step's list viewport,\n * starving it below {@link SCROLL_VIEWPORT.MIN_VIEWPORT_ROWS}, at which point\n * the shared scroll hooks stop clipping and the rows bleed. Hiding the logo\n * returns those rows to the viewport; the bail-instead-of-clip behaviour itself\n * is untouched and remains the open underlying defect.\n */\nexport const LOGO_MIN_TERMINAL_ROWS = 26;\n\nexport const DEFAULT_BRANDING = {\n NAME: \"Agents Inc.\",\n TAGLINE: \"AI-powered development tools\",\n} as const;\n\n/**\n * Fallback name for the default public marketplace when marketplace.json is\n * unavailable. Same value as `DEFAULT_PLUGIN_NAME` but a distinct concept: this\n * is the resolved source/marketplace name, that is the plugin bundle name.\n */\nexport const DEFAULT_PUBLIC_SOURCE_NAME = DEFAULT_PLUGIN_NAME;\n\n/**\n * The npm package the public catalogue publishes from, and the one thing that\n * tells the catalogue apart from a marketplace merely calling itself\n * {@link DEFAULT_PUBLIC_SOURCE_NAME}.\n *\n * Nothing a marketplace ships is unforgeable — every signal is a string in a file\n * its author controls, this one included. What it does is make the reserved\n * namespace unreachable by ACCIDENT: taking it requires renaming your own package\n * to the catalogue's published, npm-scope-governed name, which is impersonation\n * rather than drift.\n *\n * Two guards read it and must agree, which is why it lives here rather than in\n * either: `validateMarketplaceName` (`lib/marketplace-generator.ts`) exempts the\n * catalogue from the reserved-name refusal at BUILD time, and the collision guard\n * in `lib/loading/source-loader.ts` exempts it from the catalogue-id refusal at\n * LOAD time. Two definitions of who the catalogue is would let a source be the\n * catalogue to one guard and not to the other.\n */\nexport const PUBLIC_CATALOGUE_PACKAGE = \"@agents-inc/skills\";\n\n/** Human-readable labels for skill source types shown in the wizard and edit command */\nexport const SOURCE_DISPLAY_NAMES: Record<string, string> = {\n public: \"Public\",\n eject: \"Eject\",\n \"agents-inc\": \"Agents Inc\",\n};\n\n/** The two install modes a Sources row offers, in the order the grid renders them. */\nexport const INSTALL_MODES = [\"eject\", \"plugin\"] as const satisfies readonly Exclude<\n InstallMode,\n \"mixed\"\n>[];\n\n/**\n * How the Sources grid captions each of its two cells.\n *\n * Deliberately not `INSTALL_MODE_LABELS` (`Eject`/`Plugin`), which names a mode by what it does\n * to the files, nor `SOURCE_DISPLAY_NAMES`, which labels a `SkillConfig.origin` VALUE on the\n * summary surfaces. The grid asks where the skill should LIVE, and the two answers are the\n * project's own copy or the marketplace plugin — so the cells read `Local` and `Plugin`, which\n * is also the two-state badge the editor settled on (`.claude-design/DECISIONS.md`).\n */\nexport const INSTALL_MODE_CELL_LABELS = {\n eject: \"Local\",\n plugin: \"Plugin\",\n} as const satisfies Record<Exclude<InstallMode, \"mixed\">, string>;\n\n/** Resolves a source name to its human-readable display label. */\nexport function formatSourceDisplayName(source: string): string {\n return SOURCE_DISPLAY_NAMES[source] ?? source;\n}\n\n/**\n * Marketplace-row value when skills are selected but every one of them is `EJECT_SOURCE`. \"eject\"\n * names no marketplace, so there is nothing to list — but the selection is not empty either, and\n * naming the default public marketplace would claim an origin none of those skills has.\n */\nexport const ALL_SKILLS_EJECTED_LABEL = \"All skills ejected\";\n\n// TODO: update naming convention to GRAY_1,2, etc\nexport const CLI_COLORS = {\n PRIMARY: \"#99FFFF\",\n SUCCESS: \"#90EE90\",\n ERROR: \"#DC343B\",\n WARNING: \"#E6A817\",\n INFO: \"#3B82F6\",\n NEUTRAL: \"#888888\",\n FOCUS: \"#87CEFA\",\n UNFOCUSED: \"#FFFFFF\",\n WHITE: \"#FFFFFF\",\n BLACK: \"#000000\",\n DIM: \"#666666\",\n GRAY_1: \"#ddd\",\n LABEL_BG: \"#383838\",\n TOAST_BG: \"#EEEEEE\",\n TOAST_FG: \"#000000\",\n HOVER_BG: \"#333333\",\n} as const;\n\n/** Default domains pre-selected when \"Start from scratch\" is chosen (all except CLI) */\nexport const DEFAULT_SCRATCH_DOMAINS: readonly Domain[] = [\"web\", \"api\", \"mobile\"];\n\n/** Domain used when no active domain can be resolved from wizard state. */\nexport const FALLBACK_DOMAIN: Domain = \"web\";\n\nexport const ASCII_LOGO = ` █████╗ ██████╗ ███████╗███╗ ██╗████████╗███████╗ ██╗███╗ ██╗ ██████╗\n██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝██╔════╝ ██║████╗ ██║██╔════╝\n███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ███████╗ ██║██╔██╗ ██║██║\n██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ╚════██║ ██║██║╚██╗██║██║\n██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ███████║ ██║██║ ╚████║╚██████╗\n╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝`;\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
Wizard
|
|
4
|
+
} from "./chunk-TNGMF4UX.js";
|
|
5
|
+
import {
|
|
6
|
+
promptValue
|
|
7
|
+
} from "./chunk-JCPANDNR.js";
|
|
8
|
+
import {
|
|
9
|
+
hydrateWizardStore
|
|
10
|
+
} from "./chunk-F5T6TV4Z.js";
|
|
11
|
+
import {
|
|
12
|
+
disableBuffering,
|
|
13
|
+
drainBuffer,
|
|
14
|
+
enableBuffering
|
|
15
|
+
} from "./chunk-XAXJWXI4.js";
|
|
16
|
+
|
|
17
|
+
// src/cli/components/wizard/run-wizard-session.tsx
|
|
18
|
+
import "react";
|
|
19
|
+
import { jsx } from "react/jsx-runtime";
|
|
20
|
+
function hydrateIntoStartupBand(hydrate, loaded = []) {
|
|
21
|
+
enableBuffering();
|
|
22
|
+
try {
|
|
23
|
+
hydrateWizardStore(hydrate);
|
|
24
|
+
return [...loaded, ...drainBuffer()];
|
|
25
|
+
} finally {
|
|
26
|
+
disableBuffering();
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async function runWizardSession(options) {
|
|
30
|
+
const startupMessages = hydrateIntoStartupBand(options.hydrate, options.props.startupMessages);
|
|
31
|
+
const result = await promptValue(
|
|
32
|
+
(resolve) => /* @__PURE__ */ jsx(
|
|
33
|
+
Wizard,
|
|
34
|
+
{
|
|
35
|
+
...options.props,
|
|
36
|
+
startupMessages,
|
|
37
|
+
onComplete: resolve,
|
|
38
|
+
onCancel: () => {
|
|
39
|
+
options.onCancel();
|
|
40
|
+
resolve(null);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
),
|
|
44
|
+
{ onExit: null, clearOnResolve: true }
|
|
45
|
+
);
|
|
46
|
+
options.clearTerminal();
|
|
47
|
+
return !result || result.cancelled ? null : result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
runWizardSession
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=chunk-IXRZAHZF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
render
|
|
4
|
+
} from "./chunk-JFLVEFFP.js";
|
|
5
|
+
|
|
6
|
+
// src/cli/components/common/prompt-confirm.tsx
|
|
7
|
+
import "react";
|
|
8
|
+
async function promptValue(build, options) {
|
|
9
|
+
const answer = { settle: () => {
|
|
10
|
+
} };
|
|
11
|
+
const chosen = new Promise((resolve) => {
|
|
12
|
+
answer.settle = resolve;
|
|
13
|
+
});
|
|
14
|
+
const instance = render(build((value2) => answer.settle(value2)));
|
|
15
|
+
instance.waitUntilExit().then(
|
|
16
|
+
() => answer.settle(options.onExit),
|
|
17
|
+
() => answer.settle(options.onExit)
|
|
18
|
+
);
|
|
19
|
+
const value = await chosen;
|
|
20
|
+
if (options.clearOnResolve) instance.clear();
|
|
21
|
+
instance.unmount();
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
async function promptConfirm(build) {
|
|
25
|
+
return promptValue(
|
|
26
|
+
(resolve) => build({ onConfirm: () => resolve("confirmed"), onCancel: () => resolve("cancelled") }),
|
|
27
|
+
{ onExit: "cancelled" }
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
promptValue,
|
|
33
|
+
promptConfirm
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=chunk-JCPANDNR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/common/prompt-confirm.tsx"],"sourcesContent":["import React from \"react\";\nimport { render } from \"../render.js\";\n\nexport type ConfirmHandlers = {\n onConfirm: () => void;\n onCancel: () => void;\n};\n\nexport type PromptValueOptions<T> = {\n /** Value resolved when the Ink app exits before any callback fires (Ctrl+C / render failure). */\n onExit: T;\n /** Call instance.clear() before unmount — repaints a clean terminal (used by the dashboard). */\n clearOnResolve?: boolean;\n};\n\n/**\n * Renders an Ink prompt and resolves with the value produced by its callbacks.\n * First-wins: the first resolve (a callback or the app-exit fallback) settles the\n * promise; later resolves are ignored. The element is unmounted at the resolution\n * site (optionally cleared first). Callers own exit policy (exit codes, logging).\n *\n * A prompt may resolve before `render()` has handed its instance back: Ink flushes\n * mount effects synchronously, so a component that settles on mount reaches the\n * callback first. The teardown is then run the moment the instance exists — one\n * statement later, on the same tick — so callers that resolve from a keypress see\n * exactly the order they always did.\n */\nexport async function promptValue<T>(\n build: (resolve: (value: T) => void) => React.ReactElement,\n options: PromptValueOptions<T>,\n): Promise<T> {\n // The promise's own `resolve`, lifted out so the render can be a plain `const` below\n // rather than a binding the element's callbacks would reach while `render()` is still\n // producing it. The seed is never called: a Promise executor runs synchronously, so the\n // next statement has already replaced it by the time anything can answer.\n const answer: { settle: (value: T) => void } = { settle: () => {} };\n const chosen = new Promise<T>((resolve) => {\n answer.settle = resolve;\n });\n\n const instance = render(build((value) => answer.settle(value)));\n\n // App exit without a callback (e.g. Ctrl+C) or a render failure counts as the\n // fallback; the promise is first-wins, so a prior callback value is unaffected.\n instance.waitUntilExit().then(\n () => answer.settle(options.onExit),\n () => answer.settle(options.onExit),\n );\n\n const value = await chosen;\n\n // Taken down here rather than at each resolve site: it then happens exactly once,\n // whichever of the three endings settled the promise, and always with an instance in\n // hand — including the ending that arrives before `render()` has returned one.\n if (options.clearOnResolve) instance.clear();\n instance.unmount();\n\n return value;\n}\n\n/**\n * Renders a confirm UI and resolves with the user's choice. The element is\n * unmounted as soon as either handler fires; a clean exit or render failure\n * without a choice resolves as \"cancelled\". Callers own exit policy.\n */\nexport async function promptConfirm(\n build: (handlers: ConfirmHandlers) => React.ReactElement,\n): Promise<\"confirmed\" | \"cancelled\"> {\n return promptValue<\"confirmed\" | \"cancelled\">(\n (resolve) =>\n build({ onConfirm: () => resolve(\"confirmed\"), onCancel: () => resolve(\"cancelled\") }),\n { onExit: \"cancelled\" },\n );\n}\n"],"mappings":";;;;;;AAAA,OAAkB;AA2BlB,eAAsB,YACpB,OACA,SACY;AAKZ,QAAM,SAAyC,EAAE,QAAQ,MAAM;AAAA,EAAC,EAAE;AAClE,QAAM,SAAS,IAAI,QAAW,CAAC,YAAY;AACzC,WAAO,SAAS;AAAA,EAClB,CAAC;AAED,QAAM,WAAW,OAAO,MAAM,CAACA,WAAU,OAAO,OAAOA,MAAK,CAAC,CAAC;AAI9D,WAAS,cAAc,EAAE;AAAA,IACvB,MAAM,OAAO,OAAO,QAAQ,MAAM;AAAA,IAClC,MAAM,OAAO,OAAO,QAAQ,MAAM;AAAA,EACpC;AAEA,QAAM,QAAQ,MAAM;AAKpB,MAAI,QAAQ,eAAgB,UAAS,MAAM;AAC3C,WAAS,QAAQ;AAEjB,SAAO;AACT;AAOA,eAAsB,cACpB,OACoC;AACpC,SAAO;AAAA,IACL,CAAC,YACC,MAAM,EAAE,WAAW,MAAM,QAAQ,WAAW,GAAG,UAAU,MAAM,QAAQ,WAAW,EAAE,CAAC;AAAA,IACvF,EAAE,QAAQ,YAAY;AAAA,EACxB;AACF;","names":["value"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SummaryPanel
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-6RLV45HN.js";
|
|
5
5
|
|
|
6
6
|
// src/cli/components/wizard/step-confirm.tsx
|
|
7
7
|
import { useInput } from "ink";
|
|
@@ -22,4 +22,4 @@ var StepConfirm = ({ onComplete, onBack }) => {
|
|
|
22
22
|
export {
|
|
23
23
|
StepConfirm
|
|
24
24
|
};
|
|
25
|
-
//# sourceMappingURL=chunk-
|
|
25
|
+
//# sourceMappingURL=chunk-LJCNUP6M.js.map
|