agents-inc 0.173.0 → 0.174.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 +54 -0
- package/dist/{chunk-Q4UNHVPX.js → chunk-3PJZ4QNJ.js} +7 -7
- package/dist/{chunk-3N4FSTVX.js → chunk-6PGXTLA4.js} +2 -2
- package/dist/{chunk-ITQF35UQ.js → chunk-7BHDKEGK.js} +3 -3
- package/dist/{chunk-7OG635DK.js → chunk-AIBVAYHS.js} +6 -2
- package/dist/{chunk-7OG635DK.js.map → chunk-AIBVAYHS.js.map} +1 -1
- package/dist/{chunk-AARQBW5L.js → chunk-APWMMZOK.js} +30 -23
- package/dist/chunk-APWMMZOK.js.map +1 -0
- package/dist/{chunk-WVFBBZEP.js → chunk-E45IT3HC.js} +117 -22
- package/dist/chunk-E45IT3HC.js.map +1 -0
- package/dist/{chunk-F437ICEG.js → chunk-ECPFYHDX.js} +2 -2
- package/dist/{chunk-EHJIQDXR.js → chunk-EFXVYQGT.js} +4 -4
- package/dist/{chunk-G7NUK3BF.js → chunk-FQF6VHO3.js} +29 -19
- package/dist/chunk-FQF6VHO3.js.map +1 -0
- package/dist/chunk-H5E6IO2L.js +116 -0
- package/dist/chunk-H5E6IO2L.js.map +1 -0
- package/dist/{chunk-3R3LHA4Q.js → chunk-I3WF6L43.js} +2 -2
- package/dist/{chunk-LJQXQTFC.js → chunk-IAQFZFWD.js} +4 -4
- package/dist/{chunk-BRZA7ZCX.js → chunk-IXVGBUWI.js} +5 -5
- package/dist/{chunk-2RTBSLSR.js → chunk-ORO2T4K2.js} +19 -5
- package/dist/chunk-ORO2T4K2.js.map +1 -0
- package/dist/{chunk-A3ZAXL5T.js → chunk-QCX66KBM.js} +3 -3
- package/dist/{chunk-VSPC74SS.js → chunk-R7GKQBZJ.js} +10 -9
- package/dist/chunk-R7GKQBZJ.js.map +1 -0
- package/dist/{chunk-VR6QTK5Z.js → chunk-REHVGFJE.js} +5 -5
- package/dist/{chunk-SPQSNZMM.js → chunk-TVEDNGVP.js} +2 -2
- package/dist/{chunk-MHAQWMNJ.js → chunk-WUSEZFER.js} +1 -5
- package/dist/{chunk-MHAQWMNJ.js.map → chunk-WUSEZFER.js.map} +1 -1
- package/dist/commands/build/marketplace.js +4 -4
- package/dist/commands/build/plugins.js +6 -6
- package/dist/commands/compile.js +12 -12
- package/dist/commands/doctor.js +7 -7
- package/dist/commands/edit.js +56 -59
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +10 -10
- package/dist/commands/init.js +17 -18
- package/dist/commands/list.js +41 -16
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/marketplace.js +4 -4
- package/dist/commands/search.js +9 -9
- package/dist/commands/share.js +9 -9
- package/dist/commands/uninstall.js +25 -24
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +6 -6
- package/dist/components/common/select-list.js +2 -2
- package/dist/components/common/skill-agent-summary.js +3 -3
- package/dist/components/common/summary-panel.js +4 -7
- package/dist/hooks/init.js +40 -25
- package/dist/hooks/init.js.map +1 -1
- package/dist/load-agent-defs-5U5KAURA.js +14 -0
- package/dist/{recompile-project-agents-6G6M2RS6.js → recompile-project-agents-KYK44C24.js} +8 -8
- package/dist/{source-loader-W7XCNKNA.js → source-loader-G5I4RNUP.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-2RTBSLSR.js.map +0 -1
- package/dist/chunk-AARQBW5L.js.map +0 -1
- package/dist/chunk-G7NUK3BF.js.map +0 -1
- package/dist/chunk-N33AKFLR.js +0 -24
- package/dist/chunk-N33AKFLR.js.map +0 -1
- package/dist/chunk-Q6WRR4BN.js +0 -195
- package/dist/chunk-Q6WRR4BN.js.map +0 -1
- package/dist/chunk-VSPC74SS.js.map +0 -1
- package/dist/chunk-WVFBBZEP.js.map +0 -1
- package/dist/components/common/scroll-affordance.js +0 -9
- package/dist/load-agent-defs-E67DSYTN.js +0 -14
- package/dist/source-loader-W7XCNKNA.js.map +0 -1
- /package/dist/{chunk-Q4UNHVPX.js.map → chunk-3PJZ4QNJ.js.map} +0 -0
- /package/dist/{chunk-3N4FSTVX.js.map → chunk-6PGXTLA4.js.map} +0 -0
- /package/dist/{chunk-ITQF35UQ.js.map → chunk-7BHDKEGK.js.map} +0 -0
- /package/dist/{chunk-F437ICEG.js.map → chunk-ECPFYHDX.js.map} +0 -0
- /package/dist/{chunk-EHJIQDXR.js.map → chunk-EFXVYQGT.js.map} +0 -0
- /package/dist/{chunk-3R3LHA4Q.js.map → chunk-I3WF6L43.js.map} +0 -0
- /package/dist/{chunk-LJQXQTFC.js.map → chunk-IAQFZFWD.js.map} +0 -0
- /package/dist/{chunk-BRZA7ZCX.js.map → chunk-IXVGBUWI.js.map} +0 -0
- /package/dist/{chunk-A3ZAXL5T.js.map → chunk-QCX66KBM.js.map} +0 -0
- /package/dist/{chunk-VR6QTK5Z.js.map → chunk-REHVGFJE.js.map} +0 -0
- /package/dist/{chunk-SPQSNZMM.js.map → chunk-TVEDNGVP.js.map} +0 -0
- /package/dist/{components/common/scroll-affordance.js.map → load-agent-defs-5U5KAURA.js.map} +0 -0
- /package/dist/{recompile-project-agents-6G6M2RS6.js.map → recompile-project-agents-KYK44C24.js.map} +0 -0
- /package/dist/{load-agent-defs-E67DSYTN.js.map → source-loader-G5I4RNUP.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/commands/init.tsx","../src/cli/lib/permission-checker.tsx"],"sourcesContent":["import os from \"os\";\nimport React from \"react\";\n\nimport { Flags, type Interfaces } from \"@oclif/core\";\nimport { Box, Text, useApp } from \"ink\";\nimport { partition } from \"remeda\";\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 ConfigWriteResult,\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 installsAtHome,\n joinedStatement,\n notInstalledGlobally,\n readInstalledGlobal,\n type HeldGlobal,\n type InstalledGlobal,\n} from \"../lib/seed/seed-apply.js\";\nimport { agentChangesAmong, type AgentChange } from \"../lib/configuration/scope-diff.js\";\nimport { isActiveAt } from \"../lib/configuration/scope-predicates.js\";\nimport { summaryPanelBlock, type SummaryPanelProps } from \"../components/common/summary-panel.js\";\nimport {\n getInstallationsByProvider,\n type ProviderInstallation,\n} from \"../lib/plugins/plugin-info.js\";\nimport {\n assertNamedSourceUsable,\n isLocalSource,\n resolveBranding,\n} 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 { providerToNameAt } from \"../lib/installation/provider-to-name.js\";\nimport { hostCompileNotices } from \"../lib/hosts/host-compile-notices.js\";\nimport {\n installationToName,\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_ADDRESS,\n EDITOR_URL,\n EJECT_SOURCE,\n editorConfigUrl,\n type Provider,\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 {\n AgentName,\n AgentScopeConfig,\n MergedSkillsMatrix,\n SkillConfig,\n SkillId,\n SkillScope,\n} from \"../types/index.js\";\nimport { type StartupMessage } from \"../utils/logger.js\";\nimport {\n ERROR_MESSAGES,\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 subAgentChanged,\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\nconst DASHBOARD_OPTIONS_LINE = ` ${DASHBOARD_OPTIONS.map(({ label }) => `[${label}]`).join(\" \")}`;\n\ntype DashboardCommand = (typeof DASHBOARD_OPTIONS)[number][\"value\"];\n\n/** A white-labelled name replaces the logo, because the logo spells the shipped name. */\nconst DashboardTitle: React.FC<{ name: string }> = ({ name }) =>\n name === DEFAULT_BRANDING.NAME ? <Text>{ASCII_LOGO}</Text> : <Text bold>{name}</Text>;\n\ntype DashboardProps = {\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 * Shared by the TTY and piped dashboards so the two cannot drift apart. A scope holding two\n * installations gets a named block for each, a blank line apart.\n */\nfunction dashboardCountLines({ installations }: DashboardData): string[] {\n const named = installations.length > 1;\n const blocks = installations.map((installation) => [\n ...(named ? [` Provider: ${installation.provider}`] : []),\n ...installationCountLines(installation),\n ]);\n return blankLineBetween(blocks);\n}\n\nfunction blankLineBetween(blocks: string[][]): string[] {\n return blocks.flatMap((block, index) => (index === 0 ? block : [\"\", ...block]));\n}\n\nfunction installationCountLines(installation: ProviderInstallation): string[] {\n return [\n ` Skills: ${installation.skillCount} installed`,\n ` Agents: ${installation.agentCount} compiled`,\n ` Mode: ${INSTALL_MODE_LABELS[installation.mode]}`,\n ...(installation.marketplace ? [` Marketplace: ${installation.marketplace}`] : []),\n ];\n}\n\nexport function formatDashboardText(data: DashboardData): string {\n return [data.name, \"\", ...dashboardCountLines(data), \"\", DASHBOARD_OPTIONS_LINE].join(\"\\n\");\n}\n\n/** Ctrl+C cancels the run; Escape (null) only leaves the dashboard. */\nconst DASHBOARD_INTERRUPTED = \"interrupted\";\n\ntype DashboardAnswer = DashboardCommand | typeof DASHBOARD_INTERRUPTED | null;\n\nasync function showDashboard(\n projectDir: string,\n log?: (message: string) => void,\n): Promise<DashboardAnswer> {\n const data = await getDashboardData(projectDir);\n\n if (!process.stdin.isTTY) {\n const output = log ?? console.log;\n output(formatDashboardText(data));\n return null;\n }\n\n // clearOnResolve repaints a clean terminal before unmount: the dashboard fills the 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\nfunction dashboardCommandArgv(command: DashboardCommand): string[] {\n return command === \"edit\" ? [\"--ui\"] : [];\n}\n\nexport type DashboardFlow = \"not-installed\" | \"shown\" | \"cancelled\";\n\n/** Never exits the process: callers decide from the {@link DashboardFlow} it answers. */\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/** A required key, not `?`: oclif writes the key as `undefined` when the flag is not passed. */\ntype SourceFlags = { marketplace: string | undefined };\n\ntype Selection = {\n result: InstallSelection;\n sourceResult: SourceLoadResult;\n /** Where the selection was actually loaded from; a shared id may name a marketplace. */\n sourceFlags: SourceFlags;\n /** A global install's own skills, recorded as they are and never installed over. */\n installedAlready: ReadonlySet<SkillId>;\n};\n\n/** The payload names the marketplace because a skill id never says where its repository lives. */\nfunction sharedConfigSourceFlags(flags: SourceFlags, payload: SeedPayload): SourceFlags {\n return { marketplace: flags.marketplace ?? payload.marketplace };\n}\n\nexport default class Init extends BaseCommand {\n /** Resolved once in {@link install}; the closing line is printed several calls below. */\n private brandingName: string = DEFAULT_BRANDING.NAME;\n\n static summary = `Initialize ${DEFAULT_BRANDING.NAME} in this project`;\n static description = `Build a configuration in ${EDITOR_ADDRESS}, 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: `Open ${EDITOR_ADDRESS} 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 /** The exit code is decided once, after every path through {@link install} has ended. */\n async run(): Promise<void> {\n await this.install();\n this.exitIfWorkIncomplete();\n }\n\n /** The link is printed before it is opened, so it still works where no browser can open. */\n private async openEditor(\n projectDir: string,\n provider: Provider | undefined,\n id?: string,\n marketplace?: string,\n ): 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 const installedHere = await holdsItsOwnInstallation(projectDir);\n const toName = installedHere ? await installationToName(projectDir, provider) : provider;\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, installedHere, toName));\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 private async install(): Promise<void> {\n const { flags } = await this.parse(Init);\n const projectDir = process.cwd();\n\n // First, so a refused `--provider` leaves the filesystem untouched at both scopes.\n this.settleTheProviderForThisRun(flags);\n\n // Before `ensureConfigReadable`: a broken config must not block the editor route.\n if (opensTheEditor(flags)) {\n return this.openEditor(\n projectDir,\n providerNamedBy(flags.provider),\n flags.from,\n flags.marketplace,\n );\n }\n\n // ABORT: an unreadable config is refused here, before any route reads it.\n await this.ensureConfigReadable(projectDir);\n\n if (flags.from === undefined) return this.showDashboardOrOpenEditor(projectDir);\n\n // Its degrade arm cannot fire: `ensureConfigReadable` already refused every unreadable config.\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 this.reportValidationErrors(selection.result.validation);\n\n await this.handleInstallation(selection, projectDir);\n }\n\n private async showDashboardOrOpenEditor(projectDir: string): Promise<void> {\n const dashboard = await runDashboardFlow(projectDir, this.config, (msg) => this.log(msg));\n switch (dashboard) {\n case \"cancelled\":\n return this.error(\"Cancelled\", { exit: EXIT_CODES.CANCELLED });\n case \"not-installed\":\n return this.openEditor(projectDir, undefined);\n case \"shown\":\n return;\n default: {\n const _exhaustive: never = dashboard;\n return _exhaustive;\n }\n }\n }\n\n /** Refused as the install route refuses it, since the line echoes the ref it was given. */\n private addMarketplaceLineOrFail(ref: string): string {\n try {\n assertNamedSourceUsable(ref);\n return addMarketplaceInTheEditor(ref, isLocalSource(ref));\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /** `--provider` only picks which folder an install creates, so it needs `--from`. */\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 /** Every refusal fires before anything is written. */\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 const payload = await this.fetchSharedConfigOrFail(id);\n const sourceFlags = sharedConfigSourceFlags(flags, payload);\n const { sourceResult, startupMessages } = await this.loadSourceOrFail(sourceFlags, projectDir);\n // Before the decode, which would otherwise skip carried skills as unknown ids.\n const carriedSkills = this.registerExternalSkillsOrFail(\n payload,\n sourceResult.matrix,\n projectDir,\n );\n const mapping = this.decodeSeedOrFail(payload, sourceResult.matrix);\n const { result } = mapping;\n\n // Nothing is installed here: `refuseInstalledProject` has already refused a home that holds one.\n this.refuseProjectScopedContentAtHome(result, projectDir, false);\n\n const installedGlobal = await installedGlobalToHold(projectDir);\n const held = holdInstalledGlobal(result, installedGlobal);\n const arrivingCarried = notInstalledGlobally(carriedSkills, held);\n\n // Above the lists: a yes installs what was listed, so nothing listed may then be refused.\n await this.refuseSharedConfigBeforeAsking(\n held.result,\n arrivingCarried,\n projectDir,\n sourceResult,\n );\n\n // Above the skips: an \"unknown\" skill is often one whose file failed to parse.\n sayCapturedWarnings(startupMessages);\n this.warnOfSkippedEntries(mapping);\n this.refuseAnEmptySelection(held.result, id);\n\n const stackName = await this.stackNameOf(result.selectedStackId, sourceResult);\n this.logWhatGoesWhere(held, installedGlobal, stackName, {\n id: installsAtHome(result) ? id : undefined,\n provider: providerToNameAt(os.homedir(), providerInUse(projectDir)),\n });\n if (process.stdin.isTTY && !(await this.confirmInstall())) {\n this.log(\"Setup cancelled\");\n return null;\n }\n\n // After the question, so a refusal or a no leaves nothing written.\n await this.writeCarriedSkills(arrivingCarried);\n this.announceArrivingSkills(held, result.selectedAgents.length);\n\n return {\n result: held.result,\n sourceResult,\n sourceFlags,\n installedAlready: new Set(held.installed.skillIds),\n };\n }\n\n /**\n * The panel where the question is asked, or where it would be: the project against the whole\n * global install it inherits. `runFromHome.id` is the id only where home would take it.\n */\n private logWhatGoesWhere(\n held: HeldGlobal,\n installedGlobal: InstalledGlobal | null,\n stackName: string | undefined,\n runFromHome: RunFromHome,\n ): void {\n const joined = joinedGlobalAgents(held, installedGlobal);\n const lines = summaryPanelBlock(\n installPanel(held, installedGlobal, joined, stackName),\n joined.map(subAgentChanged),\n [...joinedStatement(held), ...keptAsInstalledStatement(held, runFromHome)],\n );\n for (const line of lines) {\n this.log(line);\n }\n }\n\n private refuseAnEmptySelection(result: InstallSelection, id: string): void {\n if (!selectsNothing(result)) return;\n\n this.error(`Configuration '${id}' contains no skills this catalog can install.`, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n private announceArrivingSkills(held: HeldGlobal, agentCount: number): void {\n const arriving = notInstalledGlobally(held.result.skills, held);\n if (arriving.length === 0) return;\n\n this.log(`Installing ${arriving.length} skill(s) across ${agentCount} sub-agent(s)\\n`);\n }\n\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 /** Project-scoped: `detectInstallation`'s global fallback would refuse every clean project. */\n private async refuseInstalledProject(projectDir: string, id: string): Promise<void> {\n const installation = await detectProjectInstallation(projectDir);\n if (!installation) return;\n\n const provider = providerToNameAt(projectDir, providerInUse(projectDir));\n this.error(sharedConfigExistingInstall(installation.configPath, id, provider), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n private async fetchSharedConfigOrFail(id: string): Promise<SeedPayload> {\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 return fetched.payload;\n }\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 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 private async writeCarriedSkills(carried: ExternalSkillInstall[]): Promise<void> {\n if (carried.length === 0) return;\n\n await writeExternalSkills(carried);\n this.log(carriedSkillsWritten(carried.map((skill) => skill.id)));\n }\n\n private async loadSourceOrFail(\n flags: SourceFlags,\n projectDir: string,\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,\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, sourceResult, sourceFlags, installedAlready }: Selection,\n projectDir: string,\n ): Promise<void> {\n const plan = planInstall(result, installedAlready);\n this.logInstallPlan(plan);\n\n // Before any copy, so a failed resolution cannot leave a half-install with no config.ts.\n const resolvedMarketplace = await this.marketplaceForPluginSkills(\n plan.pluginSkills,\n sourceResult,\n projectDir,\n );\n\n const copyResult = await this.copyEjectedSkills(plan, projectDir, sourceResult);\n\n if (resolvedMarketplace !== null) {\n await this.installPluginSkillsReported(\n plan.pluginSkills,\n resolvedMarketplace,\n projectDir,\n sourceResult.matrix,\n );\n }\n\n try {\n const written = await this.writeConfigAndCompile(\n result,\n sourceResult,\n sourceFlags,\n projectDir,\n );\n this.reportSuccess(written, copyResult, projectDir);\n\n await this.showPermissionNotice(projectDir);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async marketplaceForPluginSkills(\n pluginSkills: InstallSelection[\"skills\"],\n sourceResult: SourceLoadResult,\n projectDir: string,\n ): Promise<string | null> {\n if (pluginSkills.length === 0) return null;\n\n return this.requireMarketplaceOrExit(\n sourceResult,\n \"install plugin skills\",\n hostAt(projectDir),\n (marketplace) => this.log(`Registering marketplace \"${marketplace}\"...`),\n );\n }\n\n /** One frame, then unmount: the notice has no exit of its own and `--from` must run headless. */\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(plan: InstallPlan): void {\n this.log(\"\\n\");\n this.log(`Selected ${plural(plan.ejectedSkills.length + plan.pluginSkills.length, \"skill\")}`);\n this.log(`Install mode: ${installModeDescription(plan)}`);\n }\n\n private async copyEjectedSkills(\n { ejectedSkills, installMode }: InstallPlan,\n projectDir: string,\n sourceResult: SourceLoadResult,\n ): Promise<SkillCopyResult | null> {\n if (ejectedSkills.length === 0) return null;\n\n this.log(\"Copying skills to local directory...\");\n const copyResult = await copyLocalSkills(ejectedSkills, 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 projectDir: string,\n ): Promise<WrittenInstall> {\n const configResult = await this.writeConfigReported(result, sourceResult, flags, projectDir);\n const agentScopeMap = buildAgentScopeMap(configResult.config);\n const compileResult = await this.compileInstalledAgents(\n configResult.propagation,\n agentScopeMap,\n projectDir,\n );\n this.reportCompilation(compileResult);\n await this.reportWhatThisHostCannotCarry(projectDir);\n\n this.reportFanOut(configResult.propagation);\n\n return { configResult, compileResult, agentScopeMap };\n }\n\n private async writeConfigReported(\n result: InstallSelection,\n sourceResult: SourceLoadResult,\n flags: SourceFlags,\n projectDir: string,\n ): Promise<ConfigWriteResult> {\n this.log(\"Generating configuration...\");\n const configResult = await writeProjectConfig({\n selection: result,\n sourceResult,\n projectDir,\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 return configResult;\n }\n\n private async compileInstalledAgents(\n written: GateReport,\n agentScopeMap: Map<AgentName, SkillScope>,\n projectDir: string,\n ): Promise<CompilationResult> {\n this.log(STATUS_MESSAGES.COMPILING_AGENTS);\n // Sequential: both can reject and discovery warns, so the order decides what the user reads.\n const agentDefs = await loadAgentDefs();\n const { allSkills } = await discoverInstalledSkills(projectDir);\n const compile = compilesGlobalScope(projectDir, written)\n ? compileAgentsAllScopes\n : compileProjectScope;\n return compile({\n projectDir,\n sourcePath: agentDefs.sourcePath,\n skills: allSkills,\n agentScopeMap,\n });\n }\n\n private async reportWhatThisHostCannotCarry(projectDir: string): Promise<void> {\n for (const notice of await hostCompileNotices(providerInUse(projectDir), projectDir)) {\n this.log(notice);\n }\n }\n\n /**\n * Failures are recorded rather than aborted on: the skills and config are already written, and\n * {@link BaseCommand.exitIfWorkIncomplete} answers for them.\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 // Off `failed`, not `warnings`: warnings also carry entries that are not failures.\n this.recordIncompleteWork(agentsNotCompiled(failed), INCOMPLETE_WORK_RECOVERY.RECOMPILE);\n }\n\n private reportSuccess(\n { configResult, compileResult, agentScopeMap }: WrittenInstall,\n copyResult: SkillCopyResult | null,\n projectDir: string,\n ): void {\n // A run with work owed ends on the failure account instead of claiming success.\n if (!this.hasIncompleteWork) this.log(`${initSucceeded(this.brandingName)}\\n`);\n\n if (copyResult !== null && copyResult.totalCopied > 0) {\n this.logDirectoryBlocks(\"Skills copied to:\", skillsCopiedBlocks(projectDir, copyResult));\n }\n this.logDirectoryBlocks(\n \"Agents compiled to:\",\n agentsCompiledBlocks(projectDir, compileResult.compiled, agentScopeMap),\n );\n this.reportConfiguration(configResult, agentScopeMap, projectDir);\n }\n\n private reportConfiguration(\n { configPath, propagation }: ConfigWriteResult,\n agentScopeMap: Map<AgentName, SkillScope>,\n projectDir: string,\n ): void {\n const paths = {\n global: resolveInstallPaths(projectDir, \"global\").configPath,\n project: configPath,\n };\n const split = splitAgentScopes(projectDir, agentScopeMap);\n\n this.log(\"Configuration:\");\n for (const written of configsWritten(projectDir, paths, propagation.globalWritten)) {\n this.log(` ${written}`);\n }\n this.log(\"\");\n\n this.log(\"To customize agent-skill assignments:\");\n for (const [index, step] of customizationSteps(split, paths.global, projectDir).entries()) {\n this.log(` ${index + 1}. ${step}`);\n }\n this.log(\"\");\n }\n\n private logDirectoryBlocks(heading: string, blocks: DirectoryBlock[]): void {\n for (const { dir, entries } of blocks) {\n this.log(heading);\n this.log(` ${dir}`);\n for (const entry of entries) {\n this.log(` ${entry}`);\n }\n this.log(\"\");\n }\n }\n}\n\n/** The editor is where a marketplace is added, so `--marketplace` without `--from` opens it. */\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/** A sub-agent is installable without skills, so only a selection with neither is empty. */\nfunction selectsNothing(result: InstallSelection): boolean {\n return result.skills.length === 0 && result.selectedAgents.length === 0;\n}\n\n/** At the home root the global config is the project's own, so there is no global install apart. */\nasync function installedGlobalToHold(projectDir: string): Promise<InstalledGlobal | null> {\n if (isHomeDirectory(projectDir)) return null;\n return await readInstalledGlobal(projectDir);\n}\n\n/** The run from home that changes what a project run keeps, where home would take it. */\ntype RunFromHome = { id: string | undefined; provider: Provider | undefined };\n\nfunction keptAsInstalledStatement(held: HeldGlobal, runFromHome: RunFromHome): string[] {\n const { skillIds, agentNames } = held.keptAsInstalled;\n if (skillIds.length === 0 && agentNames.length === 0) return [];\n return [keptAsInstalledGlobally(skillIds, agentNames, runFromHome.id, runFromHome.provider)];\n}\n\ntype GlobalEntries = { skills: SkillConfig[]; agents: AgentScopeConfig[] };\n\n/** What the project inherits that the configuration leaves unnamed: a project config copies it all. */\nfunction inheritedGlobal(held: HeldGlobal, installedGlobal: InstalledGlobal | null): GlobalEntries {\n if (installedGlobal === null) return { skills: [], agents: [] };\n\n const namedSkills = new Set(held.result.skills.filter(isGlobal).map(({ id }) => id));\n const namedAgents = new Set(held.result.agentConfigs.filter(isGlobal).map(({ name }) => name));\n return {\n skills: installedGlobal.skills.filter((skill) => isGlobal(skill) && !namedSkills.has(skill.id)),\n agents: installedGlobal.agents.filter(\n (agent) => isGlobal(agent) && !namedAgents.has(agent.name),\n ),\n };\n}\n\nfunction isGlobal(entry: SkillConfig | AgentScopeConfig): boolean {\n return isActiveAt(entry, \"global\");\n}\n\n/** Measured against the global install: the project changes nothing else of it. */\nfunction installPanel(\n held: HeldGlobal,\n installedGlobal: InstalledGlobal | null,\n joined: AgentChange[],\n stackName: string | undefined,\n): SummaryPanelProps {\n const inherited = inheritedGlobal(held, installedGlobal);\n return {\n skillConfigs: [...held.result.skills, ...inherited.skills],\n agentConfigs: [...held.result.agentConfigs, ...inherited.agents],\n installedSkillConfigs: installedGlobal?.skills ?? null,\n installedAgentConfigs: installedGlobal?.agents ?? null,\n isInitMode: true,\n changedAgentNames: new Set(joined.map(({ name }) => name)),\n stackName,\n };\n}\n\n/** The held global sub-agents an arriving skill's row joins, against their installed rows. */\nfunction joinedGlobalAgents(\n held: HeldGlobal,\n installedGlobal: InstalledGlobal | null,\n): AgentChange[] {\n if (installedGlobal === null) return [];\n\n return agentChangesAmong(\n held.joined.map(({ agentName }) => agentName),\n installedGlobal,\n { agents: held.result.agentConfigs, stack: held.result.assignedStack },\n );\n}\n\ntype InstallPlan = {\n installMode: InstallMode;\n ejectedSkills: InstallSelection[\"skills\"];\n pluginSkills: InstallSelection[\"skills\"];\n};\n\nfunction planInstall(\n result: InstallSelection,\n installedAlready: ReadonlySet<SkillId>,\n): InstallPlan {\n const toInstall = result.skills.filter(\n (skill) => !skill.excluded && !installedAlready.has(skill.id),\n );\n const [ejectedSkills, pluginSkills] = partition(\n toInstall,\n (skill) => skill.origin === EJECT_SOURCE,\n );\n return { installMode: deriveInstallMode(toInstall), ejectedSkills, pluginSkills };\n}\n\nfunction installModeDescription({ installMode, ejectedSkills, pluginSkills }: InstallPlan): string {\n if (installMode !== \"mixed\") return INSTALL_MODE_DESCRIPTIONS[installMode];\n return `${INSTALL_MODE_LABELS.mixed} (${ejectedSkills.length} eject, ${pluginSkills.length} plugin)`;\n}\n\ntype WrittenInstall = {\n configResult: ConfigWriteResult;\n compileResult: CompilationResult;\n agentScopeMap: Map<AgentName, SkillScope>;\n};\n\n/**\n * From a project, global sub-agents recompile only when the write changed their inputs;\n * otherwise they would be rebuilt from this run's catalogue, not the one they were made from.\n */\nfunction compilesGlobalScope(cwd: string, written: GateReport): boolean {\n return isHomeDirectory(cwd) || movedGlobalAgentInputs(written);\n}\n\n/** Names the directory only when every skill landed at one scope; the block beneath lists both. */\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/** Entries are on-disk names, so ids, never display names. */\ntype DirectoryBlock = { dir: string; entries: string[] };\n\nfunction hasEntries(block: DirectoryBlock): boolean {\n return block.entries.length > 0;\n}\n\n/** At home a Claude install's two scopes are one folder, which is named once. */\nfunction oneBlockPerDir(blocks: DirectoryBlock[]): DirectoryBlock[] {\n const dirs = [...new Set(blocks.map((block) => block.dir))];\n return dirs.map((dir) => ({\n dir,\n entries: blocks.filter((block) => block.dir === dir).flatMap((block) => block.entries),\n }));\n}\n\nfunction skillsCopiedBlocks(projectDir: string, copyResult: SkillCopyResult): DirectoryBlock[] {\n return oneBlockPerDir(\n [\n copiedSkillsBlock(projectDir, \"global\", copyResult.globalCopied),\n copiedSkillsBlock(projectDir, \"project\", copyResult.projectCopied),\n ].filter(hasEntries),\n );\n}\n\nfunction copiedSkillsBlock(\n projectDir: string,\n scope: SkillScope,\n copied: SkillCopyResult[\"projectCopied\"],\n): DirectoryBlock {\n return {\n dir: resolveInstallPaths(projectDir, scope).skillsDir,\n entries: copied.map(({ skillId }) => `${skillId}/`),\n };\n}\n\n/** Mirrors `writeCompiledAgentsByScope`' routing. */\nfunction agentsCompiledBlocks(\n projectDir: string,\n compiled: AgentName[],\n agentScopeMap: Map<AgentName, SkillScope>,\n): DirectoryBlock[] {\n const [globalAgents, projectAgents] = partition(\n compiled,\n (name) => agentScopeMap.get(name) === \"global\",\n );\n return oneBlockPerDir(\n [\n compiledAgentsBlock(projectDir, \"global\", globalAgents),\n compiledAgentsBlock(projectDir, \"project\", projectAgents),\n ].filter(hasEntries),\n );\n}\n\n/** Per scope, because the project and global installs can be on different hosts. */\nfunction compiledAgentsBlock(\n projectDir: string,\n scope: SkillScope,\n agents: AgentName[],\n): DirectoryBlock {\n const { extension } = agentCodec(providerInUse(installBaseDir(projectDir, scope)));\n return {\n dir: resolveInstallPaths(projectDir, scope).agentsDir,\n entries: agents.map((name) => `${name}${extension}`),\n };\n}\n\ntype ConfigPaths = { global: string; project: string };\n\ntype AgentScopeSplit = { globalAgentCount: number; isGlobalOnly: boolean };\n\n/** At the home root both scopes are one config and one pass, so there is no split. */\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 * From a project its own config is always written, and the global one whenever the run changed it,\n * if only to register the project. At home the two are one file.\n */\nfunction configsWritten(projectDir: string, paths: ConfigPaths, globalWritten: boolean): string[] {\n if (isHomeDirectory(projectDir)) return [paths.project];\n return globalWritten ? [paths.global, paths.project] : [paths.project];\n}\n\n/** `compile` in a project recompiles no global agent, hence the global hint. */\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 name: string;\n installations: ProviderInstallation[];\n};\n\n/** Each installation's counts come from its own scope-aware read, so project and global never mix. */\nasync function getDashboardData(projectDir: string): Promise<DashboardData> {\n // ABORT: an unloadable config throws here, as the installation check before it already would.\n const [installations, branding] = await Promise.all([\n getInstallationsByProvider(projectDir),\n resolveBranding(projectDir),\n ]);\n // Every caller found an installation before drawing the dashboard.\n if (installations.length === 0) throw new Error(ERROR_MESSAGES.NO_INSTALLATION);\n\n return { name: branding.name, installations };\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/** Undefined when absent, malformed or empty; silent about every other field (Claude Code's). */\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\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/** Relative to the project and POSIX-separated: a name shown to a person, not a path to open. */\nfunction asUserWritesIt(projectRoot: string, file: string): string {\n return path.relative(projectRoot, file).split(path.sep).join(\"/\");\n}\n\n/** `null` for a host whose permission model this release cannot advise on. */\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: the one this CLI writes and a user with neither is asked to create.\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"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/common/skill-agent-summary.tsx","../src/cli/lib/configuration/scope-diff.ts"],"sourcesContent":["import { Box, Text } from \"ink\";\nimport React from \"react\";\nimport { CLI_COLORS, EJECT_SOURCE, UI_SYMBOLS } from \"../../consts.js\";\nimport { computeScopeDiff } from \"../../lib/configuration/scope-diff.js\";\nimport type {\n AgentDiffRow,\n DiffRowStatus,\n ScopeDiffInput,\n SkillDiffRow,\n} from \"../../lib/configuration/scope-diff.js\";\nimport { getSkillDisplayName } from \"../../lib/matrix/matrix-provider.js\";\nimport type { AgentScopeConfig, SkillConfig } from \"../../types/config.js\";\nimport type { SkillId } from \"../../types/skills.js\";\nimport { inertLine } from \"../../utils/string.js\";\n\nexport type SkillAgentSummaryProps = Pick<\n ScopeDiffInput,\n | \"installedSkillConfigs\"\n | \"installedAgentConfigs\"\n | \"isInitMode\"\n | \"overwrittenSkillIds\"\n | \"changedAgentNames\"\n> & {\n skillConfigs: SkillConfig[];\n agentConfigs: AgentScopeConfig[];\n /** Read off each copy's metadata.yaml by a run that loads no marketplace to name them from. */\n skillNames?: ReadonlyMap<SkillId, string>;\n};\n\nconst NO_NAMES: ReadonlyMap<SkillId, string> = new Map();\n\n/** A name the run read stands over the catalogue's: it is what that copy says it is. */\nfunction skillNameOf(id: SkillId, names: ReadonlyMap<SkillId, string>): string {\n const recorded = names.get(id);\n return recorded === undefined ? getSkillDisplayName(id) : inertLine(recorded);\n}\n\nconst TableHeader: React.FC<{ children: React.ReactNode }> = ({ children }) => (\n <Text bold color={CLI_COLORS.WARNING}>\n {children}\n </Text>\n);\n\nconst ScopeLabel: React.FC<{ children: string }> = ({ children }) => (\n <Text color={CLI_COLORS.WHITE} backgroundColor={CLI_COLORS.LABEL_BG}>\n {` ${children} `}\n </Text>\n);\n\nconst EjectIcon: React.FC = () => <Text color={CLI_COLORS.WARNING}> {UI_SYMBOLS.EJECT}</Text>;\n\nconst DIFF_PREFIX: Record<DiffRowStatus, string> = {\n added: `${UI_SYMBOLS.ADDED} `,\n \"mode-changed\": `${UI_SYMBOLS.CHANGED} `,\n overwritten: `${UI_SYMBOLS.OVERWRITTEN} `,\n changed: `${UI_SYMBOLS.CHANGED} `,\n removed: `${UI_SYMBOLS.REMOVED} `,\n unchanged: `${UI_SYMBOLS.BULLET} `,\n};\n\nconst DIFF_COLOR: Record<DiffRowStatus, string> = {\n added: CLI_COLORS.SUCCESS,\n \"mode-changed\": CLI_COLORS.WARNING,\n overwritten: CLI_COLORS.WARNING,\n changed: CLI_COLORS.WARNING,\n removed: CLI_COLORS.ERROR,\n unchanged: CLI_COLORS.NEUTRAL,\n};\n\n/**\n * Yoga widens a text to whole columns on both sides and Ink draws it from its rounded left, so a\n * name in a half that starts or ends mid-column draws up to two columns past the half: over the\n * next name, or over the table's border. The third column stays blank.\n */\nconst NAME_GUTTER_COLUMNS = 3;\n\n/**\n * A long name wraps under itself, beside a prefix that never shrinks, and carries its mark in its\n * own text: drawn beside the name, the mark covered its last letters.\n */\nconst SkillRow: React.FC<{ row: SkillDiffRow; name: string }> = ({ row, name }) => (\n <Box width=\"50%\" paddingRight={NAME_GUTTER_COLUMNS}>\n <Box flexShrink={0}>\n <Text color={DIFF_COLOR[row.status]}>{DIFF_PREFIX[row.status]}</Text>\n </Box>\n <Text color={DIFF_COLOR[row.status]}>\n {name}\n {row.source === EJECT_SOURCE && <EjectIcon />}\n </Text>\n </Box>\n);\n\nconst AgentRow: React.FC<{ row: AgentDiffRow }> = ({ row }) => (\n <Text color={DIFF_COLOR[row.status]}>\n {DIFF_PREFIX[row.status]}\n {row.name}\n </Text>\n);\n\nconst skillRowKey = (row: SkillDiffRow): string =>\n row.status === \"removed\" ? `removed-${row.id}` : row.id;\n\nconst agentRowKey = (row: AgentDiffRow): string =>\n row.status === \"removed\" ? `removed-${row.name}` : row.name;\n\nexport const SkillAgentSummary: React.FC<SkillAgentSummaryProps> = ({\n skillConfigs,\n agentConfigs,\n skillNames = NO_NAMES,\n ...baseline\n}) => {\n const diff = computeScopeDiff({\n currentSkills: skillConfigs,\n currentAgents: agentConfigs,\n ...baseline,\n });\n\n if (!diff.hasContent) return null;\n\n return (\n <Box flexDirection=\"row\" width=\"100%\">\n <Box\n flexDirection=\"column\"\n borderStyle=\"single\"\n flexGrow={2}\n flexBasis={0}\n borderRight={true}\n borderTop={false}\n borderBottom={false}\n borderLeft={false}\n borderColor={CLI_COLORS.NEUTRAL}\n borderRightDimColor\n >\n <TableHeader>Skills</TableHeader>\n {diff.projectSkillRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Project</ScopeLabel>\n <Box flexWrap=\"wrap\">\n {diff.projectSkillRows.map((row) => (\n <SkillRow key={skillRowKey(row)} row={row} name={skillNameOf(row.id, skillNames)} />\n ))}\n </Box>\n </Box>\n )}\n {diff.globalSkillRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Global</ScopeLabel>\n <Box flexWrap=\"wrap\">\n {diff.globalSkillRows.map((row) => (\n <SkillRow key={skillRowKey(row)} row={row} name={skillNameOf(row.id, skillNames)} />\n ))}\n </Box>\n </Box>\n )}\n </Box>\n <Box flexDirection=\"column\" flexGrow={1} flexBasis={0} marginLeft={1} paddingLeft={1}>\n <TableHeader>Agents</TableHeader>\n {diff.projectAgentRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Project</ScopeLabel>\n <Box flexDirection=\"column\">\n {diff.projectAgentRows.map((row) => (\n <AgentRow key={agentRowKey(row)} row={row} />\n ))}\n </Box>\n </Box>\n )}\n {diff.globalAgentRows.length > 0 && (\n <Box flexDirection=\"column\" marginTop={1}>\n <ScopeLabel>Global</ScopeLabel>\n <Box flexDirection=\"column\">\n {diff.globalAgentRows.map((row) => (\n <AgentRow key={agentRowKey(row)} row={row} />\n ))}\n </Box>\n </Box>\n )}\n </Box>\n </Box>\n );\n};\n","import { difference, partition, unique } from \"remeda\";\nimport type { AgentScopeConfig, SkillConfig, SkillScope } from \"../../types/config\";\nimport type { AgentName, SkillId, StackAgentConfig } from \"../../types/index\";\nimport { typedValues } from \"../../utils/typed-object\";\nimport { isActiveAt, isGlobalTombstone, type ScopedEntry } from \"./scope-predicates\";\n\nexport type ScopeDiffInput = {\n currentSkills: SkillConfig[];\n currentAgents: AgentScopeConfig[];\n installedSkillConfigs: SkillConfig[] | null;\n installedAgentConfigs: AgentScopeConfig[] | null;\n isInitMode: boolean;\n /** Skills whose files the run writes over where they stand. */\n overwrittenSkillIds?: ReadonlySet<SkillId>;\n /** Sub-agents that keep their slot and still change. */\n changedAgentNames?: ReadonlySet<AgentName>;\n};\n\nexport type DiffRowStatus =\n \"added\" | \"mode-changed\" | \"overwritten\" | \"changed\" | \"removed\" | \"unchanged\";\n\nexport type SkillDiffRow = {\n id: SkillId;\n source: string;\n status: Exclude<DiffRowStatus, \"changed\">;\n};\n\nexport type AgentDiffRow = {\n name: AgentName;\n status: Exclude<DiffRowStatus, \"mode-changed\" | \"overwritten\">;\n};\n\nexport type ScopeDiff = {\n projectSkillRows: SkillDiffRow[];\n globalSkillRows: SkillDiffRow[];\n projectAgentRows: AgentDiffRow[];\n globalAgentRows: AgentDiffRow[];\n hasContent: boolean;\n};\n\nconst NOTHING: ReadonlySet<never> = new Set();\n\n/** One scope's share of a roster's diff: the entries listed with a status, then the removals. */\ntype ScopeEntries<Entry> = { listed: Entry[]; removed: Entry[] };\n\ntype RosterDiff<Entry> = Record<SkillScope, ScopeEntries<Entry>>;\n\n/**\n * A tombstone occupies its (id, scope) slot without filling it: it silences a global install at\n * project scope. Slot checks count tombstones; removal and `~` read the active baseline only.\n */\nexport function computeScopeDiff(input: ScopeDiffInput): ScopeDiff {\n const { currentSkills, currentAgents, installedSkillConfigs, installedAgentConfigs, isInitMode } =\n input;\n const overwritten = input.overwrittenSkillIds ?? NOTHING;\n const changed = input.changedAgentNames ?? NOTHING;\n\n const skills = diffRoster(currentSkills, installedSkillConfigs, (skill) => skill.id, isInitMode);\n const agents = diffRoster(\n currentAgents,\n installedAgentConfigs,\n (agent) => agent.name,\n isInitMode,\n );\n const skillRow = skillRowClassifier(installedSkillConfigs, overwritten);\n const agentRow = agentRowClassifier(installedAgentConfigs, changed);\n\n const projectSkillRows = rowsOf(skills.project, skillRow, toRemovedSkillRow);\n const globalSkillRows = rowsOf(skills.global, skillRow, toRemovedSkillRow);\n const projectAgentRows = rowsOf(agents.project, agentRow, toRemovedAgentRow);\n const globalAgentRows = rowsOf(agents.global, agentRow, toRemovedAgentRow);\n\n const hasContent = [projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows].some(\n (rows) => rows.length > 0,\n );\n\n return { projectSkillRows, globalSkillRows, projectAgentRows, globalAgentRows, hasContent };\n}\n\nfunction diffRoster<Entry extends ScopedEntry>(\n current: Entry[],\n installed: Entry[] | null,\n identityOf: (entry: Entry) => string,\n isInitMode: boolean,\n): RosterDiff<Entry> {\n // The installs the baseline actually records; tombstones are not installs.\n const activeBaseline = (installed ?? []).filter((entry) => !entry.excluded);\n const vacated = vacatedInstalls(activeBaseline, current, identityOf);\n const projectEntries = current.filter((entry) => isActiveAt(entry, \"project\"));\n const claimedByProject = new Set(projectEntries.map(identityOf));\n // A vacated global the project claims is inherited: listed once under Global, never removed.\n const [inheritedGlobals, removedGlobals] = partition(\n vacated.filter((entry) => entry.scope === \"global\"),\n (entry) => claimedByProject.has(identityOf(entry)),\n );\n\n return {\n project: {\n listed: projectEntries,\n removed: vacated.filter((entry) => entry.scope === \"project\"),\n },\n global: {\n listed: [\n ...current.filter((entry) => isActiveAt(entry, \"global\")),\n ...inheritedGlobals,\n ...current.filter(isGlobalTombstone),\n ],\n removed: isInitMode ? [] : removedGlobals,\n },\n };\n}\n\n/** Baseline installs whose slot nothing in current, active or tombstone, occupies. */\nfunction vacatedInstalls<Entry extends ScopedEntry>(\n activeBaseline: Entry[],\n current: Entry[],\n identityOf: (entry: Entry) => string,\n): Entry[] {\n const slotOf = (entry: Entry) => slotKey(identityOf(entry), entry.scope);\n const occupiedSlots = new Set(current.map(slotOf));\n return activeBaseline.filter((install) => !occupiedSlots.has(slotOf(install)));\n}\n\nfunction rowsOf<Entry, Row>(\n entries: ScopeEntries<Entry>,\n toRow: (entry: Entry) => Row,\n toRemovedRow: (entry: Entry) => Row,\n): Row[] {\n return [...entries.listed.map(toRow), ...entries.removed.map(toRemovedRow)];\n}\n\n/** The `(id, scope)` SLOT key this module diffs on, rather than the id alone. */\nfunction slotKey(identity: string, scope: SkillScope | undefined): string {\n return `${identity}:${scope}`;\n}\n\nexport function formatScopeTag(scope: SkillScope): \"[G]\" | \"[P]\" {\n return scope === \"global\" ? \"[G]\" : \"[P]\";\n}\n\nfunction skillRowClassifier(\n installed: SkillConfig[] | null,\n overwritten: ReadonlySet<SkillId>,\n): (skill: SkillConfig) => SkillDiffRow {\n const installedSlots = installed\n ? new Set(installed.map((skill) => slotKey(skill.id, skill.scope)))\n : null;\n const installedOriginBySlot = installed\n ? new Map(\n installed\n .filter((skill) => !skill.excluded)\n .map((skill) => [slotKey(skill.id, skill.scope), skill.origin]),\n )\n : null;\n return (skill) => ({\n id: skill.id,\n source: skill.origin,\n status: skillStatus(skill, installedSlots, installedOriginBySlot, overwritten),\n });\n}\n\nfunction agentRowClassifier(\n installed: AgentScopeConfig[] | null,\n changed: ReadonlySet<AgentName>,\n): (agent: AgentScopeConfig) => AgentDiffRow {\n const installedSlots = installed\n ? new Set(installed.map((agent) => slotKey(agent.name, agent.scope)))\n : null;\n return (agent) => ({ name: agent.name, status: agentStatus(agent, installedSlots, changed) });\n}\n\n/**\n * Compares `origin`, which is where a skill's install mode is recorded. An overwrite outranks a\n * mode change: a copy its plugin replaces is deleted, not merely switched. A mask is never written.\n */\nfunction skillStatus(\n skill: SkillConfig,\n installedSlots: Set<string> | null,\n installedOriginBySlot: Map<string, string> | null,\n overwritten: ReadonlySet<SkillId>,\n): SkillDiffRow[\"status\"] {\n const slot = slotKey(skill.id, skill.scope);\n if (installedSlots === null || !installedSlots.has(slot)) return \"added\";\n if (!skill.excluded && overwritten.has(skill.id)) return \"overwritten\";\n\n const installedOrigin = installedOriginBySlot?.get(slot);\n const modeChanged = installedOrigin != null && installedOrigin !== skill.origin;\n return modeChanged ? \"mode-changed\" : \"unchanged\";\n}\n\n/** A mask is never the sub-agent that changes: its active half is. */\nfunction agentStatus(\n agent: AgentScopeConfig,\n installedSlots: Set<string> | null,\n changed: ReadonlySet<AgentName>,\n): AgentDiffRow[\"status\"] {\n const isNew = installedSlots === null || !installedSlots.has(slotKey(agent.name, agent.scope));\n if (isNew) return \"added\";\n return !agent.excluded && changed.has(agent.name) ? \"changed\" : \"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\n/** A sub-agent that keeps its slot and still changes: the skills its rows gain and lose, and its retunes. */\nexport type AgentChange = {\n name: AgentName;\n scope: SkillScope;\n gains: SkillId[];\n loses: SkillId[];\n settings: SettingChange[];\n};\n\n/** `undefined` where the setting is left to its default. */\nexport type SettingChange = {\n setting: AgentSetting;\n from: string | undefined;\n to: string | undefined;\n};\n\ntype AgentSetting = \"model\" | \"codex model\" | \"effort\";\n\nconst AGENT_SETTINGS: ReadonlyArray<\n [AgentSetting, (agent: AgentScopeConfig) => string | undefined]\n> = [\n [\"model\", (agent) => agent.model],\n [\"codex model\", (agent) => agent.codexModel],\n [\"effort\", (agent) => agent.effort],\n];\n\n/** One sub-agent as a config records it: its entry and its skill rows. */\nexport type AgentState = { agent: AgentScopeConfig; rows: StackAgentConfig | undefined };\n\ntype AgentsAndRows = {\n agents: AgentScopeConfig[];\n stack?: Partial<Record<string, StackAgentConfig>>;\n};\n\n/** How each named sub-agent moves between two configs; one either config lacks is not named. */\nexport function agentChangesAmong(\n names: readonly AgentName[],\n before: AgentsAndRows,\n after: AgentsAndRows,\n): AgentChange[] {\n return names.flatMap((name) => {\n const was = agentStateIn(before, name);\n const is = agentStateIn(after, name);\n return was === undefined || is === undefined ? [] : [agentChange(was, is)];\n });\n}\n\n/** Its active entry, never the mask a project's own copy leaves; `undefined` where none is. */\nfunction agentStateIn(config: AgentsAndRows, name: AgentName): AgentState | undefined {\n const agent = config.agents.find((entry) => entry.name === name && !entry.excluded);\n return agent === undefined ? undefined : { agent, rows: config.stack?.[name] };\n}\n\nexport function agentChange(before: AgentState, after: AgentState): AgentChange {\n const beforeIds = assignedSkillIds(before.rows);\n const afterIds = assignedSkillIds(after.rows);\n\n return {\n name: after.agent.name,\n scope: after.agent.scope,\n gains: difference(afterIds, beforeIds),\n loses: difference(beforeIds, afterIds),\n settings: settingChanges(before.agent, after.agent),\n };\n}\n\nfunction settingChanges(before: AgentScopeConfig, after: AgentScopeConfig): SettingChange[] {\n return AGENT_SETTINGS.filter(([, read]) => read(before) !== read(after)).map(\n ([setting, read]) => ({ setting, from: read(before), to: read(after) }),\n );\n}\n\nfunction assignedSkillIds(rows: StackAgentConfig | undefined): SkillId[] {\n return unique(typedValues(rows ?? {}).flatMap((assignments) => assignments.map(({ id }) => id)));\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-N33AKFLR.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
SCROLL_VIEWPORT
|
|
4
|
-
} from "./chunk-MHAQWMNJ.js";
|
|
5
|
-
|
|
6
|
-
// src/cli/components/common/scroll-affordance.tsx
|
|
7
|
-
import { Box, Text } from "ink";
|
|
8
|
-
import "react";
|
|
9
|
-
import { jsx } from "react/jsx-runtime";
|
|
10
|
-
function formatHiddenCounts(hiddenAbove, hiddenBelow) {
|
|
11
|
-
return [
|
|
12
|
-
hiddenAbove > 0 ? `${hiddenAbove} more above` : null,
|
|
13
|
-
hiddenBelow > 0 ? `${hiddenBelow} more below` : null
|
|
14
|
-
].filter((part) => part !== null).join(" ");
|
|
15
|
-
}
|
|
16
|
-
var ScrollAffordance = ({ hiddenAbove, hiddenBelow }) => {
|
|
17
|
-
if (hiddenAbove <= 0 && hiddenBelow <= 0) return null;
|
|
18
|
-
return /* @__PURE__ */ jsx(Box, { height: SCROLL_VIEWPORT.SCROLL_INDICATOR_HEIGHT, flexShrink: 0, children: /* @__PURE__ */ jsx(Text, { dimColor: true, children: formatHiddenCounts(hiddenAbove, hiddenBelow) }) });
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
export {
|
|
22
|
-
ScrollAffordance
|
|
23
|
-
};
|
|
24
|
-
//# sourceMappingURL=chunk-N33AKFLR.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/common/scroll-affordance.tsx"],"sourcesContent":["import { Box, Text } from \"ink\";\nimport React from \"react\";\nimport { SCROLL_VIEWPORT } from \"../../consts.js\";\n\nexport type ScrollAffordanceProps = {\n hiddenAbove: number;\n hiddenBelow: number;\n};\n\nfunction formatHiddenCounts(hiddenAbove: number, hiddenBelow: number): string {\n return [\n hiddenAbove > 0 ? `${hiddenAbove} more above` : null,\n hiddenBelow > 0 ? `${hiddenBelow} more below` : null,\n ]\n .filter((part) => part !== null)\n .join(\" \");\n}\n\n/** Render as a sibling of the clipped viewport, never inside it, or it is clipped too. */\nexport const ScrollAffordance: React.FC<ScrollAffordanceProps> = ({ hiddenAbove, hiddenBelow }) => {\n if (hiddenAbove <= 0 && hiddenBelow <= 0) return null;\n\n return (\n <Box height={SCROLL_VIEWPORT.SCROLL_INDICATOR_HEIGHT} flexShrink={0}>\n <Text dimColor>{formatHiddenCounts(hiddenAbove, hiddenBelow)}</Text>\n </Box>\n );\n};\n"],"mappings":";;;;;;AAAA,SAAS,KAAK,YAAY;AAC1B,OAAkB;AAuBZ;AAfN,SAAS,mBAAmB,aAAqB,aAA6B;AAC5E,SAAO;AAAA,IACL,cAAc,IAAI,GAAG,WAAW,gBAAgB;AAAA,IAChD,cAAc,IAAI,GAAG,WAAW,gBAAgB;AAAA,EAClD,EACG,OAAO,CAAC,SAAS,SAAS,IAAI,EAC9B,KAAK,KAAK;AACf;AAGO,IAAM,mBAAoD,CAAC,EAAE,aAAa,YAAY,MAAM;AACjG,MAAI,eAAe,KAAK,eAAe,EAAG,QAAO;AAEjD,SACE,oBAAC,OAAI,QAAQ,gBAAgB,yBAAyB,YAAY,GAChE,8BAAC,QAAK,UAAQ,MAAE,6BAAmB,aAAa,WAAW,GAAE,GAC/D;AAEJ;","names":[]}
|
package/dist/chunk-Q6WRR4BN.js
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
ScrollAffordance
|
|
4
|
-
} from "./chunk-N33AKFLR.js";
|
|
5
|
-
import {
|
|
6
|
-
SkillAgentSummary
|
|
7
|
-
} from "./chunk-G7NUK3BF.js";
|
|
8
|
-
import {
|
|
9
|
-
ALL_SKILLS_EJECTED_LABEL,
|
|
10
|
-
CLI_COLORS,
|
|
11
|
-
DEFAULT_PUBLIC_SOURCE_NAME,
|
|
12
|
-
EJECT_SOURCE,
|
|
13
|
-
formatSourceDisplayName
|
|
14
|
-
} from "./chunk-MHAQWMNJ.js";
|
|
15
|
-
|
|
16
|
-
// src/cli/components/common/summary-panel.tsx
|
|
17
|
-
import { Box, Text, renderToString } from "ink";
|
|
18
|
-
import "react";
|
|
19
|
-
import { unique } from "remeda";
|
|
20
|
-
|
|
21
|
-
// src/cli/components/hooks/use-panel-scroll.ts
|
|
22
|
-
import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
|
|
23
|
-
import { measureElement as measureElement2, useInput } from "ink";
|
|
24
|
-
|
|
25
|
-
// src/cli/components/hooks/use-measured-height.ts
|
|
26
|
-
import { useRef, useState, useEffect } from "react";
|
|
27
|
-
import { measureElement, useStdout } from "ink";
|
|
28
|
-
function useMeasuredHeight() {
|
|
29
|
-
const ref = useRef(null);
|
|
30
|
-
const [measuredHeight, setMeasuredHeight] = useState(0);
|
|
31
|
-
const { stdout } = useStdout();
|
|
32
|
-
const measure = () => {
|
|
33
|
-
if (!ref.current) return;
|
|
34
|
-
const { height } = measureElement(ref.current);
|
|
35
|
-
setMeasuredHeight((prev) => prev !== height ? height : prev);
|
|
36
|
-
};
|
|
37
|
-
useEffect(() => {
|
|
38
|
-
measure();
|
|
39
|
-
});
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
const RETRY_DELAYS_MS = [0, 16, 50];
|
|
42
|
-
const timers = [];
|
|
43
|
-
for (const delay of RETRY_DELAYS_MS) {
|
|
44
|
-
timers.push(setTimeout(measure, delay));
|
|
45
|
-
}
|
|
46
|
-
return () => {
|
|
47
|
-
for (const timer of timers) {
|
|
48
|
-
clearTimeout(timer);
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
}, []);
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
stdout.on("resize", measure);
|
|
54
|
-
return () => {
|
|
55
|
-
stdout.off("resize", measure);
|
|
56
|
-
};
|
|
57
|
-
}, [stdout]);
|
|
58
|
-
return { ref, measuredHeight };
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// src/cli/components/hooks/use-panel-scroll.ts
|
|
62
|
-
function usePanelScroll() {
|
|
63
|
-
const { ref: viewportRef, measuredHeight: viewportHeight } = useMeasuredHeight();
|
|
64
|
-
const contentRef = useRef2(null);
|
|
65
|
-
const [contentHeight, setContentHeight] = useState2(0);
|
|
66
|
-
const [scrollOffset, setScrollOffset] = useState2(0);
|
|
67
|
-
useEffect2(() => {
|
|
68
|
-
if (!contentRef.current) return;
|
|
69
|
-
const { height } = measureElement2(contentRef.current);
|
|
70
|
-
setContentHeight((prev) => Math.max(prev, height));
|
|
71
|
-
});
|
|
72
|
-
const maxScroll = Math.max(0, contentHeight - viewportHeight);
|
|
73
|
-
const hiddenBelow = Math.max(0, maxScroll - scrollOffset);
|
|
74
|
-
useInput((_input, key) => {
|
|
75
|
-
if (key.upArrow) setScrollOffset((prev) => Math.max(0, prev - 1));
|
|
76
|
-
if (key.downArrow) setScrollOffset((prev) => Math.min(maxScroll, prev + 1));
|
|
77
|
-
});
|
|
78
|
-
return {
|
|
79
|
-
viewportRef,
|
|
80
|
-
contentRef,
|
|
81
|
-
contentMarginTop: scrollOffset > 0 ? -scrollOffset : 0,
|
|
82
|
-
hiddenAbove: scrollOffset,
|
|
83
|
-
hiddenBelow
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// src/cli/components/hooks/use-terminal-dimensions.ts
|
|
88
|
-
import { useState as useState3, useEffect as useEffect3 } from "react";
|
|
89
|
-
import { useStdout as useStdout2 } from "ink";
|
|
90
|
-
var DEFAULT_COLUMNS = 80;
|
|
91
|
-
var DEFAULT_ROWS = 24;
|
|
92
|
-
function dimensionsOf(stdout) {
|
|
93
|
-
return {
|
|
94
|
-
columns: stdout.columns || DEFAULT_COLUMNS,
|
|
95
|
-
rows: stdout.rows || DEFAULT_ROWS
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
function useTerminalDimensions() {
|
|
99
|
-
const { stdout } = useStdout2();
|
|
100
|
-
const [dimensions, setDimensions] = useState3(() => dimensionsOf(stdout));
|
|
101
|
-
useEffect3(() => {
|
|
102
|
-
const handleResize = () => {
|
|
103
|
-
setDimensions(dimensionsOf(stdout));
|
|
104
|
-
};
|
|
105
|
-
stdout.on("resize", handleResize);
|
|
106
|
-
return () => {
|
|
107
|
-
stdout.off("resize", handleResize);
|
|
108
|
-
};
|
|
109
|
-
}, [stdout]);
|
|
110
|
-
return dimensions;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// src/cli/components/common/summary-panel.tsx
|
|
114
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
115
|
-
function skillsTheHeaderNames({
|
|
116
|
-
skillConfigs,
|
|
117
|
-
installedSkillConfigs
|
|
118
|
-
}) {
|
|
119
|
-
return skillConfigs.length > 0 ? skillConfigs : installedSkillConfigs ?? [];
|
|
120
|
-
}
|
|
121
|
-
function formatSkillMarketplaces(skillConfigs) {
|
|
122
|
-
if (skillConfigs.length === 0) return formatSourceDisplayName(DEFAULT_PUBLIC_SOURCE_NAME);
|
|
123
|
-
const marketplaceNames = unique(
|
|
124
|
-
skillConfigs.map((config) => config.origin).filter((origin) => origin !== EJECT_SOURCE)
|
|
125
|
-
);
|
|
126
|
-
if (marketplaceNames.length === 0) return ALL_SKILLS_EJECTED_LABEL;
|
|
127
|
-
return marketplaceNames.map((name) => formatSourceDisplayName(name)).sort().join(" \xB7 ");
|
|
128
|
-
}
|
|
129
|
-
var PanelHeader = ({ sourceNames, stackName }) => /* @__PURE__ */ jsxs(
|
|
130
|
-
Box,
|
|
131
|
-
{
|
|
132
|
-
flexDirection: "column",
|
|
133
|
-
flexShrink: 0,
|
|
134
|
-
borderStyle: "single",
|
|
135
|
-
borderBottom: true,
|
|
136
|
-
borderTop: false,
|
|
137
|
-
borderLeft: false,
|
|
138
|
-
borderRight: false,
|
|
139
|
-
borderColor: CLI_COLORS.NEUTRAL,
|
|
140
|
-
borderBottomDimColor: true,
|
|
141
|
-
paddingBottom: 1,
|
|
142
|
-
marginBottom: 1,
|
|
143
|
-
children: [
|
|
144
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", columnGap: 1, children: [
|
|
145
|
-
/* @__PURE__ */ jsx(Text, { color: CLI_COLORS.WARNING, bold: true, children: "Marketplace" }),
|
|
146
|
-
/* @__PURE__ */ jsx(Text, { color: CLI_COLORS.NEUTRAL, children: sourceNames })
|
|
147
|
-
] }),
|
|
148
|
-
/* @__PURE__ */ jsxs(Box, { flexDirection: "row", columnGap: 1, children: [
|
|
149
|
-
/* @__PURE__ */ jsx(Text, { color: CLI_COLORS.WARNING, bold: true, children: "Stack" }),
|
|
150
|
-
/* @__PURE__ */ jsx(Text, { color: CLI_COLORS.NEUTRAL, children: stackName ?? "none" })
|
|
151
|
-
] })
|
|
152
|
-
]
|
|
153
|
-
}
|
|
154
|
-
);
|
|
155
|
-
var SummaryPanel = ({ stackName, ...summary }) => {
|
|
156
|
-
const { viewportRef, contentRef, contentMarginTop, hiddenAbove, hiddenBelow } = usePanelScroll();
|
|
157
|
-
const sourceNames = formatSkillMarketplaces(skillsTheHeaderNames(summary));
|
|
158
|
-
return /* @__PURE__ */ jsxs(
|
|
159
|
-
Box,
|
|
160
|
-
{
|
|
161
|
-
flexDirection: "column",
|
|
162
|
-
flexGrow: 1,
|
|
163
|
-
flexBasis: 0,
|
|
164
|
-
borderStyle: "single",
|
|
165
|
-
borderColor: CLI_COLORS.NEUTRAL,
|
|
166
|
-
paddingX: 2,
|
|
167
|
-
children: [
|
|
168
|
-
/* @__PURE__ */ jsx(Box, { ref: viewportRef, flexDirection: "column", flexGrow: 1, flexBasis: 0, overflow: "hidden", children: /* @__PURE__ */ jsxs(Box, { ref: contentRef, flexDirection: "column", flexShrink: 0, marginTop: contentMarginTop, children: [
|
|
169
|
-
/* @__PURE__ */ jsx(PanelHeader, { sourceNames, stackName }),
|
|
170
|
-
/* @__PURE__ */ jsx(Box, { width: "100%", children: /* @__PURE__ */ jsx(SkillAgentSummary, { ...summary }) })
|
|
171
|
-
] }) }),
|
|
172
|
-
/* @__PURE__ */ jsx(ScrollAffordance, { hiddenAbove, hiddenBelow })
|
|
173
|
-
]
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
};
|
|
177
|
-
function summaryPanelText(props, columns = dimensionsOf(process.stdout).columns) {
|
|
178
|
-
return renderToString(/* @__PURE__ */ jsx(SummaryPanel, { ...props }), { columns });
|
|
179
|
-
}
|
|
180
|
-
function summaryPanelBlock(panel, linesUnder, statements) {
|
|
181
|
-
return [
|
|
182
|
-
summaryPanelText(panel),
|
|
183
|
-
...linesUnder,
|
|
184
|
-
...statements.flatMap((statement) => ["", statement]),
|
|
185
|
-
""
|
|
186
|
-
];
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
export {
|
|
190
|
-
useTerminalDimensions,
|
|
191
|
-
SummaryPanel,
|
|
192
|
-
summaryPanelText,
|
|
193
|
-
summaryPanelBlock
|
|
194
|
-
};
|
|
195
|
-
//# sourceMappingURL=chunk-Q6WRR4BN.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli/components/common/summary-panel.tsx","../src/cli/components/hooks/use-panel-scroll.ts","../src/cli/components/hooks/use-measured-height.ts","../src/cli/components/hooks/use-terminal-dimensions.ts"],"sourcesContent":["import { Box, Text, renderToString } from \"ink\";\nimport React from \"react\";\nimport { unique } from \"remeda\";\nimport {\n ALL_SKILLS_EJECTED_LABEL,\n CLI_COLORS,\n DEFAULT_PUBLIC_SOURCE_NAME,\n EJECT_SOURCE,\n formatSourceDisplayName,\n} from \"../../consts.js\";\nimport type { SkillConfig } from \"../../types/config.js\";\nimport { usePanelScroll } from \"../hooks/use-panel-scroll.js\";\nimport { dimensionsOf } from \"../hooks/use-terminal-dimensions.js\";\nimport { ScrollAffordance } from \"./scroll-affordance.js\";\nimport { SkillAgentSummary, type SkillAgentSummaryProps } from \"./skill-agent-summary.js\";\n\nexport type SummaryPanelProps = SkillAgentSummaryProps & {\n /** `undefined` when the configuration was built from no stack. */\n stackName: string | undefined;\n};\n\n/**\n * The skills the panel leaves in place; leaving none, as an uninstall does, those it removes. The\n * default marketplace is only for a panel with no skill either way.\n */\nfunction skillsTheHeaderNames({\n skillConfigs,\n installedSkillConfigs,\n}: SkillAgentSummaryProps): SkillConfig[] {\n return skillConfigs.length > 0 ? skillConfigs : (installedSkillConfigs ?? []);\n}\n\n/**\n * No skills shows the default marketplace; all-ejected names none. Tombstoned entries count: the\n * summary below renders them as rows.\n */\nfunction formatSkillMarketplaces(skillConfigs: SkillConfig[]): string {\n if (skillConfigs.length === 0) return formatSourceDisplayName(DEFAULT_PUBLIC_SOURCE_NAME);\n\n const marketplaceNames = unique(\n skillConfigs.map((config) => config.origin).filter((origin) => origin !== EJECT_SOURCE),\n );\n if (marketplaceNames.length === 0) return ALL_SKILLS_EJECTED_LABEL;\n\n return marketplaceNames\n .map((name) => formatSourceDisplayName(name))\n .sort()\n .join(\" · \");\n}\n\ntype PanelHeaderProps = {\n sourceNames: string;\n stackName: string | undefined;\n};\n\n/** `flexShrink={0}`: squeezed by Yoga on a short terminal, its two rows overprint. */\nconst PanelHeader: React.FC<PanelHeaderProps> = ({ sourceNames, stackName }) => (\n <Box\n flexDirection=\"column\"\n flexShrink={0}\n borderStyle=\"single\"\n borderBottom={true}\n borderTop={false}\n borderLeft={false}\n borderRight={false}\n borderColor={CLI_COLORS.NEUTRAL}\n borderBottomDimColor\n paddingBottom={1}\n marginBottom={1}\n >\n <Box flexDirection=\"row\" columnGap={1}>\n <Text color={CLI_COLORS.WARNING} bold>\n Marketplace\n </Text>\n <Text color={CLI_COLORS.NEUTRAL}>{sourceNames}</Text>\n </Box>\n <Box flexDirection=\"row\" columnGap={1}>\n <Text color={CLI_COLORS.WARNING} bold>\n Stack\n </Text>\n <Text color={CLI_COLORS.NEUTRAL}>{stackName ?? \"none\"}</Text>\n </Box>\n </Box>\n);\n\n/** Horizontal padding only: unshrinkable vertical padding starves the viewport on a short terminal. */\nexport const SummaryPanel: React.FC<SummaryPanelProps> = ({ stackName, ...summary }) => {\n const { viewportRef, contentRef, contentMarginTop, hiddenAbove, hiddenBelow } = usePanelScroll();\n\n const sourceNames = formatSkillMarketplaces(skillsTheHeaderNames(summary));\n\n return (\n <Box\n flexDirection=\"column\"\n flexGrow={1}\n flexBasis={0}\n borderStyle=\"single\"\n borderColor={CLI_COLORS.NEUTRAL}\n paddingX={2}\n >\n <Box ref={viewportRef} flexDirection=\"column\" flexGrow={1} flexBasis={0} overflow=\"hidden\">\n <Box ref={contentRef} flexDirection=\"column\" flexShrink={0} marginTop={contentMarginTop}>\n <PanelHeader sourceNames={sourceNames} stackName={stackName} />\n\n <Box width=\"100%\">\n <SkillAgentSummary {...summary} />\n </Box>\n </Box>\n </Box>\n <ScrollAffordance hiddenAbove={hiddenAbove} hiddenBelow={hiddenBelow} />\n </Box>\n );\n};\n\n/**\n * The whole panel as text, drawn once: printed, it scrolls with the terminal like any other line,\n * and a run with no terminal prints the same thing.\n */\nexport function summaryPanelText(\n props: SummaryPanelProps,\n columns: number = dimensionsOf(process.stdout).columns,\n): string {\n return renderToString(<SummaryPanel {...props} />, { columns });\n}\n\n/**\n * What a question shows, or where none is asked, what prints in its place: the panel, the lines\n * under it marking what it cannot show, then each statement after a blank line, and a blank line\n * before what follows.\n */\nexport function summaryPanelBlock(\n panel: SummaryPanelProps,\n linesUnder: readonly string[],\n statements: readonly string[],\n): string[] {\n return [\n summaryPanelText(panel),\n ...linesUnder,\n ...statements.flatMap((statement) => [\"\", statement]),\n \"\",\n ];\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { Ref, RefObject } from \"react\";\nimport { type DOMElement, measureElement, useInput } from \"ink\";\nimport { useMeasuredHeight } from \"./use-measured-height.js\";\n\nexport type UsePanelScrollResult = {\n /** The `overflow=\"hidden\"` box. */\n viewportRef: Ref<DOMElement>;\n contentRef: RefObject<DOMElement | null>;\n contentMarginTop: number;\n hiddenAbove: number;\n hiddenBelow: number;\n};\n\n/** `↑`/`↓` line scrolling for one clipped viewport; hosts add their own `useInput` for other keys. */\nexport function usePanelScroll(): UsePanelScrollResult {\n const { ref: viewportRef, measuredHeight: viewportHeight } = useMeasuredHeight();\n const contentRef = useRef<DOMElement>(null);\n const [contentHeight, setContentHeight] = useState(0);\n const [scrollOffset, setScrollOffset] = useState(0);\n\n // eslint-disable-next-line react-hooks/exhaustive-deps -- re-measures every render; layout changes are invisible to React\n useEffect(() => {\n if (!contentRef.current) return;\n const { height } = measureElement(contentRef.current);\n // Yoga under-reports inside a squeezed viewport; trusting that loops the render.\n setContentHeight((prev) => Math.max(prev, height));\n });\n\n // Not returned: gating the clip on contentHeight paints content over the border.\n const maxScroll = Math.max(0, contentHeight - viewportHeight);\n const hiddenBelow = Math.max(0, maxScroll - scrollOffset);\n\n useInput((_input, key) => {\n if (key.upArrow) setScrollOffset((prev) => Math.max(0, prev - 1));\n if (key.downArrow) setScrollOffset((prev) => Math.min(maxScroll, prev + 1));\n });\n\n return {\n viewportRef,\n contentRef,\n contentMarginTop: scrollOffset > 0 ? -scrollOffset : 0,\n hiddenAbove: scrollOffset,\n hiddenBelow,\n };\n}\n","import { useRef, useState, useEffect } from \"react\";\nimport { type DOMElement, measureElement, useStdout } from \"ink\";\n\n/** Attach to a `flexGrow={1}` Box under an ancestor of constrained height; 0 before first layout. */\nexport function useMeasuredHeight(): {\n ref: React.Ref<DOMElement>;\n measuredHeight: number;\n} {\n const ref = useRef<DOMElement>(null);\n const [measuredHeight, setMeasuredHeight] = useState(0);\n const { stdout } = useStdout();\n\n const measure = () => {\n if (!ref.current) return;\n const { height } = measureElement(ref.current);\n setMeasuredHeight((prev) => (prev !== height ? height : prev));\n };\n\n // Every render, so late-mounted refs are picked up.\n useEffect(() => {\n measure();\n });\n\n // Yoga may not have laid out yet on first render, so retry a few times.\n useEffect(() => {\n const RETRY_DELAYS_MS = [0, 16, 50];\n const timers: ReturnType<typeof setTimeout>[] = [];\n\n for (const delay of RETRY_DELAYS_MS) {\n timers.push(setTimeout(measure, delay));\n }\n\n return () => {\n for (const timer of timers) {\n clearTimeout(timer);\n }\n };\n // Mount-only: listing `measure` would re-arm the timers every render.\n }, []);\n\n useEffect(() => {\n stdout.on(\"resize\", measure);\n return () => {\n stdout.off(\"resize\", measure);\n };\n }, [stdout]);\n\n return { ref, measuredHeight };\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 columns: number;\n rows: number;\n};\n\n/** A stream that is not a terminal reports no size, so it gets the defaults. */\nexport function dimensionsOf(stdout: NodeJS.WriteStream): TerminalDimensions {\n return {\n columns: stdout.columns || DEFAULT_COLUMNS,\n rows: stdout.rows || DEFAULT_ROWS,\n };\n}\n\nexport function useTerminalDimensions(): TerminalDimensions {\n const { stdout } = useStdout();\n\n const [dimensions, setDimensions] = useState<TerminalDimensions>(() => dimensionsOf(stdout));\n\n useEffect(() => {\n const handleResize = () => {\n setDimensions(dimensionsOf(stdout));\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":["useEffect","useRef","useState","measureElement","useRef","useState","useEffect","measureElement","useState","useEffect","useStdout"]}
|