agents-inc 0.168.0 → 0.170.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/README.md +18 -15
- package/dist/{chunk-JIBCVXXL.js → chunk-3G7X2WKI.js} +4 -4
- package/dist/{chunk-JOEA52NR.js → chunk-44TE3RKH.js} +46 -2
- package/dist/chunk-44TE3RKH.js.map +1 -0
- package/dist/{chunk-NU2K5G54.js → chunk-52HDHJ7I.js} +11 -19
- package/dist/chunk-52HDHJ7I.js.map +1 -0
- package/dist/{chunk-EH2PGPLP.js → chunk-6HNXYYVF.js} +39 -22
- package/dist/chunk-6HNXYYVF.js.map +1 -0
- package/dist/{chunk-4UKMQUAU.js → chunk-6ZRH5RHC.js} +10 -11
- package/dist/chunk-6ZRH5RHC.js.map +1 -0
- package/dist/{chunk-5JUQKGCP.js → chunk-7RDMTR64.js} +14 -34
- package/dist/chunk-7RDMTR64.js.map +1 -0
- package/dist/{chunk-3LZNY46H.js → chunk-BMRUNMPV.js} +4 -4
- package/dist/{chunk-VVRI35SK.js → chunk-CLPUWOSA.js} +4 -4
- package/dist/{chunk-VVRI35SK.js.map → chunk-CLPUWOSA.js.map} +1 -1
- package/dist/{chunk-TW35AEB4.js → chunk-F2BHT5C4.js} +9 -7
- package/dist/chunk-F2BHT5C4.js.map +1 -0
- package/dist/{chunk-27AVGFXH.js → chunk-F5EBEATU.js} +2 -2
- package/dist/{chunk-GE7NUPMI.js → chunk-HED2DAXZ.js} +3 -3
- package/dist/{chunk-7PYXS2QU.js → chunk-KOLDW6SF.js} +3 -3
- package/dist/{chunk-7PYXS2QU.js.map → chunk-KOLDW6SF.js.map} +1 -1
- package/dist/{chunk-C2UISKIM.js → chunk-MQ6CGZNJ.js} +109 -422
- package/dist/chunk-MQ6CGZNJ.js.map +1 -0
- package/dist/{chunk-P6I72PR3.js → chunk-NCWDK6L7.js} +115 -196
- package/dist/chunk-NCWDK6L7.js.map +1 -0
- package/dist/{chunk-VRXX4D6K.js → chunk-NEZ4OAOL.js} +1 -1
- package/dist/chunk-NEZ4OAOL.js.map +1 -0
- package/dist/chunk-NIHUOWE4.js +106 -0
- package/dist/chunk-NIHUOWE4.js.map +1 -0
- package/dist/{chunk-OI2H6M5I.js → chunk-NQW25DCF.js} +2 -2
- package/dist/chunk-NQW25DCF.js.map +1 -0
- package/dist/{chunk-ZUGH4MQG.js → chunk-OYJQUA3D.js} +3 -3
- package/dist/{chunk-ZUGH4MQG.js.map → chunk-OYJQUA3D.js.map} +1 -1
- package/dist/{chunk-AG3ZVM3B.js → chunk-PJWGTNOX.js} +186 -210
- package/dist/chunk-PJWGTNOX.js.map +1 -0
- package/dist/{chunk-HR7TK2XW.js → chunk-RIPSGNLU.js} +3 -3
- package/dist/chunk-RIPSGNLU.js.map +1 -0
- package/dist/{chunk-4DRFEYCE.js → chunk-SZYQISA2.js} +7 -7
- package/dist/chunk-SZYQISA2.js.map +1 -0
- package/dist/{chunk-W6GO2CYX.js → chunk-USVBYQSQ.js} +2 -2
- package/dist/{chunk-H4ZKGGTE.js → chunk-V3KTSP3Q.js} +50 -42
- package/dist/chunk-V3KTSP3Q.js.map +1 -0
- package/dist/{chunk-KTLKR4YY.js → chunk-WTWMGH2C.js} +2 -2
- package/dist/commands/build/marketplace.js +23 -22
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +8 -9
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/compile.js +19 -20
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +17 -18
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +118 -297
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +21 -33
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/init.js +17 -45
- package/dist/commands/list.js +19 -17
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +11 -11
- package/dist/commands/new/marketplace.js.map +1 -1
- package/dist/commands/search.js +12 -13
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/share.js +11 -12
- package/dist/commands/share.js.map +1 -1
- package/dist/commands/uninstall.js +18 -20
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +8 -9
- package/dist/commands/update.js.map +1 -1
- package/dist/components/common/removal-plan-confirm.js +2 -2
- package/dist/components/common/scroll-affordance.js +9 -0
- package/dist/components/common/select-list.js +2 -3
- package/dist/components/common/skill-agent-summary.js +11 -0
- package/dist/components/common/spinner.js +1 -1
- package/dist/{chunk-QWFG7Y3R.js → components/common/summary-panel.js} +57 -31
- package/dist/components/common/summary-panel.js.map +1 -0
- package/dist/config-exports.js +1 -1
- package/dist/hooks/init.js +18 -46
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-YMDWBFDP.js +14 -0
- package/dist/recompile-project-agents-SZ76WNTW.js +18 -0
- package/dist/{source-loader-FRJTCSDL.js → source-loader-C5SQXZXI.js} +5 -5
- package/dist/src/agents/meta/codex-keeper/playbook.md +2 -3
- package/package.json +2 -3
- package/src/agents/meta/codex-keeper/playbook.md +2 -3
- package/src/schemas/project-config.schema.json +1 -1
- package/assets/demo.tape +0 -266
- package/dist/chunk-23DNVNFP.js +0 -292
- package/dist/chunk-23DNVNFP.js.map +0 -1
- package/dist/chunk-3DIDV6H3.js +0 -268
- package/dist/chunk-3DIDV6H3.js.map +0 -1
- package/dist/chunk-4DRFEYCE.js.map +0 -1
- package/dist/chunk-4HWOYYY7.js +0 -92
- package/dist/chunk-4HWOYYY7.js.map +0 -1
- package/dist/chunk-4UKMQUAU.js.map +0 -1
- package/dist/chunk-5JUQKGCP.js.map +0 -1
- package/dist/chunk-6WGXTB2L.js +0 -28
- package/dist/chunk-6WGXTB2L.js.map +0 -1
- package/dist/chunk-AG3ZVM3B.js.map +0 -1
- package/dist/chunk-C2UISKIM.js.map +0 -1
- package/dist/chunk-CMJBKQUH.js +0 -23
- package/dist/chunk-CMJBKQUH.js.map +0 -1
- package/dist/chunk-DJEO3F2H.js +0 -230
- package/dist/chunk-DJEO3F2H.js.map +0 -1
- package/dist/chunk-EH2PGPLP.js.map +0 -1
- package/dist/chunk-GRL73YPF.js +0 -197
- package/dist/chunk-GRL73YPF.js.map +0 -1
- package/dist/chunk-H4ZKGGTE.js.map +0 -1
- package/dist/chunk-HI6YB7XP.js +0 -59
- package/dist/chunk-HI6YB7XP.js.map +0 -1
- package/dist/chunk-HL3GYRMR.js +0 -17
- package/dist/chunk-HL3GYRMR.js.map +0 -1
- package/dist/chunk-HR7TK2XW.js.map +0 -1
- package/dist/chunk-JOEA52NR.js.map +0 -1
- package/dist/chunk-JPMV4E4E.js +0 -118
- package/dist/chunk-JPMV4E4E.js.map +0 -1
- package/dist/chunk-JVUN6AOO.js +0 -237
- package/dist/chunk-JVUN6AOO.js.map +0 -1
- package/dist/chunk-KQ3PDARZ.js +0 -25
- package/dist/chunk-KQ3PDARZ.js.map +0 -1
- package/dist/chunk-L3W2JWBA.js +0 -168
- package/dist/chunk-L3W2JWBA.js.map +0 -1
- package/dist/chunk-LFUJCRCT.js +0 -27
- package/dist/chunk-LFUJCRCT.js.map +0 -1
- package/dist/chunk-NU2K5G54.js.map +0 -1
- package/dist/chunk-OI2H6M5I.js.map +0 -1
- package/dist/chunk-P6I72PR3.js.map +0 -1
- package/dist/chunk-PCFUXQJA.js +0 -317
- package/dist/chunk-PCFUXQJA.js.map +0 -1
- package/dist/chunk-PLX2FLEQ.js +0 -48
- package/dist/chunk-PLX2FLEQ.js.map +0 -1
- package/dist/chunk-QWFG7Y3R.js.map +0 -1
- package/dist/chunk-SLBL3WIP.js +0 -121
- package/dist/chunk-SLBL3WIP.js.map +0 -1
- package/dist/chunk-TSIU7DME.js +0 -43
- package/dist/chunk-TSIU7DME.js.map +0 -1
- package/dist/chunk-TW35AEB4.js.map +0 -1
- package/dist/chunk-VRXX4D6K.js.map +0 -1
- package/dist/chunk-W5KEYSOL.js +0 -51
- package/dist/chunk-W5KEYSOL.js.map +0 -1
- package/dist/chunk-WNLF5EDZ.js +0 -1170
- package/dist/chunk-WNLF5EDZ.js.map +0 -1
- package/dist/chunk-WTJ3AY33.js +0 -31
- package/dist/chunk-WTJ3AY33.js.map +0 -1
- package/dist/chunk-X6ZZEYO3.js +0 -53
- package/dist/chunk-X6ZZEYO3.js.map +0 -1
- package/dist/chunk-XQHZPINL.js +0 -89
- package/dist/chunk-XQHZPINL.js.map +0 -1
- package/dist/chunk-YN3SWF53.js +0 -35
- package/dist/chunk-YN3SWF53.js.map +0 -1
- package/dist/components/wizard/category-grid.js +0 -13
- package/dist/components/wizard/checkbox-grid.js +0 -12
- package/dist/components/wizard/domain-selection.js +0 -18
- package/dist/components/wizard/run-wizard-session.js +0 -40
- package/dist/components/wizard/run-wizard-session.js.map +0 -1
- package/dist/components/wizard/scroll-affordance.js +0 -9
- package/dist/components/wizard/skill-agent-summary.js +0 -13
- package/dist/components/wizard/source-grid.js +0 -16
- package/dist/components/wizard/source-grid.js.map +0 -1
- package/dist/components/wizard/stack-selection.js +0 -17
- package/dist/components/wizard/stack-selection.js.map +0 -1
- package/dist/components/wizard/step-agents.js +0 -18
- package/dist/components/wizard/step-agents.js.map +0 -1
- package/dist/components/wizard/step-build.js +0 -18
- package/dist/components/wizard/step-build.js.map +0 -1
- package/dist/components/wizard/step-confirm.js +0 -18
- package/dist/components/wizard/step-confirm.js.map +0 -1
- package/dist/components/wizard/step-sources.js +0 -19
- package/dist/components/wizard/step-sources.js.map +0 -1
- package/dist/components/wizard/step-stack.js +0 -18
- package/dist/components/wizard/step-stack.js.map +0 -1
- package/dist/components/wizard/summary-panel.js +0 -17
- package/dist/components/wizard/summary-panel.js.map +0 -1
- package/dist/components/wizard/toast.js +0 -9
- package/dist/components/wizard/toast.js.map +0 -1
- package/dist/components/wizard/wizard-layout.js +0 -22
- package/dist/components/wizard/wizard-layout.js.map +0 -1
- package/dist/components/wizard/wizard-tabs.js +0 -11
- package/dist/components/wizard/wizard-tabs.js.map +0 -1
- package/dist/components/wizard/wizard.js +0 -39
- package/dist/components/wizard/wizard.js.map +0 -1
- package/dist/load-agent-defs-5XMVB3MU.js +0 -14
- package/dist/load-agent-defs-5XMVB3MU.js.map +0 -1
- package/dist/recompile-project-agents-7PQWYQ6B.js +0 -18
- package/dist/recompile-project-agents-7PQWYQ6B.js.map +0 -1
- package/dist/source-loader-FRJTCSDL.js.map +0 -1
- package/dist/stores/wizard-store.js +0 -24
- package/dist/stores/wizard-store.js.map +0 -1
- /package/assets/{demo.gif → legacy-wizard.gif} +0 -0
- /package/dist/{chunk-JIBCVXXL.js.map → chunk-3G7X2WKI.js.map} +0 -0
- /package/dist/{chunk-3LZNY46H.js.map → chunk-BMRUNMPV.js.map} +0 -0
- /package/dist/{chunk-27AVGFXH.js.map → chunk-F5EBEATU.js.map} +0 -0
- /package/dist/{chunk-GE7NUPMI.js.map → chunk-HED2DAXZ.js.map} +0 -0
- /package/dist/{chunk-W6GO2CYX.js.map → chunk-USVBYQSQ.js.map} +0 -0
- /package/dist/{chunk-KTLKR4YY.js.map → chunk-WTWMGH2C.js.map} +0 -0
- /package/dist/components/{wizard → common}/scroll-affordance.js.map +0 -0
- /package/dist/components/{wizard → common}/skill-agent-summary.js.map +0 -0
- /package/dist/{components/wizard/category-grid.js.map → load-agent-defs-YMDWBFDP.js.map} +0 -0
- /package/dist/{components/wizard/checkbox-grid.js.map → recompile-project-agents-SZ76WNTW.js.map} +0 -0
- /package/dist/{components/wizard/domain-selection.js.map → source-loader-C5SQXZXI.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/init.tsx","../src/cli/components/hooks/use-terminal-dimensions.ts","../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 { InstallSelection } from \"@workspace/compile/seed-to-config\";\nimport { useTerminalDimensions } from \"../components/hooks/use-terminal-dimensions.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport {\n loadSource,\n sayCapturedWarnings,\n loadAgentDefs,\n copyLocalSkills,\n writeProjectConfig,\n compileAgentsAllScopes,\n compileProjectScope,\n type CompilationResult,\n type SkillCopyResult,\n discoverInstalledSkills,\n} from \"../lib/operations/index.js\";\nimport { movedGlobalAgentInputs, type GateReport } from \"../lib/config-gate/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 { seedToInstallSelection, type SeedMapping } from \"../lib/seed/seed-to-selection.js\";\nimport {\n holdInstalledGlobal,\n installPlanLines,\n notInstalledGlobally,\n readInstalledGlobal,\n type HeldGlobal,\n} from \"../lib/seed/seed-apply.js\";\nimport { getInstallationInfo } from \"../lib/plugins/plugin-info.js\";\nimport { loadProjectConfig } from \"../lib/configuration/project-config.js\";\nimport { isLocalSource, resolveBranding } from \"../lib/configuration/config.js\";\nimport {\n type InstallMode,\n detectInstallation,\n detectProjectInstallation,\n deriveInstallMode,\n holdsItsOwnInstallation,\n installBaseDir,\n resolveInstallPaths,\n buildAgentScopeMap,\n isHomeDirectory,\n INSTALL_MODE_LABELS,\n INSTALL_MODE_DESCRIPTIONS,\n} from \"../lib/installation/index.js\";\nimport { hostAt } from \"../lib/hosts/host-for.js\";\nimport {\n agentCodec,\n chooseProviderForThisRun,\n providerInUse,\n relativeConfigPath,\n} from \"../lib/installation/install-layout.js\";\nimport { hostCompileNotices } from \"../lib/hosts/host-compile-notices.js\";\nimport {\n providerFlag,\n providerNamedBy,\n providerNeedsAConfigurationToInstall,\n} from \"../lib/installation/provider-flag.js\";\nimport { checkPermissions } from \"../lib/permission-checker.js\";\nimport {\n ASCII_LOGO,\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n EDITOR_URL,\n EJECT_SOURCE,\n editorConfigUrl,\n} from \"../consts.js\";\nimport { clearTerminalScreen } from \"../utils/terminal.js\";\nimport { SelectList, type SelectListItem } from \"../components/common/select-list.js\";\nimport { promptConfirm, promptValue } from \"../components/common/prompt-confirm.js\";\nimport { Confirm } from \"../components/common/confirm.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { openUrl } from \"../utils/open-url.js\";\nimport { plural } from \"../utils/string.js\";\nimport type { AgentName, MergedSkillsMatrix, SkillId, SkillScope } from \"../types/index.js\";\nimport { type StartupMessage } from \"../utils/logger.js\";\nimport {\n INCOMPLETE_WORK_RECOVERY,\n SHARED_CONFIG_ARRIVALS,\n STATUS_MESSAGES,\n addMarketplaceInTheEditor,\n agentsNotCompiled,\n applySharedConfigHere,\n carriedSkillsWritten,\n globalScopedAgentsHint,\n initSucceeded,\n keptAsInstalledGlobally,\n sharedConfigExistingInstall,\n skippedUnknownAgents,\n skippedUnknownSkills,\n} from \"../utils/messages.js\";\nimport type { SeedPayload } from \"@workspace/matrix/seed\";\n\nconst DASHBOARD_OPTIONS = [\n { label: \"Edit in the web editor\", 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 options as the piped dashboard prints them, one bracketed label each. */\nconst DASHBOARD_OPTIONS_LINE = ` ${DASHBOARD_OPTIONS.map(({ label }) => `[${label}]`).join(\" \")}`;\n\n/** The commands offered by the project dashboard (single source: DASHBOARD_OPTIONS). */\nexport type DashboardCommand = (typeof DASHBOARD_OPTIONS)[number][\"value\"];\n\n/**\n * The dashboard's title: {@link ASCII_LOGO} for an installation resting on the shipped branding,\n * and the configured name in its place for one that white-labels it.\n *\n * **The logo gives way rather than sitting above the name, because it spells the shipped name.**\n * `branding.name` replaces a heading everywhere else it is read — every configured leg of\n * `commands/branding-name-reaches-headings` asserts {@link DEFAULT_BRANDING.NAME} is ABSENT — so\n * painting `AGENTS INC` in block capitals above `Northwind` would leave the vendor's name at the\n * most prominent surface the product has, which is the one thing white-labelling is for.\n *\n * The default path is untouched by construction: {@link resolveBranding} answers\n * {@link DEFAULT_BRANDING.NAME} for a configuration with no `branding` key, so an unbranded\n * install takes the logo arm. A configuration naming the shipped name explicitly takes it too —\n * it asked for the shipped name and gets the shipped presentation of it.\n */\nconst DashboardTitle: React.FC<{ name: string }> = ({ name }) =>\n name === DEFAULT_BRANDING.NAME ? <Text>{ASCII_LOGO}</Text> : <Text bold>{name}</Text>;\n\ntype DashboardProps = {\n /** Everything the screen paints, exactly as {@link formatDashboardText} is handed it. */\n data: DashboardData;\n onSelect: (command: DashboardCommand) => void;\n onCancel: () => void;\n};\n\nexport const Dashboard: React.FC<DashboardProps> = ({ data, 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 <DashboardTitle name={data.name} />\n </Box>\n <Box marginBottom={1}>\n <Text>{dashboardCountLines(data).join(\"\\n\")}</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/**\n * What this installation is, as the lines both dashboards paint between the title and the menu.\n *\n * **Shared because the two paths had diverged, not for reuse.** `showDashboard` branches on\n * `process.stdin.isTTY`, and only the text branch drew these — so the screen a person sits in\n * front of was less informative than the output they get by piping it, and no assertion could see\n * it, because each path was only ever compared against itself. One producer is what makes the two\n * unable to drift apart again.\n */\nexport function dashboardCountLines(data: DashboardData): string[] {\n const lines = [\n ` Skills: ${data.skillCount} installed`,\n ` Agents: ${data.agentCount} compiled`,\n ` Mode: ${INSTALL_MODE_LABELS[data.mode]}`,\n ];\n if (data.source) {\n lines.push(` Marketplace: ${data.source}`);\n }\n return lines;\n}\n\n/** Formats the dashboard summary as plain text lines (for non-interactive/test output). */\nexport function formatDashboardText(data: DashboardData): string {\n return [data.name, \"\", ...dashboardCountLines(data), \"\", DASHBOARD_OPTIONS_LINE].join(\"\\n\");\n}\n\n/**\n * What {@link showDashboard} answers when Ctrl+C ended it: a cancellation, as Ctrl+C is at every\n * other prompt — where Escape, which answers null, only steps back out of the dashboard.\n */\nconst DASHBOARD_INTERRUPTED = \"interrupted\";\n\n/** How the dashboard was left: a command chosen, Escape (null), or Ctrl+C. */\ntype DashboardAnswer = DashboardCommand | typeof DASHBOARD_INTERRUPTED | null;\n\n/**\n * Shows the project dashboard and returns the selected command, null when it was left with Escape,\n * or {@link DASHBOARD_INTERRUPTED} when Ctrl+C ended it.\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<DashboardAnswer> {\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<DashboardAnswer>(\n (resolve) => (\n <Dashboard\n data={data}\n onSelect={(command) => resolve(command)}\n onCancel={() => resolve(null)}\n />\n ),\n { onExit: DASHBOARD_INTERRUPTED, clearOnResolve: true },\n );\n\n clearTerminalScreen();\n\n return selectedCommand;\n}\n\n/** The argv a dashboard selection runs its command with: Edit opens the editor. */\nfunction dashboardCommandArgv(command: DashboardCommand): string[] {\n return command === \"edit\" ? [\"--ui\"] : [];\n}\n\n/**\n * What a run offered the dashboard came to: no installation to show it for, shown and left or\n * acted on, or cancelled with Ctrl+C — which the caller ends the run on as cancelled.\n */\nexport type DashboardFlow = \"not-installed\" | \"shown\" | \"cancelled\";\n\n/**\n * Shared dashboard entry: when the project is already initialized, shows the\n * dashboard and runs the chosen command. Never exits the process — callers decide\n * from the {@link DashboardFlow} it answers (the init hook exits SUCCESS at its own\n * call site for a dashboard shown).\n *\n * A project with no installation of its own is shown the global installation's dashboard, so its\n * Edit opens the global installation in the editor.\n */\nexport async function runDashboardFlow(\n projectDir: string,\n config: Interfaces.Config,\n log?: (message: string) => void,\n): Promise<DashboardFlow> {\n const installation = await detectInstallation(projectDir);\n if (!installation) return \"not-installed\";\n\n const selectedCommand = await showDashboard(projectDir, log);\n if (selectedCommand === DASHBOARD_INTERRUPTED) return \"cancelled\";\n if (selectedCommand) {\n await config.runCommand(selectedCommand, dashboardCommandArgv(selectedCommand));\n }\n return \"shown\";\n}\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\n/** What `init --from` decided to install, as the install sequence takes it. */\ntype Selection = {\n result: InstallSelection;\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 /**\n * Skills in the selection that are already installed where it puts them — a global install's\n * own, which a run from a project records as they are and never installs over.\n */\n installedAlready: ReadonlySet<SkillId>;\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 /**\n * The name this run prints itself under, resolved once on {@link install}'s spine because the\n * closing line is printed several calls below it. Same shape and same reason as `uninstall`'s\n * field: a plain `string` holding the shipped default rather than an optional every reader\n * would have to answer for.\n */\n private brandingName: string = DEFAULT_BRANDING.NAME;\n\n static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;\n static description =\n \"Build a configuration in agentsinc.sh/editor, or install one by id with --from. Over an existing installation, shows its dashboard.\";\n\n static examples = [\n {\n description: \"Open the editor to build a configuration\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n {\n description: \"Install a configuration built in the editor\",\n command: \"<%= config.bin %> <%= command.id %> --from <id>\",\n },\n {\n description: \"Test local marketplace changes against a configuration built in the editor\",\n command: \"<%= config.bin %> <%= command.id %> --from <id> --marketplace ./my-marketplace\",\n },\n ];\n\n static flags = {\n marketplace: Flags.string({\n char: \"m\",\n description:\n \"With --from, install from this marketplace instead of the one the configuration names. Without --from, open the editor and say how to add it there\",\n required: false,\n }),\n from: Flags.string({\n description: \"Install a configuration shared from agentsinc.sh by its id\",\n helpValue: \"<id>\",\n }),\n ui: Flags.boolean({\n description:\n \"Open agentsinc.sh/editor on the id --from names, or on the catalogue — what a bare init does where nothing is installed\",\n default: false,\n }),\n provider: providerFlag(),\n };\n\n /**\n * The command in two statements: do the work, then answer for it.\n *\n * {@link install} owns every path through the setup and returns however it likes; the exit\n * code is decided once, here, after the last of them. Deciding it inside would mean deciding\n * it at each of that method's endings, and an ending added later would inherit the exit-0\n * default silently — which is the defect this pair exists to close. `edit` is two statements\n * for the same reason.\n */\n async run(): Promise<void> {\n await this.install();\n this.exitIfWorkIncomplete();\n }\n\n /**\n * The editor, opened on whatever `--from` named — or on nothing when it named nothing.\n *\n * **One rule, both commands (owner ruling 2026-08-24): `--ui` opens the command's SUBJECT, and\n * `--from` is what supplies one.** `edit --ui` alone opens this installation because that is\n * `edit`'s subject; `init --ui` alone opens the catalogue because a fresh directory has none.\n * Given an id, either opens that id — which is what makes a shared configuration something a\n * recipient can look at rather than only apply blind.\n *\n * No publish happens here and none is needed. `edit --ui` mints an id because an installation\n * is not a configuration the store holds yet; an id already IS one, so this is\n * `editorConfigUrl` and nothing else — no network, no marketplace, no catalogue load.\n *\n * The link is PRINTED first and opened second. Over a pipe, in CI, and on a machine with no\n * desktop session there is no browser to be anybody's — a link nobody can copy is the whole\n * loss, so opening one is the convenience on top and a failure to open is a warning beside a\n * link that still works.\n *\n * A marketplace named here cannot ride along: the address carries an id and nothing else, so\n * the line under the link says how to add it in the editor.\n */\n private async openEditor(projectDir: string, id?: string, marketplace?: string): Promise<void> {\n const url = id === undefined ? EDITOR_URL : editorConfigUrl(id);\n // Above the first line, so a ref the install route would refuse is refused before any output.\n const marketplaceLine =\n marketplace === undefined ? undefined : this.addMarketplaceLineOrFail(marketplace);\n\n this.log(id === undefined ? `Build it at ${url}` : `Open it at ${url}`);\n if (marketplaceLine !== undefined) this.log(marketplaceLine);\n this.log(applySharedConfigHere(id, await holdsItsOwnInstallation(projectDir)));\n\n if (!process.stdin.isTTY) return;\n\n const opened = await openUrl(url);\n if (!opened.ok) this.warn(opened.error);\n }\n\n /**\n * Every route `init` has, in the order they are tried: the editor for `--ui` and for a\n * marketplace named without `--from`; for a bare run, the installation's dashboard — or the\n * editor where nothing is installed; and the install of the configuration `--from` names.\n */\n private async install(): Promise<void> {\n const { flags } = await this.parse(Init);\n const projectDir = process.cwd();\n\n // Above everything, including `--ui`: `--provider` names which installation this run creates,\n // and a run that creates none has nothing for it to name. Refusing here is what leaves the\n // filesystem untouched at both scopes — an installation half-created by a run that then\n // refused is the state every later command has to guess about.\n this.settleTheProviderForThisRun(flags);\n\n // Above `ensureConfigReadable`, and above every read below it, because this route needs no\n // installation at all. A config too broken to load must not stop someone reaching the other\n // front door, and an id somebody shared is not this directory's business either.\n if (opensTheEditor(flags)) return this.openEditor(projectDir, flags.from, flags.marketplace);\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 === undefined) return this.showDashboardOrOpenEditor(projectDir);\n\n // Read once on the spine, because the closing line is printed several calls below it. The\n // degrade arm of `resolveBrandingName` cannot fire here: `ensureConfigReadable` has already\n // refused every config this would read.\n this.brandingName = await this.resolveBrandingName(projectDir);\n\n const selection = await this.selectionFromSharedConfig(flags.from, flags, projectDir);\n if (!selection) this.exit(EXIT_CODES.CANCELLED);\n\n // A broken constraint is this catalog's verdict on what survived the decode.\n this.reportValidationErrors(selection.result.validation);\n\n await this.handleInstallation(selection);\n }\n\n /** A bare `init`: the installation's dashboard, or the editor where nothing is installed. */\n private async showDashboardOrOpenEditor(projectDir: string): Promise<void> {\n const dashboard = await runDashboardFlow(projectDir, this.config, (msg) => this.log(msg));\n if (dashboard === \"cancelled\") this.error(\"Cancelled\", { exit: EXIT_CODES.CANCELLED });\n if (dashboard === \"not-installed\") await this.openEditor(projectDir);\n }\n\n /** The editor's marketplace line, or the refusal the install route gives a ref it cannot read. */\n private addMarketplaceLineOrFail(ref: string): string {\n try {\n return addMarketplaceInTheEditor(ref, isLocalSource(ref));\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Commits this run to the provider `--provider` named, or refuses a flag with nothing to name.\n *\n * **`--provider` is a LOCATION parameter, not a feature switch**, and the control that proves it\n * is `--provider claude`: naming the default out loud installs byte-for-byte what no flag\n * installs, because all the flag decides is which folder this run creates. Without that half\n * \"the flag selects an installation\" would be indistinguishable from \"the flag means Codex\".\n *\n * **And it is meaningless without `--from` (D15).** The provider is chosen in the web app, so\n * the only run that can be told one is the run that installs what the app produced. It also\n * gives the placement refusal something to refuse BEFORE anything is written: with `--from`\n * required, a provider always arrives beside a payload the pre-flight can read.\n */\n private settleTheProviderForThisRun(flags: Interfaces.InferredFlags<typeof Init.flags>): void {\n const named = providerNamedBy(flags.provider);\n if (named === undefined) return;\n\n if (flags.from === undefined) {\n this.error(providerNeedsAConfigurationToInstall(), { exit: EXIT_CODES.INVALID_ARGS });\n }\n\n chooseProviderForThisRun(named);\n }\n\n /**\n * The `--from <id>` producer: fetch and map — and, at a terminal, one question.\n *\n * It installs into a clean directory, which is what the first refusal is: a shared\n * configuration is installed whole, so a directory already holding one has it applied with\n * `edit --from` instead, or is uninstalled first. The second is about the LOCATION rather than what is already in it — a global\n * installation holds only global-scoped content. Both fire before anything is written.\n *\n * A global installation ABOVE a project is not in the way. It is not this project's, so the run\n * adds to it what it lacks and states every entry it already holds as installed (see\n * `holdInstalledGlobal`).\n *\n * Before writing anything the run lists what goes into the project and what into the global\n * install. At a terminal it then asks, and a no writes nothing. With no terminal — a CI job or a\n * script — it prints the same lists and carries on: running headless is most of why the flag\n * exists.\n */\n private async selectionFromSharedConfig(\n id: string,\n flags: SourceFlags,\n projectDir: string,\n ): Promise<Selection | null> {\n await this.refuseInstalledProject(projectDir, id);\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, startupMessages } = 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.\n this.refuseProjectScopedContentAtHome(result, projectDir);\n\n const held = holdInstalledGlobal(\n result,\n isHomeDirectory(projectDir) ? null : await readInstalledGlobal(projectDir),\n );\n const arrivingCarried = notInstalledGlobally(carriedSkills, held);\n\n // The last refusals, and still above the lists and the question: a yes installs what was\n // listed, so nothing listed may then be refused.\n await this.refuseSharedConfigBeforeAsking(\n held.result,\n arrivingCarried,\n projectDir,\n sourceResult,\n );\n\n // What the load held back, directly above the skips it may explain — a skill this catalogue\n // \"does not know\" is often one it ships with a file that will not parse.\n sayCapturedWarnings(startupMessages);\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 // Below the skips, which are its explanation, and above the lists: a configuration this\n // catalogue can place nothing of has nothing to list, and nothing to ask about.\n if (selectsNothing(held.result)) {\n this.error(`Configuration '${id}' contains no skills this catalog can install.`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n this.logWhatGoesWhere(held);\n if (process.stdin.isTTY && !(await this.confirmInstall())) {\n this.log(\"Setup cancelled\");\n return null;\n }\n\n // After the question and before the install: every refusal this producer makes, and a no,\n // leave nothing written, and the copy step that follows finds these skills already where they\n // belong.\n await this.writeCarriedSkills(arrivingCarried);\n\n const arriving = notInstalledGlobally(held.result.skills, held);\n if (arriving.length > 0) {\n this.log(\n `Installing ${arriving.length} skill(s) across ${result.selectedAgents.length} sub-agent(s)\\n`,\n );\n }\n\n return {\n result: held.result,\n sourceResult,\n sourceFlags,\n installedAlready: new Set(held.installed.skillIds),\n };\n }\n\n /**\n * The two lists — what goes into this project, and what into the global install — then the\n * global skills skipped as already installed, the held sub-agents a new skill joins, and the\n * global entries the configuration states otherwise than they are installed, which stay.\n */\n private logWhatGoesWhere(held: HeldGlobal): void {\n for (const line of installPlanLines(held)) {\n this.log(line);\n }\n\n const { skillIds, agentNames } = held.keptAsInstalled;\n if (skillIds.length > 0 || agentNames.length > 0) {\n this.log(keptAsInstalledGlobally(skillIds, agentNames));\n }\n this.log(\"\");\n }\n\n /** The question under the lists, defaulting to no: nothing has been written yet. */\n private async confirmInstall(): Promise<boolean> {\n const outcome = await promptConfirm(({ onConfirm, onCancel }) => (\n <Confirm\n message={SHARED_CONFIG_ARRIVALS.INSTALL_CONFIRM}\n onConfirm={onConfirm}\n onCancel={onCancel}\n />\n ));\n return outcome === \"confirmed\";\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. A global install above the project is\n * added to rather than refused over — see {@link selectionFromSharedConfig}.\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, id: string): Promise<void> {\n const installation = await detectProjectInstallation(projectDir);\n if (!installation) return;\n\n this.error(sharedConfigExistingInstall(installation.configPath, id), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n /**\n * The decode refuses a payload the config model has nowhere to write (see\n * `seedToInstallSelection`). That is a failure of this command, reported with this command's exit\n * code rather than left to surface as an unhandled throw.\n */\n private decodeSeedOrFail(payload: SeedPayload, matrix: MergedSkillsMatrix): SeedMapping {\n try {\n return seedToInstallSelection(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 refusals are `registerExternalSkills`' own — a carried skill asked for as a plugin, which\n * no marketplace serves, and a carried skill claiming an id the loaded catalogue already owns,\n * whose bytes would be written over that catalogue's own copy — and are reported with this\n * command's exit code for the same reason the 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 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 private async handleInstallation({\n result,\n sourceResult,\n sourceFlags,\n installedAlready,\n }: Selection): Promise<void> {\n const projectDir = process.cwd();\n const activeSkills = result.skills.filter((s) => !s.excluded);\n const toInstall = activeSkills.filter((s) => !installedAlready.has(s.id));\n const installMode = deriveInstallMode(toInstall);\n const ejectedSkills = toInstall.filter((s) => s.origin === EJECT_SOURCE);\n const pluginSkills = toInstall.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 hostAt(projectDir),\n (marketplace) => this.log(`Registering marketplace \"${marketplace}\"...`),\n )\n : null;\n\n const copyResult =\n ejectedSkills.length > 0\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 sourceFlags,\n );\n this.reportSuccess(\n configResult,\n compileResult,\n agentScopeMap,\n installMode,\n pluginModeSucceeded,\n copyResult,\n );\n\n await this.showPermissionNotice(projectDir);\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 one frame is rendered and let go: the notice is information, not a prompt, and `--from`\n * has to complete over a pipe and in CI.\n */\n private async showPermissionNotice(projectDir: string): Promise<void> {\n const permissionWarning = await checkPermissions(projectDir);\n if (!permissionWarning) return;\n\n const { unmount } = render(permissionWarning);\n unmount();\n }\n\n private logInstallPlan(\n installMode: InstallMode,\n ejectedSkills: InstallSelection[\"skills\"],\n pluginSkills: InstallSelection[\"skills\"],\n ): void {\n this.log(\"\\n\");\n this.log(`Selected ${plural(ejectedSkills.length + pluginSkills.length, \"skill\")}`);\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 /**\n * Copies the ejected skills and says how many landed at each scope, in the words\n * {@link skillsCopiedLine} chooses.\n */\n private async copyEjectSkillsStep(\n localSkills: InstallSelection[\"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 this.log(skillsCopiedLine(copyResult, installMode, projectDir));\n return copyResult;\n }\n\n private async writeConfigAndCompile(\n result: InstallSelection,\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 selection: 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 (${plural(configResult.config.agents.length, \"agent\")})\\n`);\n this.reportUnassignedSkills(configResult.config, result.skills);\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 compile = compilesGlobalScope(cwd, configResult.propagation)\n ? compileAgentsAllScopes\n : compileProjectScope;\n const compileResult = await compile({\n projectDir: cwd,\n sourcePath: agentDefs.sourcePath,\n skills: allSkills,\n agentScopeMap,\n });\n this.reportCompilation(compileResult);\n await this.reportWhatThisHostCannotCarry(cwd);\n\n this.reportFanOut(configResult.propagation);\n\n return { configResult, compileResult, agentScopeMap };\n }\n\n /**\n * What this host could not carry, after the compile summary and once per run.\n *\n * `init --from` is the door a configuration somebody ELSE wrote arrives through, so it is\n * precisely the run that must not be silent about the parts of it that did not survive the\n * translation. `compile` prints the same lines in the same order — see\n * {@link hostCompileNotices}, which is the one place either of them gets them from.\n *\n * A Claude install expresses every setting and carries every sub-agent, so it gets one line at\n * most: the trust dialog, while its project sub-agents' completion gate cannot run in this\n * folder.\n */\n private async reportWhatThisHostCannotCarry(cwd: string): Promise<void> {\n for (const notice of await hostCompileNotices(providerInUse(cwd), cwd)) {\n this.log(notice);\n }\n }\n\n /**\n * What the compile pass did, including the half this command used to drop.\n *\n * It read `compiled` and nothing else, so a pass that lost a sub-agent printed a number that\n * looked perfectly right — `compiled` counts successes, so it is correct either way — and the\n * failures reached no surface at all: no count, no reason, no exit code. A user's FIRST\n * install could silently land a roster missing a sub-agent.\n *\n * The compile is the last thing `init` does, so a failure here cannot be answered by aborting:\n * the skills are on disk and `config.ts` and `config-types.ts` describe them. What is owed is\n * the account, which {@link BaseCommand.exitIfWorkIncomplete} prints and answers for.\n */\n private reportCompilation(compileResult: CompilationResult): void {\n const { compiled, failed, warnings } = compileResult;\n const summary = `Compiled ${plural(compiled.length, \"agent\")}`;\n\n if (failed.length === 0) {\n this.log(`${summary}\\n`);\n return;\n }\n\n this.log(`${summary} (${failed.length} failed)\\n`);\n for (const warning of warnings) {\n this.warn(warning);\n }\n // Recorded off `failed` rather than off the warnings just printed: `warnings` also carries\n // entries that are not failures, and the ending must not file those as work owed.\n this.recordIncompleteWork(agentsNotCompiled(failed), INCOMPLETE_WORK_RECOVERY.RECOMPILE);\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 // A run with work owed ends on the failure account instead — `initialized successfully!`\n // over a roster missing a sub-agent is the claim being withdrawn, not a line beside it.\n // Where the install landed is still reported below: that is what the account is about.\n if (!this.hasIncompleteWork) this.log(`${initSucceeded(this.brandingName)}\\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, cwd).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 * **The EXTENSION is the host's, per scope, and was Claude's literal `.md` until C5.** This\n * block describes the filesystem, so every line under a path header has to be a name a user can\n * copy out and open — and a Codex install printed `web-developer.md` above a directory holding\n * `web-developer.toml`. The two scopes are read separately because they can be on two hosts.\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 ? [{ ...compiledInto(cwd, \"project\"), agents: compiled }]\n : [\n {\n ...compiledInto(cwd, \"global\"),\n agents: compiled.filter((name) => agentScopeMap.get(name) === \"global\"),\n },\n {\n ...compiledInto(cwd, \"project\"),\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}${group.extension}`);\n }\n this.log(\"\");\n }\n }\n}\n\n/**\n * Whether a run takes the editor route whatever is installed: `--ui`, or a marketplace named\n * without `--from` — that flag acts only beside an install, and the editor is where one is added\n * otherwise.\n */\nfunction opensTheEditor(\n flags: Pick<Interfaces.InferredFlags<typeof Init.flags>, \"ui\" | \"from\" | \"marketplace\">,\n): boolean {\n return flags.ui || (flags.from === undefined && flags.marketplace !== undefined);\n}\n\n/**\n * Whether a selection holds nothing to install. A sub-agent is installable on its own — it has\n * front-matter, a prompt and a compiled file without owning a single skill — so only a selection\n * with neither is empty.\n */\nfunction selectsNothing(result: InstallSelection): boolean {\n return result.skills.length === 0 && result.selectedAgents.length === 0;\n}\n\n/**\n * Whether this run's compile covers the global install as well as the project — `edit`'s rule\n * (`compilesGlobalScope` in `commands/edit.tsx`), for the same reason.\n *\n * From a project, the global install is held as installed, so its sub-agents are recompiled only\n * when the write added something they are built from. Recompiled anyway, they would be built from\n * the catalogue THIS run loaded rather than the one the global install was made from — a skill\n * that catalogue does not ship is described by its fallback guidance instead of its own — and a\n * project run that added nothing to the global install would still have rewritten it.\n */\nfunction compilesGlobalScope(cwd: string, written: GateReport): boolean {\n return isHomeDirectory(cwd) || movedGlobalAgentInputs(written);\n}\n\n/**\n * The line an eject copy ends on: how many skills landed, and where.\n *\n * A copy that landed at one scope names the directory `copyLocalSkills` wrote it into, read the\n * way that function reads it — `resolveInstallPaths` at the scope — so it is the folder the\n * `Skills copied to:` block beneath names too. The line spelled the directory from the scope ROOT\n * until 2026-10-03, so a run from a project that copied every skill under HOME printed\n * `.claude/skills/`, which, read where the command was typed, names the project's own empty\n * folder. A copy that landed at both scopes names no directory, because two scopes have two and\n * the block beneath lists each.\n *\n * In a mixed install the copies are its \"local\" half, beside the plugins installed after them.\n */\nfunction skillsCopiedLine(\n copyResult: SkillCopyResult,\n installMode: InstallMode,\n projectDir: string,\n): string {\n const isMixed = installMode === \"mixed\";\n const copied = plural(copyResult.totalCopied, isMixed ? \"local skill\" : \"skill\");\n const lineEnd = isMixed ? \"\" : \"\\n\";\n const projectCount = copyResult.projectCopied.length;\n const globalCount = copyResult.globalCopied.length;\n const landedAtBothScopes = projectCount > 0 && globalCount > 0;\n\n if (landedAtBothScopes) {\n return `Copied ${copied} (${projectCount} project, ${globalCount} global)${lineEnd}`;\n }\n const landedAt: SkillScope = globalCount > 0 ? \"global\" : \"project\";\n return `Copied ${copied} to ${resolveInstallPaths(projectDir, landedAt).skillsDir}/${lineEnd}`;\n}\n\n/**\n * Where one scope's sub-agents landed, and the extension the host that reads them writes.\n *\n * One read per scope, exactly as `resolveInstallPaths` reads one beside it: a project on Codex\n * under a global on Claude puts `.toml` in one block and `.md` in the other, and one answer for\n * both is how a path block names a file that is not there.\n */\nfunction compiledInto(cwd: string, scope: SkillScope): { dir: string; extension: string } {\n return {\n dir: resolveInstallPaths(cwd, scope).agentsDir,\n extension: agentCodec(providerInUse(installBaseDir(cwd, scope))).extension,\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(\n split: AgentScopeSplit,\n globalConfigPath: string,\n projectDir: string,\n): string[] {\n if (split.isGlobalOnly) {\n return [`Edit ${globalConfigPath}`, globalScopedAgentsHint(split.globalAgentCount)];\n }\n\n return [\n `Edit ${relativeConfigPath(projectDir, providerInUse(projectDir))}`,\n `Run '${CLI_INVOKE_COMMAND} compile' to regenerate agents`,\n ...(split.globalAgentCount > 0 ? [globalScopedAgentsHint(split.globalAgentCount)] : []),\n ];\n}\n\nexport type DashboardData = {\n /**\n * The name the dashboard is titled with — `branding.name` where the configuration supplies one\n * and {@link DEFAULT_BRANDING.NAME} otherwise. Carried on the data rather than read by either\n * consumer so {@link formatDashboardText} stays a pure function of what it is handed, and so\n * the one place that reaches a configuration is the one that already loads it.\n *\n * **Both of {@link showDashboard}'s branches read it, and that is the invariant to keep.** This\n * field was resolved for the piped branch alone for as long as it was, while the `Dashboard`\n * component was handed only its callbacks and painted {@link ASCII_LOGO} — so the dashboard a\n * person actually sees was the one surface `branding.name` never reached, and every spec on the\n * subject drove through a pipe and could not see it.\n */\n name: string;\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 // ABORT is the posture on `resolveBranding`, and it is the one already in force: the\n // `loadProjectConfig` beside it raises for the same file, so a configuration that cannot be\n // evaluated fails this call whether branding is read or not. Nothing is degraded here that was\n // not already, and the dashboard is only reached once an installation has been detected.\n const [info, loaded, branding] = await Promise.all([\n getInstallationInfo(),\n loadProjectConfig(projectDir),\n resolveBranding(projectDir),\n ]);\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 {\n name: branding.name,\n skillCount,\n agentCount,\n mode,\n ...(source !== undefined && { source }),\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","import React from \"react\";\nimport { z } from \"zod\";\n\nimport { Text, Box } from \"ink\";\nimport path from \"path\";\n\nimport { CLI_COLORS, MAX_CONFIG_FILE_SIZE } from \"../consts\";\nimport {\n advisesOnPermissions,\n permissionFiles,\n providerInUse,\n} from \"./installation/install-layout.js\";\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.\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/**\n * The files this host reads permissions from at project scope, in the host's own order: the base\n * file this CLI writes first, then any overlay that beats it.\n *\n * Composed from `CLAUDE_DIR` until 2026-09-22, which is why a Codex install read a `.claude/`\n * directory it had never written. {@link permissionFiles} is the one answer now, and this is its\n * first production reader.\n */\nfunction settingsFilesFor(projectRoot: string): string[] {\n return permissionFiles(providerInUse(projectRoot), \"project\", projectRoot);\n}\n\n/** Permissions from the highest-precedence settings file that defines them — the overlay wins. */\nasync function loadPermissions(files: readonly string[]): Promise<PermissionConfig | undefined> {\n for (const filePath of [...files].reverse()) {\n const permissions = await readSettingsPermissions(filePath);\n if (permissions) return permissions;\n }\n return undefined;\n}\n\n/**\n * One settings file as the notice names it: relative to the project, POSIX-separated.\n *\n * POSIX for `pathUnder`'s reason one module over — what comes back is a NAME shown to a person,\n * not a path this process opens.\n */\nfunction asUserWritesIt(projectRoot: string, file: string): string {\n return path.relative(projectRoot, file).split(path.sep).join(\"/\");\n}\n\n/**\n * The notice a run ends on when nothing has granted the agents any permissions — or `null` where\n * there is nothing true to say.\n *\n * **`null` for a host whose permission model this release cannot advise on**, which is\n * {@link advisesOnPermissions}'s whole subject. Every word below is Claude Code's: a\n * `permissions.allow` block, in JSON, in `settings.json`. Codex has neither the key nor the file,\n * and a Codex install printed this verbatim until 2026-09-22 — ending a run that had touched no\n * `.claude/` directory by telling the user to go and edit one.\n *\n * The file is NAMED from the layout rather than spelled, so the notice points at the file it\n * actually read.\n */\nexport async function checkPermissions(projectRoot: string): Promise<React.ReactElement | null> {\n if (!advisesOnPermissions(providerInUse(projectRoot))) return null;\n\n const files = settingsFilesFor(projectRoot);\n // The BASE file rather than the overlay: it is the one this CLI writes, and the one a user with\n // neither is being asked to create. A host with a notice to print has a file to name it in, so\n // an empty roster is a host that has nothing to say rather than a case to paper over.\n const [base] = files;\n if (base === undefined) return null;\n\n const permissions = await loadPermissions(files);\n const settingsFile = asUserWritesIt(projectRoot, base);\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 {settingsFile}</Text>\n <Text>Agents will prompt for approval on each tool use.</Text>\n <Text> </Text>\n <Text>For autonomous operation, add to {settingsFile}:</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","Text","Box"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/common/spinner.tsx"],"sourcesContent":["import React from \"react\";\nimport { Text, type Instance } from \"ink\";\nimport { Spinner as InkSpinner } from \"@inkjs/ui\";\nimport { render } from \"../render.js\";\n\ntype SpinnerProps = {\n label: string;\n};\n\nexport const Spinner: React.FC<SpinnerProps> = ({ label }) => <InkSpinner label={label} />;\n\n/**\n * Awaits `load` behind a spinner and takes the spinner down whichever way the await ends, leaving\n * the terminal as it found it.\n *\n * The cleanup is a `finally` because a load that refuses the run throws from inside this await,\n * and oclif would otherwise paint its error under an Ink tree still repainting over it. Never a\n * `catch`: the throw reaches the caller untouched, or both the error rendering and the exit code\n * change with it.\n */\nexport async function awaitUnderSpinner<T>(label: string, load: () => Promise<T>): Promise<T> {\n const spinner = render(<Spinner label={label} />);\n try {\n return await load();\n } finally {\n await takeDownWithoutTrace(spinner, label);\n }\n}\n\n/**\n * Stop the clock, paint what Ink is holding, and only then erase.\n *\n * Ink paints through a render throttle, and a spinner frame that arrives inside its window is\n * held rather than painted. `unmount()` paints whatever is held — so a spinner cleared with a\n * frame held was drawn again after the clear, where nothing erases it. A starved event loop is\n * what puts one there: a spinner tick that runs late is followed by the next one less than a\n * window later. Hence the order: the still line has no clock, so once it replaces the spinner no\n * new frame can be held; the flush paints anything already held; the clear then erases the last\n * thing painted, and `unmount()` finds nothing left to draw.\n */\nasync function takeDownWithoutTrace(spinner: Instance, label: string): Promise<void> {\n spinner.rerender(<Text>{label}</Text>);\n await spinner.waitUntilRenderFlush();\n spinner.clear();\n spinner.unmount();\n}\n"],"mappings":";;;;;;AAAA,OAAkB;AAClB,SAAS,YAA2B;AACpC,SAAS,WAAW,kBAAkB;AAOwB;AAAvD,IAAM,UAAkC,CAAC,EAAE,MAAM,MAAM,oBAAC,cAAW,OAAc;AAWxF,eAAsB,kBAAqB,OAAe,MAAoC;AAC5F,QAAM,UAAU,OAAO,oBAAC,WAAQ,OAAc,CAAE;AAChD,MAAI;AACF,WAAO,MAAM,KAAK;AAAA,EACpB,UAAE;AACA,UAAM,qBAAqB,SAAS,KAAK;AAAA,EAC3C;AACF;AAaA,eAAe,qBAAqB,SAAmB,OAA8B;AACnF,UAAQ,SAAS,oBAAC,QAAM,iBAAM,CAAO;AACrC,QAAM,QAAQ,qBAAqB;AACnC,UAAQ,MAAM;AACd,UAAQ,QAAQ;AAClB;","names":[]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli/lib/configuration/scope-diff.ts
|
|
4
|
+
function computeScopeDiff(input) {
|
|
5
|
+
const { currentSkills, currentAgents, installedSkillConfigs, installedAgentConfigs, isInitMode } = input;
|
|
6
|
+
const projectSkills = currentSkills.filter((s) => s.scope === "project" && !s.excluded);
|
|
7
|
+
const globalSkills = currentSkills.filter((s) => s.scope === "global" && !s.excluded);
|
|
8
|
+
const projectAgents = currentAgents.filter((a) => a.scope === "project" && !a.excluded);
|
|
9
|
+
const globalAgents = currentAgents.filter((a) => a.scope === "global" && !a.excluded);
|
|
10
|
+
const excludedGlobalSkills = currentSkills.filter((s) => s.scope === "global" && !!s.excluded);
|
|
11
|
+
const excludedGlobalAgents = currentAgents.filter((a) => a.scope === "global" && !!a.excluded);
|
|
12
|
+
const prevSkillKeySet = installedSkillConfigs ? new Set(installedSkillConfigs.map((s) => skillSlotKey(s.id, s.scope))) : null;
|
|
13
|
+
const prevSourceMap = installedSkillConfigs ? new Map(
|
|
14
|
+
installedSkillConfigs.filter((s) => !s.excluded).map((s) => [skillSlotKey(s.id, s.scope), s.origin])
|
|
15
|
+
) : null;
|
|
16
|
+
const prevAgentKeySet = installedAgentConfigs ? new Set(installedAgentConfigs.map((a) => agentSlotKey(a.name, a.scope))) : null;
|
|
17
|
+
const activeSkillBaseline = installedSkillConfigs ? installedSkillConfigs.filter((s) => !s.excluded) : [];
|
|
18
|
+
const activeAgentBaseline = installedAgentConfigs ? installedAgentConfigs.filter((a) => !a.excluded) : [];
|
|
19
|
+
const inheritedGlobalSkills = activeSkillBaseline.filter(
|
|
20
|
+
(s) => s.scope === "global" && !globalSkills.some((g) => g.id === s.id) && !excludedGlobalSkills.some((e) => e.id === s.id) && projectSkills.some((p) => p.id === s.id)
|
|
21
|
+
);
|
|
22
|
+
const inheritedGlobalAgents = activeAgentBaseline.filter(
|
|
23
|
+
(a) => a.scope === "global" && !globalAgents.some((g) => g.name === a.name) && !excludedGlobalAgents.some((e) => e.name === a.name) && projectAgents.some((p) => p.name === a.name)
|
|
24
|
+
);
|
|
25
|
+
const removedSkills = activeSkillBaseline.filter(
|
|
26
|
+
(s) => !currentSkills.some((c) => c.id === s.id && c.scope === s.scope)
|
|
27
|
+
);
|
|
28
|
+
const removedAgents = activeAgentBaseline.filter(
|
|
29
|
+
(a) => !currentAgents.some((c) => c.name === a.name && c.scope === a.scope)
|
|
30
|
+
);
|
|
31
|
+
const inheritedSkillIdSet = new Set(inheritedGlobalSkills.map((s) => s.id));
|
|
32
|
+
const uniqueExcludedGlobalSkills = excludedGlobalSkills.filter(
|
|
33
|
+
(s) => !inheritedSkillIdSet.has(s.id)
|
|
34
|
+
);
|
|
35
|
+
const allGlobalSkills = [
|
|
36
|
+
...globalSkills,
|
|
37
|
+
...inheritedGlobalSkills,
|
|
38
|
+
...uniqueExcludedGlobalSkills
|
|
39
|
+
];
|
|
40
|
+
const inheritedAgentNameSet = new Set(inheritedGlobalAgents.map((a) => a.name));
|
|
41
|
+
const uniqueExcludedGlobalAgents = excludedGlobalAgents.filter(
|
|
42
|
+
(a) => !inheritedAgentNameSet.has(a.name)
|
|
43
|
+
);
|
|
44
|
+
const allGlobalAgents = [
|
|
45
|
+
...globalAgents,
|
|
46
|
+
...inheritedGlobalAgents,
|
|
47
|
+
...uniqueExcludedGlobalAgents
|
|
48
|
+
];
|
|
49
|
+
const removedGlobalSkills = isInitMode ? [] : removedSkills.filter((s) => s.scope === "global" && !inheritedSkillIdSet.has(s.id));
|
|
50
|
+
const removedProjectSkills = removedSkills.filter((s) => s.scope === "project");
|
|
51
|
+
const removedGlobalAgents = isInitMode ? [] : removedAgents.filter((a) => a.scope === "global" && !inheritedAgentNameSet.has(a.name));
|
|
52
|
+
const removedProjectAgents = removedAgents.filter((a) => a.scope === "project");
|
|
53
|
+
const projectSkillRows = [
|
|
54
|
+
...projectSkills.map((s) => classifyDiffRow(s, prevSkillKeySet, prevSourceMap)),
|
|
55
|
+
...removedProjectSkills.map(toRemovedSkillRow)
|
|
56
|
+
];
|
|
57
|
+
const globalSkillRows = [
|
|
58
|
+
...allGlobalSkills.map((s) => classifyDiffRow(s, prevSkillKeySet, prevSourceMap)),
|
|
59
|
+
...removedGlobalSkills.map(toRemovedSkillRow)
|
|
60
|
+
];
|
|
61
|
+
const projectAgentRows = [
|
|
62
|
+
...projectAgents.map((a) => classifyAgentDiffRow(a, prevAgentKeySet)),
|
|
63
|
+
...removedProjectAgents.map(toRemovedAgentRow)
|
|
64
|
+
];
|
|
65
|
+
const globalAgentRows = [
|
|
66
|
+
...allGlobalAgents.map((a) => classifyAgentDiffRow(a, prevAgentKeySet)),
|
|
67
|
+
...removedGlobalAgents.map(toRemovedAgentRow)
|
|
68
|
+
];
|
|
69
|
+
const hasContent = projectSkillRows.length > 0 || globalSkillRows.length > 0 || projectAgentRows.length > 0 || globalAgentRows.length > 0;
|
|
70
|
+
return { projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows, hasContent };
|
|
71
|
+
}
|
|
72
|
+
function skillSlotKey(id, scope) {
|
|
73
|
+
return `${id}:${scope}`;
|
|
74
|
+
}
|
|
75
|
+
function agentSlotKey(name, scope) {
|
|
76
|
+
return `${name}:${scope}`;
|
|
77
|
+
}
|
|
78
|
+
function formatScopeTag(scope) {
|
|
79
|
+
return scope === "global" ? "[G]" : "[P]";
|
|
80
|
+
}
|
|
81
|
+
function classifyDiffRow(skill, prevKeySet, prevSourceMap) {
|
|
82
|
+
const key = skillSlotKey(skill.id, skill.scope);
|
|
83
|
+
const isNew = prevKeySet === null || !prevKeySet.has(key);
|
|
84
|
+
const prevSource = prevSourceMap?.get(key);
|
|
85
|
+
const modeChanged = !isNew && prevSource != null && prevSource !== skill.origin;
|
|
86
|
+
if (modeChanged) {
|
|
87
|
+
return { id: skill.id, source: skill.origin, status: "mode-changed" };
|
|
88
|
+
}
|
|
89
|
+
return { id: skill.id, source: skill.origin, status: isNew ? "added" : "unchanged" };
|
|
90
|
+
}
|
|
91
|
+
function classifyAgentDiffRow(agent, prevKeySet) {
|
|
92
|
+
const isNew = prevKeySet === null || !prevKeySet.has(agentSlotKey(agent.name, agent.scope));
|
|
93
|
+
return { name: agent.name, status: isNew ? "added" : "unchanged" };
|
|
94
|
+
}
|
|
95
|
+
function toRemovedSkillRow(skill) {
|
|
96
|
+
return { id: skill.id, source: skill.origin, status: "removed" };
|
|
97
|
+
}
|
|
98
|
+
function toRemovedAgentRow(agent) {
|
|
99
|
+
return { name: agent.name, status: "removed" };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export {
|
|
103
|
+
computeScopeDiff,
|
|
104
|
+
formatScopeTag
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=chunk-NIHUOWE4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/configuration/scope-diff.ts"],"sourcesContent":["import type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { AgentName, SkillId } from \"../../types/index\";\n\nexport type ScopeDiffInput = {\n currentSkills: SkillConfig[];\n currentAgents: AgentScopeConfig[];\n installedSkillConfigs: SkillConfig[] | null;\n installedAgentConfigs: AgentScopeConfig[] | null;\n isInitMode: boolean;\n};\n\nexport type DiffRowStatus = \"added\" | \"mode-changed\" | \"removed\" | \"unchanged\";\n\nexport type SkillDiffRow = {\n id: SkillId;\n source: string;\n status: DiffRowStatus;\n};\n\nexport type AgentDiffRow = {\n name: AgentName;\n status: Exclude<DiffRowStatus, \"mode-changed\">;\n};\n\nexport type ScopeDiff = {\n projectSkillRows: SkillDiffRow[];\n globalSkillRows: SkillDiffRow[];\n projectAgentRows: AgentDiffRow[];\n globalAgentRows: AgentDiffRow[];\n hasContent: boolean;\n};\n\n/**\n * Computes the per-scope diff rows.\n *\n * The diff baseline keeps tombstones as first-class entries. A tombstone\n * occupies the (id, scope) slot: it means \"the global install still exists but\n * is silenced at project scope\" — the dual-scope indicator. Treating the slot\n * as occupied — for both the previous-key set (isNew detection) and removal\n * (slot-occupancy match) — prevents a dual-scope G→P toggle from rendering a\n * spurious `-` at Global or a spurious `+` at Global on the next edit\n * when the stored tombstone is re-read; mode-change (`~`) tracking filters to active baseline\n * entries because tombstones don't represent a live install.\n *\n * Occupying a slot is not the same as filling it, which is why removal reads the\n * ACTIVE baseline alone and every re-surfaced global row is deduped against the\n * inherited set. A baseline tombstone masks an install rather than being one, and\n * an inherited global can be admitted as inherited and matched as removed at once.\n */\nexport function computeScopeDiff(input: ScopeDiffInput): ScopeDiff {\n const { currentSkills, currentAgents, installedSkillConfigs, installedAgentConfigs, isInitMode } =\n input;\n\n const projectSkills = currentSkills.filter((s) => s.scope === \"project\" && !s.excluded);\n const globalSkills = currentSkills.filter((s) => s.scope === \"global\" && !s.excluded);\n const projectAgents = currentAgents.filter((a) => a.scope === \"project\" && !a.excluded);\n const globalAgents = currentAgents.filter((a) => a.scope === \"global\" && !a.excluded);\n const excludedGlobalSkills = currentSkills.filter((s) => s.scope === \"global\" && !!s.excluded);\n const excludedGlobalAgents = currentAgents.filter((a) => a.scope === \"global\" && !!a.excluded);\n\n const prevSkillKeySet = installedSkillConfigs\n ? new Set(installedSkillConfigs.map((s) => skillSlotKey(s.id, s.scope)))\n : null;\n const prevSourceMap = installedSkillConfigs\n ? new Map(\n installedSkillConfigs\n .filter((s) => !s.excluded)\n .map((s) => [skillSlotKey(s.id, s.scope), s.origin]),\n )\n : null;\n const prevAgentKeySet = installedAgentConfigs\n ? new Set(installedAgentConfigs.map((a) => agentSlotKey(a.name, a.scope)))\n : null;\n\n // The installs the baseline actually records. Both readers below want this\n // rather than the raw snapshot: `inheritedGlobal*` re-surfaces an active global\n // the project overrides without a tombstone — a historical no-tombstone\n // dual-scope shape, current tombstones being handled by\n // `uniqueExcludedGlobalSkills` — and removal reports only what an install left.\n const activeSkillBaseline = installedSkillConfigs\n ? installedSkillConfigs.filter((s) => !s.excluded)\n : [];\n const activeAgentBaseline = installedAgentConfigs\n ? installedAgentConfigs.filter((a) => !a.excluded)\n : [];\n const inheritedGlobalSkills = activeSkillBaseline.filter(\n (s) =>\n s.scope === \"global\" &&\n !globalSkills.some((g) => g.id === s.id) &&\n !excludedGlobalSkills.some((e) => e.id === s.id) &&\n projectSkills.some((p) => p.id === s.id),\n );\n const inheritedGlobalAgents = activeAgentBaseline.filter(\n (a) =>\n a.scope === \"global\" &&\n !globalAgents.some((g) => g.name === a.name) &&\n !excludedGlobalAgents.some((e) => e.name === a.name) &&\n projectAgents.some((p) => p.name === a.name),\n );\n\n // Slot-occupancy match over the ACTIVE baseline: an installed entry at\n // (id, scope) is considered removed only if nothing — active OR tombstone —\n // occupies that slot in current. A current tombstone at the same key keeps the\n // slot occupied (dual-scope indicator, not a removal).\n //\n // A baseline TOMBSTONE is never a removal candidate. It masks a global install\n // rather than being one, so its slot held nothing to delete and dropping it\n // takes nothing away — a `-` there announces a deletion that never happens.\n const removedSkills = activeSkillBaseline.filter(\n (s) => !currentSkills.some((c) => c.id === s.id && c.scope === s.scope),\n );\n const removedAgents = activeAgentBaseline.filter(\n (a) => !currentAgents.some((c) => c.name === a.name && c.scope === a.scope),\n );\n\n // The Global section renders at most one row per skill, so both of the ways a\n // baseline global entry can re-surface are deduped against the inherited set:\n // `uniqueExcludedGlobalSkills` for the current tombstone, and the removed-global\n // rows below for the removal match. The second is not covered by the first —\n // an inherited global that the project claims WITHOUT a tombstone occupies no\n // slot in current, so it is admitted as inherited and matched as removed at\n // once, and the same skill lands under Global twice.\n const inheritedSkillIdSet = new Set(inheritedGlobalSkills.map((s) => s.id));\n const uniqueExcludedGlobalSkills = excludedGlobalSkills.filter(\n (s) => !inheritedSkillIdSet.has(s.id),\n );\n const allGlobalSkills = [\n ...globalSkills,\n ...inheritedGlobalSkills,\n ...uniqueExcludedGlobalSkills,\n ];\n const inheritedAgentNameSet = new Set(inheritedGlobalAgents.map((a) => a.name));\n const uniqueExcludedGlobalAgents = excludedGlobalAgents.filter(\n (a) => !inheritedAgentNameSet.has(a.name),\n );\n const allGlobalAgents = [\n ...globalAgents,\n ...inheritedGlobalAgents,\n ...uniqueExcludedGlobalAgents,\n ];\n\n const removedGlobalSkills = isInitMode\n ? []\n : removedSkills.filter((s) => s.scope === \"global\" && !inheritedSkillIdSet.has(s.id));\n const removedProjectSkills = removedSkills.filter((s) => s.scope === \"project\");\n const removedGlobalAgents = isInitMode\n ? []\n : removedAgents.filter((a) => a.scope === \"global\" && !inheritedAgentNameSet.has(a.name));\n const removedProjectAgents = removedAgents.filter((a) => a.scope === \"project\");\n\n const projectSkillRows = [\n ...projectSkills.map((s) => classifyDiffRow(s, prevSkillKeySet, prevSourceMap)),\n ...removedProjectSkills.map(toRemovedSkillRow),\n ];\n const globalSkillRows = [\n ...allGlobalSkills.map((s) => classifyDiffRow(s, prevSkillKeySet, prevSourceMap)),\n ...removedGlobalSkills.map(toRemovedSkillRow),\n ];\n const projectAgentRows = [\n ...projectAgents.map((a) => classifyAgentDiffRow(a, prevAgentKeySet)),\n ...removedProjectAgents.map(toRemovedAgentRow),\n ];\n const globalAgentRows = [\n ...allGlobalAgents.map((a) => classifyAgentDiffRow(a, prevAgentKeySet)),\n ...removedGlobalAgents.map(toRemovedAgentRow),\n ];\n\n const hasContent =\n projectSkillRows.length > 0 ||\n globalSkillRows.length > 0 ||\n projectAgentRows.length > 0 ||\n globalAgentRows.length > 0;\n\n return { projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows, hasContent };\n}\n\n/** The `(id, scope)` SLOT key this module diffs on, rather than the id alone. */\nfunction skillSlotKey(id: SkillId, scope: SkillScope | undefined): string {\n return `${id}:${scope}`;\n}\n\n/** The `(name, scope)` SLOT key for an agent — the agent-side counterpart of {@link skillSlotKey}. */\nfunction agentSlotKey(name: AgentName, scope: SkillScope | undefined): string {\n return `${name}:${scope}`;\n}\n\n/** Bracketed scope badge: `[G]` for global, `[P]` for project. */\nexport function formatScopeTag(scope: SkillScope): \"[G]\" | \"[P]\" {\n return scope === \"global\" ? \"[G]\" : \"[P]\";\n}\n\n/**\n * Classifies an active skill entry against the baseline: added, mode-changed, or unchanged.\n *\n * The comparison is on `origin`, because that field IS where a skill's install mode is\n * recorded: `eject` means the project's own copy and anything else names the marketplace the\n * plugin comes from. With no second marketplace to move between, an `origin` that changed is a\n * mode that changed, which is what the `~` marker has always meant to a reader.\n */\nfunction classifyDiffRow(\n skill: SkillConfig,\n prevKeySet: Set<string> | null,\n prevSourceMap: Map<string, string> | null,\n): SkillDiffRow {\n const key = skillSlotKey(skill.id, skill.scope);\n const isNew = prevKeySet === null || !prevKeySet.has(key);\n const prevSource = prevSourceMap?.get(key);\n const modeChanged = !isNew && prevSource != null && prevSource !== skill.origin;\n if (modeChanged) {\n return { id: skill.id, source: skill.origin, status: \"mode-changed\" };\n }\n return { id: skill.id, source: skill.origin, status: isNew ? \"added\" : \"unchanged\" };\n}\n\nfunction classifyAgentDiffRow(\n agent: AgentScopeConfig,\n prevKeySet: Set<string> | null,\n): AgentDiffRow {\n const isNew = prevKeySet === null || !prevKeySet.has(agentSlotKey(agent.name, agent.scope));\n return { name: agent.name, status: isNew ? \"added\" : \"unchanged\" };\n}\n\nfunction toRemovedSkillRow(skill: SkillConfig): SkillDiffRow {\n return { id: skill.id, source: skill.origin, status: \"removed\" };\n}\n\nfunction toRemovedAgentRow(agent: AgentScopeConfig): AgentDiffRow {\n return { name: agent.name, status: \"removed\" };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1401,7 +1401,7 @@ var defaultRules = {
|
|
|
1401
1401
|
{
|
|
1402
1402
|
skill: "composable-components",
|
|
1403
1403
|
needs: ["react"],
|
|
1404
|
-
reason: "Composition patterns are React surface \u2014
|
|
1404
|
+
reason: "Composition patterns are React surface \u2014 JSX parts sharing context, ref as a prop, asChild/render via cloneElement, useId"
|
|
1405
1405
|
},
|
|
1406
1406
|
{
|
|
1407
1407
|
skill: "web-reviewing",
|
|
@@ -3589,4 +3589,4 @@ export {
|
|
|
3589
3589
|
defaultRules,
|
|
3590
3590
|
defaultStacks
|
|
3591
3591
|
};
|
|
3592
|
-
//# sourceMappingURL=chunk-
|
|
3592
|
+
//# sourceMappingURL=chunk-NQW25DCF.js.map
|