agents-inc 0.174.0 → 0.176.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/{chunk-APWMMZOK.js → chunk-3F5LT433.js} +157 -53
  3. package/dist/chunk-3F5LT433.js.map +1 -0
  4. package/dist/chunk-5CFHP6Z5.js +109 -0
  5. package/dist/chunk-5CFHP6Z5.js.map +1 -0
  6. package/dist/{chunk-3PJZ4QNJ.js → chunk-B7AVWSK2.js} +21 -11
  7. package/dist/chunk-B7AVWSK2.js.map +1 -0
  8. package/dist/{chunk-H5E6IO2L.js → chunk-C2BSCEDN.js} +9 -11
  9. package/dist/chunk-C2BSCEDN.js.map +1 -0
  10. package/dist/{chunk-R7GKQBZJ.js → chunk-CKBWEWHZ.js} +96 -52
  11. package/dist/chunk-CKBWEWHZ.js.map +1 -0
  12. package/dist/{chunk-IXVGBUWI.js → chunk-EC3JXT23.js} +5 -5
  13. package/dist/{chunk-E45IT3HC.js → chunk-ENET4IF6.js} +998 -472
  14. package/dist/chunk-ENET4IF6.js.map +1 -0
  15. package/dist/{chunk-FQF6VHO3.js → chunk-FACDJH6O.js} +12 -105
  16. package/dist/chunk-FACDJH6O.js.map +1 -0
  17. package/dist/{chunk-TVEDNGVP.js → chunk-H6WUOW5F.js} +2 -2
  18. package/dist/{chunk-7BHDKEGK.js → chunk-JNRACLNS.js} +3 -3
  19. package/dist/{chunk-IAQFZFWD.js → chunk-JTMSFBCA.js} +231 -24
  20. package/dist/chunk-JTMSFBCA.js.map +1 -0
  21. package/dist/{chunk-EFXVYQGT.js → chunk-MQZNDK5F.js} +39 -40
  22. package/dist/chunk-MQZNDK5F.js.map +1 -0
  23. package/dist/{chunk-QCX66KBM.js → chunk-SN64WNWE.js} +3 -3
  24. package/dist/{chunk-WUSEZFER.js → chunk-U46LYYRA.js} +3 -2
  25. package/dist/{chunk-WUSEZFER.js.map → chunk-U46LYYRA.js.map} +1 -1
  26. package/dist/{chunk-6PGXTLA4.js → chunk-U672FZVC.js} +2 -2
  27. package/dist/{chunk-AIBVAYHS.js → chunk-UE4Z3YMB.js} +2 -2
  28. package/dist/chunk-UE4Z3YMB.js.map +1 -0
  29. package/dist/{chunk-REHVGFJE.js → chunk-XMQIWPIR.js} +84 -32
  30. package/dist/chunk-XMQIWPIR.js.map +1 -0
  31. package/dist/{chunk-I3WF6L43.js → chunk-XYBHH3M5.js} +2 -2
  32. package/dist/{chunk-ECPFYHDX.js → chunk-ZBI6GFJD.js} +11 -11
  33. package/dist/chunk-ZBI6GFJD.js.map +1 -0
  34. package/dist/commands/build/marketplace.js +5 -4
  35. package/dist/commands/build/marketplace.js.map +1 -1
  36. package/dist/commands/build/plugins.js +7 -6
  37. package/dist/commands/build/plugins.js.map +1 -1
  38. package/dist/commands/compile.js +20 -16
  39. package/dist/commands/compile.js.map +1 -1
  40. package/dist/commands/doctor.js +106 -87
  41. package/dist/commands/doctor.js.map +1 -1
  42. package/dist/commands/edit.js +76 -48
  43. package/dist/commands/edit.js.map +1 -1
  44. package/dist/commands/eject.js +31 -18
  45. package/dist/commands/eject.js.map +1 -1
  46. package/dist/commands/init.js +17 -17
  47. package/dist/commands/list.js +10 -9
  48. package/dist/commands/list.js.map +1 -1
  49. package/dist/commands/new/marketplace.js +5 -4
  50. package/dist/commands/new/marketplace.js.map +1 -1
  51. package/dist/commands/search.js +14 -9
  52. package/dist/commands/search.js.map +1 -1
  53. package/dist/commands/share.js +20 -22
  54. package/dist/commands/share.js.map +1 -1
  55. package/dist/commands/uninstall.js +24 -19
  56. package/dist/commands/uninstall.js.map +1 -1
  57. package/dist/commands/update.js +110 -31
  58. package/dist/commands/update.js.map +1 -1
  59. package/dist/components/common/select-list.js +2 -2
  60. package/dist/components/common/skill-agent-summary.js +4 -3
  61. package/dist/components/common/summary-panel.js +5 -4
  62. package/dist/hooks/init.js +24 -25
  63. package/dist/hooks/init.js.map +1 -1
  64. package/dist/load-agent-defs-5BSECHE6.js +14 -0
  65. package/dist/{recompile-project-agents-KYK44C24.js → recompile-project-agents-U3UGHPWG.js} +8 -8
  66. package/dist/{source-loader-G5I4RNUP.js → source-loader-E2Y5MMN5.js} +4 -4
  67. package/package.json +1 -1
  68. package/dist/chunk-3PJZ4QNJ.js.map +0 -1
  69. package/dist/chunk-AIBVAYHS.js.map +0 -1
  70. package/dist/chunk-APWMMZOK.js.map +0 -1
  71. package/dist/chunk-E45IT3HC.js.map +0 -1
  72. package/dist/chunk-ECPFYHDX.js.map +0 -1
  73. package/dist/chunk-EFXVYQGT.js.map +0 -1
  74. package/dist/chunk-FQF6VHO3.js.map +0 -1
  75. package/dist/chunk-H5E6IO2L.js.map +0 -1
  76. package/dist/chunk-IAQFZFWD.js.map +0 -1
  77. package/dist/chunk-ORO2T4K2.js +0 -96
  78. package/dist/chunk-ORO2T4K2.js.map +0 -1
  79. package/dist/chunk-R7GKQBZJ.js.map +0 -1
  80. package/dist/chunk-REHVGFJE.js.map +0 -1
  81. package/dist/load-agent-defs-5U5KAURA.js +0 -14
  82. /package/dist/{chunk-IXVGBUWI.js.map → chunk-EC3JXT23.js.map} +0 -0
  83. /package/dist/{chunk-TVEDNGVP.js.map → chunk-H6WUOW5F.js.map} +0 -0
  84. /package/dist/{chunk-7BHDKEGK.js.map → chunk-JNRACLNS.js.map} +0 -0
  85. /package/dist/{chunk-QCX66KBM.js.map → chunk-SN64WNWE.js.map} +0 -0
  86. /package/dist/{chunk-6PGXTLA4.js.map → chunk-U672FZVC.js.map} +0 -0
  87. /package/dist/{chunk-I3WF6L43.js.map → chunk-XYBHH3M5.js.map} +0 -0
  88. /package/dist/{load-agent-defs-5U5KAURA.js.map → load-agent-defs-5BSECHE6.js.map} +0 -0
  89. /package/dist/{recompile-project-agents-KYK44C24.js.map → recompile-project-agents-U3UGHPWG.js.map} +0 -0
  90. /package/dist/{source-loader-G5I4RNUP.js.map → source-loader-E2Y5MMN5.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n copy,\n ensureDir,\n directoryExists,\n fileExists,\n isSymlink,\n listDirectories,\n} from \"../utils/fs.js\";\nimport { DIRS, PROJECT_ROOT } from \"../consts.js\";\nimport {\n providerInUse,\n relativeConfigPath,\n sourceFolderInUse,\n} from \"../lib/installation/install-layout.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { resolveSource, getProjectConfigPath } from \"../lib/configuration/index.js\";\nimport {\n ensureBlankPair,\n lazyGateDeps,\n mutateGlobal,\n writeProjectPartial,\n} from \"../lib/config-gate/index.js\";\nimport { isHomeDirectory, resolveInstallPaths } from \"../lib/installation/index.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { copySkillsToLocalFlattened, type CopiedSkill } from \"../lib/skills/index.js\";\nimport { INCOMPLETE_WORK_RECOVERY, INFO_MESSAGES } from \"../utils/messages.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { bytewise, plural } from \"../utils/string.js\";\nimport type { MergedSkillsMatrix } from \"../types/index.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"templates\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nfunction isEjectType(value: string): value is EjectType {\n return (EJECT_TYPES as readonly string[]).includes(value);\n}\n\n/** Skills come from the marketplace this installation reads, so only their ejects load it. */\ntype EjectPlan =\n | { type: \"agent-partials\" | \"templates\" }\n | { type: \"skills\" | \"all\"; sourceResult: SourceLoadResult };\n\nfunction loadedSourceOf(plan: EjectPlan): SourceLoadResult | undefined {\n return \"sourceResult\" in plan ? plan.sourceResult : undefined;\n}\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills, agent partials, or templates for local customization\";\n static description =\n \"Copy agent partials, templates, or skills to your project for customization. \" +\n \"Agent partials and templates are always copied from the CLI. \" +\n \"Skills are copied from the marketplace this installation is configured to read \" +\n \"(the public one by default).\";\n\n static examples = [\n {\n description: \"Eject agent partials for customization\",\n command: \"<%= config.bin %> <%= command.id %> agent-partials\",\n },\n {\n description: \"Eject only agent templates\",\n command: \"<%= config.bin %> <%= command.id %> templates\",\n },\n {\n description: \"Eject skills to local directory\",\n command: \"<%= config.bin %> <%= command.id %> skills\",\n },\n {\n description: \"Eject everything with force overwrite\",\n command: \"<%= config.bin %> <%= command.id %> all --force\",\n },\n {\n description: \"Eject to a custom output directory\",\n command: \"<%= config.bin %> <%= command.id %> skills -o ./custom-dir\",\n },\n ];\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, templates, skills, all\",\n required: false,\n options: [...EJECT_TYPES],\n }),\n };\n\n static flags = {\n provider: providerFlag(),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n // No default: each eject type has its own destination and this replaces all three.\n description:\n \"Write everything into this directory instead of each eject type's own destination\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n // Before the layout settle: this decides which installation that refusal is about.\n await refuseAnAmbiguousInstallation(\n projectDir,\n \"eject\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n\n // Before anything is copied, so a refusal never follows files already written.\n await this.ensureConfigReadable(projectDir);\n const ejectType = this.validateEjectType(args.type);\n const outputBase = await this.resolveOutputBase(flags, projectDir);\n\n this.printHeader(\n await this.resolveBrandingName(projectDir),\n flags.output ? outputBase : undefined,\n );\n\n const plan = await this.planEject(ejectType, projectDir);\n await this.executeEject(plan, outputBase, flags, projectDir);\n await this.ensureConfig(projectDir, loadedSourceOf(plan));\n\n this.reportEnding();\n }\n\n /** Withholds `Eject complete!` when part of the eject did not land. */\n private reportEnding(): void {\n this.log(\"\");\n if (!this.hasIncompleteWork) this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n\n this.exitIfWorkIncomplete();\n }\n\n private validateEjectType(typeArg: string | undefined): EjectType {\n if (!typeArg) {\n this.error(\"Please specify what to eject: agent-partials, templates, skills, or all\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!isEjectType(typeArg)) {\n this.error(`Unknown eject type: ${typeArg}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return typeArg;\n }\n\n private async resolveOutputBase(\n flags: { output: string | undefined },\n projectDir: string,\n ): Promise<string> {\n if (!flags.output) return sourceFolderInUse(projectDir, providerInUse(projectDir)).dir;\n\n const outputBase = path.resolve(projectDir, expandHome(flags.output));\n await this.refuseUnwritableOutput(outputBase);\n return outputBase;\n }\n\n private async refuseUnwritableOutput(outputBase: string): Promise<void> {\n // First, as the checks below follow a link, and so would every write.\n if (await isSymlink(outputBase)) {\n this.error(`Output path is a link: ${outputBase}. Name the folder it points to instead.`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n // `fileExists` is true of a directory too; an existing directory is written into, and each\n // kind then skips what it would write there already unless --force.\n const namesAFile = (await fileExists(outputBase)) && !(await directoryExists(outputBase));\n if (namesAFile) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n }\n\n private printHeader(brandingName: string, outputBase?: string): void {\n this.log(\"\");\n this.log(`${brandingName} Eject`);\n this.log(\"\");\n\n if (outputBase) {\n this.log(`Output directory: ${outputBase}`);\n }\n }\n\n private async planEject(type: EjectType, projectDir: string): Promise<EjectPlan> {\n if (type === \"agent-partials\" || type === \"templates\") return { type };\n\n const { sourceResult } = await loadSource({ projectDir });\n return { type, sourceResult };\n }\n\n private async executeEject(\n plan: EjectPlan,\n outputBase: string,\n flags: { force: boolean; output: string | undefined },\n projectDir: string,\n ): Promise<void> {\n const directOutput = !!flags.output;\n\n switch (plan.type) {\n case \"agent-partials\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n break;\n case \"templates\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, true);\n break;\n case \"skills\":\n await this.handleSkills(\n skillsDestination(projectDir, directOutput, outputBase),\n flags.force,\n plan.sourceResult,\n );\n break;\n case \"all\": {\n // The partials carry the templates as one unit, so they arrive once and obey --force.\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n await this.handleSkills(\n skillsDestination(projectDir, directOutput, outputBase),\n flags.force,\n plan.sourceResult,\n );\n break;\n }\n default: {\n const _exhaustive: never = plan;\n return _exhaustive;\n }\n }\n }\n\n /**\n * Writes a minimal config so `compile` works afterwards. A refusal is reported as incomplete\n * work rather than thrown, because the ejection has already landed.\n */\n private async ensureConfig(\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n // Named before the write, which may create the provider folder.\n const configTsRel = relativeConfigPath(projectDir, providerInUse(projectDir));\n\n try {\n const configResult = await ensureMinimalConfig({\n projectDir,\n ...(sourceResult !== undefined && { sourceResult }),\n });\n if (configResult.created) {\n this.logSuccess(`Created ${configTsRel}`);\n }\n } catch (error) {\n this.reportIncompleteWork(\n `Could not create ${configTsRel}: ${getErrorMessage(error)}`,\n INCOMPLETE_WORK_RECOVERY.INSPECT_INSTALLATION,\n );\n }\n }\n\n private async handleAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput: boolean,\n templatesOnly: boolean,\n ): Promise<void> {\n const result = await ejectAgentPartials({\n outputBase,\n force,\n directOutput,\n templatesOnly,\n });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n if (result.skippedSubAgents.length > 0) {\n this.warn(subAgentsAlreadyThere(result.destDir, result.skippedSubAgents));\n }\n\n if (result.templatesSkipped) {\n this.warn(\n \"Agent templates already exist — skipping templates, only ejecting agent partials.\",\n );\n }\n\n this.logSuccess(\n `${templatesOnly ? \"Agent templates\" : \"Agent partials\"} ejected to ${result.destDir}`,\n );\n this.log(\n templatesOnly\n ? \"You can now customize agent templates locally.\"\n : INFO_MESSAGES.AGENT_PARTIALS_CUSTOMIZABLE,\n );\n }\n\n private async handleSkills(\n destinationDir: string,\n force: boolean,\n sourceResult: SourceLoadResult,\n ): Promise<void> {\n const result = await ejectSkills({ destinationDir, force, sourceResult, matrix });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n if (result.skippedSkillCount > 0) {\n this.warn(skillsAlreadyThere(destinationDir, result.skippedSkillCount));\n }\n\n this.logSuccess(\n `${plural(result.copiedSkills.length, \"skill\")} ejected to ${destinationDir} from ${result.sourceLabel}`,\n );\n this.log(\"You can now customize skill content locally.\");\n }\n}\n\nfunction expandHome(outputPath: string): string {\n return outputPath.startsWith(\"~\") ? path.join(os.homedir(), outputPath.slice(1)) : outputPath;\n}\n\n/** Some of what an eject copies was already there: named, with the rest copied beside it. */\nfunction subAgentsAlreadyThere(destDir: string, subAgents: readonly string[]): string {\n return `Agent partials already exist at ${destDir} — skipped ${plural(subAgents.length, \"sub-agent\")}: ${subAgents.join(\", \")}. Use --force to overwrite them.`;\n}\n\n/** Counted rather than named: a re-run into a nearly full folder skips most of the marketplace. */\nfunction skillsAlreadyThere(destinationDir: string, skippedCount: number): string {\n return `Skills already exist at ${destinationDir} — skipped ${plural(skippedCount, \"skill\")}. Use --force to overwrite them.`;\n}\n\n/** Those of `names` already at `dir`, file or folder: what an eject without --force leaves. */\nasync function alreadyIn<Name extends string>(\n dir: string,\n names: readonly Name[],\n): Promise<Name[]> {\n const checked = await Promise.all(\n names.map(async (name) => ({ name, there: await fileExists(path.join(dir, name)) })),\n );\n return checked.filter(({ there }) => there).map(({ name }) => name);\n}\n\ntype EjectAgentPartialsOptions = {\n outputBase: string;\n force: boolean;\n directOutput?: boolean;\n templatesOnly?: boolean;\n};\n\ntype EjectAgentPartialsResult =\n | {\n skipped: true;\n skipReason: string;\n }\n | {\n skipped: false;\n destDir: string;\n /** The sub-agents left as they were, by name, bytewise-sorted. */\n skippedSubAgents: string[];\n templatesSkipped: boolean;\n };\n\nfunction resolveEjectDestDir(\n outputBase: string,\n directOutput: boolean,\n templatesOnly: boolean,\n): string {\n if (directOutput) return outputBase;\n const agentsDir = path.join(outputBase, path.basename(DIRS.agents));\n return templatesOnly ? path.join(agentsDir, path.basename(DIRS.templates)) : agentsDir;\n}\n\nasync function ejectAgentPartials(\n options: EjectAgentPartialsOptions,\n): Promise<EjectAgentPartialsResult> {\n const { outputBase, force, directOutput = false, templatesOnly = false } = options;\n const destDir = resolveEjectDestDir(outputBase, directOutput, templatesOnly);\n\n return templatesOnly ? ejectTemplates(destDir, force) : ejectSubAgentPartials(destDir, force);\n}\n\n/** Whole or not at all: a templates folder already there is kept unless --force. */\nasync function ejectTemplates(destDir: string, force: boolean): Promise<EjectAgentPartialsResult> {\n const sourceDir = path.join(PROJECT_ROOT, DIRS.templates);\n\n if (!(await directoryExists(sourceDir))) {\n return { skipped: true, skipReason: \"No agent templates found in CLI.\" };\n }\n\n if ((await directoryExists(destDir)) && !force) {\n return {\n skipped: true,\n skipReason: `Agent templates already exist at ${destDir}. Use --force to overwrite.`,\n };\n }\n\n await ensureDir(destDir);\n await copy(sourceDir, destDir);\n return { skipped: false, destDir, skippedSubAgents: [], templatesSkipped: false };\n}\n\n/** Unit by unit: one already there is kept unless --force, and the rest are copied beside it. */\nasync function ejectSubAgentPartials(\n destDir: string,\n force: boolean,\n): Promise<EjectAgentPartialsResult> {\n const sourceDir = path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n return { skipped: true, skipReason: \"No agent partials found in CLI.\" };\n }\n\n const units = await partialUnitsIn(sourceDir);\n const present = force ? [] : await alreadyIn(destDir, units);\n const absent = units.filter((unit) => !present.includes(unit));\n\n if (absent.length === 0) {\n return {\n skipped: true,\n skipReason: `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n };\n }\n\n await copyUnits(absent, sourceDir, destDir);\n\n return {\n skipped: false,\n destDir,\n skippedSubAgents: subAgentNames(present),\n templatesSkipped: present.some(isTemplatesUnit),\n };\n}\n\nconst TEMPLATES_UNIT = path.basename(DIRS.templates);\n\nfunction isTemplatesUnit(unit: string): boolean {\n return unit === TEMPLATES_UNIT;\n}\n\n/**\n * What a re-eject keeps or copies whole: each sub-agent's directory, as `<category>/<agent>`, and\n * the templates. A category folder is not one, so a file of the user's in it is written beside.\n */\nasync function partialUnitsIn(agentsSourceDir: string): Promise<string[]> {\n const entries = await listDirectories(agentsSourceDir);\n const categories = entries.filter((entry) => !isTemplatesUnit(entry));\n const subAgentDirs = await Promise.all(\n categories.map((category) => subAgentDirsOf(agentsSourceDir, category)),\n );\n return [...entries.filter(isTemplatesUnit), ...subAgentDirs.flat()];\n}\n\nasync function subAgentDirsOf(agentsSourceDir: string, category: string): Promise<string[]> {\n const agents = await listDirectories(path.join(agentsSourceDir, category));\n return agents.map((agent) => path.join(category, agent));\n}\n\n/** As the skipped-list warning names them: by directory name, bytewise-sorted. */\nfunction subAgentNames(units: readonly string[]): string[] {\n return units\n .filter((unit) => !isTemplatesUnit(unit))\n .map((unit) => path.basename(unit))\n .sort(bytewise);\n}\n\n/** `copy` makes the folders above each unit. */\nasync function copyUnits(\n units: readonly string[],\n sourceDir: string,\n destDir: string,\n): Promise<void> {\n for (const unit of units) {\n await copy(path.join(sourceDir, unit), path.join(destDir, unit));\n }\n}\n\nfunction skillsDestination(projectDir: string, directOutput: boolean, outputBase: string): string {\n return directOutput ? outputBase : installedSkillsDir(projectDir);\n}\n\ntype EjectSkillsOptions = {\n destinationDir: string;\n force: boolean;\n sourceResult: SourceLoadResult;\n matrix: MergedSkillsMatrix;\n};\n\ntype EjectSkillsResult =\n | {\n skipped: true;\n skipReason: string;\n }\n | {\n skipped: false;\n copiedSkills: CopiedSkill[];\n /** How many skills were left as they were. */\n skippedSkillCount: number;\n sourceLabel: string;\n };\n\n/**\n * Only the loaded marketplace's own non-local skills: others' skills are not on disk here. One\n * already in the destination is skipped first, as the local copy may be the one there.\n */\nasync function ejectSkills(options: EjectSkillsOptions): Promise<EjectSkillsResult> {\n const { destinationDir, force, sourceResult, matrix } = options;\n\n const marketplaceSkillIds = [...sourceResult.marketplaceSkillIds];\n const alreadyThere = force ? [] : await alreadyIn(destinationDir, marketplaceSkillIds);\n const notThere = marketplaceSkillIds.filter((skillId) => !alreadyThere.includes(skillId));\n const skillIds = notThere.filter((skillId) => !matrix.skills[skillId]?.local);\n\n if (skillIds.length === 0 && alreadyThere.length > 0) {\n return {\n skipped: true,\n skipReason: `Skills already exist at ${destinationDir}. Use --force to overwrite.`,\n };\n }\n\n if (skillIds.length === 0) {\n return { skipped: true, skipReason: \"No skills found in the marketplace to eject.\" };\n }\n\n await ensureDir(destinationDir);\n\n const copiedSkills = await copySkillsToLocalFlattened(skillIds, destinationDir, sourceResult);\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n return {\n skipped: false,\n copiedSkills,\n skippedSkillCount: alreadyThere.length,\n sourceLabel,\n };\n}\n\n/** Where the host of the installation `projectDir` roots reads skills. */\nfunction installedSkillsDir(projectDir: string): string {\n const scope = isHomeDirectory(projectDir) ? \"global\" : \"project\";\n return resolveInstallPaths(projectDir, scope).skillsDir;\n}\n\ntype EnsureMinimalConfigOptions = {\n projectDir: string;\n sourceResult?: SourceLoadResult;\n};\n\ntype EnsureMinimalConfigResult = {\n configPath: string;\n created: boolean;\n};\n\nasync function ensureMinimalConfig(\n options: EnsureMinimalConfigOptions,\n): Promise<EnsureMinimalConfigResult> {\n const { projectDir, sourceResult } = options;\n\n const provider = providerInUse(projectDir);\n const tsConfigPath = getProjectConfigPath(projectDir, provider);\n\n if (await fileExists(tsConfigPath)) {\n return { configPath: tsConfigPath, created: false };\n }\n\n // ABORT on an unreadable global config: the invented file would record a marketplace from nowhere.\n const resolvedConfig =\n sourceResult?.sourceConfig ?? (await resolveSource({ caller: \"stored\", projectDir }));\n const source = resolvedConfig.source || undefined;\n\n // At home the invented config is the global manifest, which needs its config-types sibling.\n if (isHomeDirectory(projectDir)) {\n await ensureBlankPair(provider);\n if (source) await recordSourceInGlobal(projectDir, source);\n return { configPath: tsConfigPath, created: true };\n }\n\n await writeProjectPartial(\n projectDir,\n {\n skills: [],\n agents: [],\n ...(source ? { marketplace: source } : {}),\n ...(resolvedConfig.marketplace ? { marketplaceName: resolvedConfig.marketplace } : {}),\n },\n { fallbackName: path.basename(projectDir) },\n );\n\n return { configPath: tsConfigPath, created: true };\n}\n\n/** At home the config is the global manifest projects inline from, so it goes through the gate. */\nasync function recordSourceInGlobal(projectDir: string, source: string): Promise<void> {\n await mutateGlobal(\n { kind: \"set-source\", source, fallbackName: path.basename(projectDir) },\n lazyGateDeps(projectDir),\n );\n}\n"],"mappings":"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","names":["matrix"]}
1
+ {"version":3,"sources":["../../src/cli/commands/eject.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport path from \"path\";\nimport os from \"os\";\nimport { BaseCommand } from \"../base-command.js\";\nimport {\n copy,\n ensureDir,\n directoryExists,\n fileExists,\n isSymlink,\n listDirectories,\n} from \"../utils/fs.js\";\nimport { DIRS, PROJECT_ROOT } from \"../consts.js\";\nimport {\n providerInUse,\n relativeConfigPath,\n sourceFolderInUse,\n} from \"../lib/installation/install-layout.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { type SourceLoadResult } from \"../lib/loading/index.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { resolveSource, getProjectConfigPath } from \"../lib/configuration/index.js\";\nimport {\n ensureBlankPair,\n lazyGateDeps,\n mutateGlobal,\n writeProjectPartial,\n} from \"../lib/config-gate/index.js\";\nimport { isHomeDirectory, resolveInstallPaths } from \"../lib/installation/index.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { copyMarketplaceSkillsToLocalFlattened, type CopiedSkill } from \"../lib/skills/index.js\";\nimport { INCOMPLETE_WORK_RECOVERY, INFO_MESSAGES } from \"../utils/messages.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { bytewise, plural } from \"../utils/string.js\";\nimport type { MergedSkillsMatrix, ResolvedSkill } from \"../types/index.js\";\n\nconst EJECT_TYPES = [\"agent-partials\", \"templates\", \"skills\", \"all\"] as const;\ntype EjectType = (typeof EJECT_TYPES)[number];\n\nfunction isEjectType(value: string): value is EjectType {\n return (EJECT_TYPES as readonly string[]).includes(value);\n}\n\n/** Skills come from the marketplace this installation reads, so only their ejects load it. */\ntype EjectPlan =\n | { type: \"agent-partials\" | \"templates\" }\n | { type: \"skills\" | \"all\"; sourceResult: SourceLoadResult };\n\nfunction loadedSourceOf(plan: EjectPlan): SourceLoadResult | undefined {\n return \"sourceResult\" in plan ? plan.sourceResult : undefined;\n}\n\nexport default class Eject extends BaseCommand {\n static summary = \"Eject skills, agent partials, or templates for local customization\";\n static description =\n \"Copy agent partials, templates, or skills to your project for customization. \" +\n \"Agent partials and templates are always copied from the CLI. \" +\n \"Skills are copied from the marketplace this installation is configured to read \" +\n \"(the public one by default).\";\n\n static examples = [\n {\n description: \"Eject agent partials for customization\",\n command: \"<%= config.bin %> <%= command.id %> agent-partials\",\n },\n {\n description: \"Eject only agent templates\",\n command: \"<%= config.bin %> <%= command.id %> templates\",\n },\n {\n description: \"Eject skills to local directory\",\n command: \"<%= config.bin %> <%= command.id %> skills\",\n },\n {\n description: \"Eject everything with force overwrite\",\n command: \"<%= config.bin %> <%= command.id %> all --force\",\n },\n {\n description: \"Eject to a custom output directory\",\n command: \"<%= config.bin %> <%= command.id %> skills -o ./custom-dir\",\n },\n ];\n\n static args = {\n type: Args.string({\n description: \"What to eject: agent-partials, templates, skills, all\",\n required: false,\n options: [...EJECT_TYPES],\n }),\n };\n\n static flags = {\n provider: providerFlag(),\n force: Flags.boolean({\n char: \"f\",\n description: \"Overwrite existing files\",\n default: false,\n }),\n output: Flags.string({\n char: \"o\",\n // No default: each eject type has its own destination and this replaces all three.\n description:\n \"Write everything into this directory instead of each eject type's own destination\",\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Eject);\n const projectDir = process.cwd();\n\n // Before the layout settle: this decides which installation that refusal is about.\n await refuseAnAmbiguousInstallation(\n projectDir,\n \"eject\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n await this.sayWhenTheProjectsConfigDeclaresNothing(\n INFO_MESSAGES.DECLARES_NOTHING_TO_EJECT_FROM,\n );\n\n // Before anything is copied, so a refusal never follows files already written.\n await this.ensureConfigReadable(projectDir);\n const ejectType = this.validateEjectType(args.type);\n const outputBase = await this.resolveOutputBase(flags, projectDir);\n\n this.printHeader(\n await this.resolveBrandingName(projectDir),\n flags.output ? outputBase : undefined,\n );\n\n const plan = await this.planEject(ejectType, projectDir);\n await this.executeEject(plan, outputBase, flags, projectDir);\n await this.ensureConfig(projectDir, loadedSourceOf(plan));\n\n this.reportEnding();\n }\n\n /** Withholds `Eject complete!` when part of the eject did not land. */\n private reportEnding(): void {\n this.log(\"\");\n if (!this.hasIncompleteWork) this.logSuccess(\"Eject complete!\");\n this.log(\"\");\n\n this.exitIfWorkIncomplete();\n }\n\n private validateEjectType(typeArg: string | undefined): EjectType {\n if (!typeArg) {\n this.error(\"Please specify what to eject: agent-partials, templates, skills, or all\", {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n if (!isEjectType(typeArg)) {\n this.error(`Unknown eject type: ${typeArg}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n return typeArg;\n }\n\n private async resolveOutputBase(\n flags: { output: string | undefined },\n projectDir: string,\n ): Promise<string> {\n if (!flags.output) return sourceFolderInUse(projectDir, providerInUse(projectDir)).dir;\n\n const outputBase = path.resolve(projectDir, expandHome(flags.output));\n await this.refuseUnwritableOutput(outputBase);\n return outputBase;\n }\n\n private async refuseUnwritableOutput(outputBase: string): Promise<void> {\n // First, as the checks below follow a link, and so would every write.\n if (await isSymlink(outputBase)) {\n this.error(`Output path is a link: ${outputBase}. Name the folder it points to instead.`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n\n // `fileExists` is true of a directory too; an existing directory is written into, and each\n // kind then skips what it would write there already unless --force.\n const namesAFile = (await fileExists(outputBase)) && !(await directoryExists(outputBase));\n if (namesAFile) {\n this.error(`Output path exists as a file: ${outputBase}`, {\n exit: EXIT_CODES.INVALID_ARGS,\n });\n }\n }\n\n private printHeader(brandingName: string, outputBase?: string): void {\n this.log(\"\");\n this.log(`${brandingName} Eject`);\n this.log(\"\");\n\n if (outputBase) {\n this.log(`Output directory: ${outputBase}`);\n }\n }\n\n private async planEject(type: EjectType, projectDir: string): Promise<EjectPlan> {\n if (type === \"agent-partials\" || type === \"templates\") return { type };\n\n const { sourceResult } = await loadSource({ projectDir });\n return { type, sourceResult };\n }\n\n private async executeEject(\n plan: EjectPlan,\n outputBase: string,\n flags: { force: boolean; output: string | undefined },\n projectDir: string,\n ): Promise<void> {\n const directOutput = !!flags.output;\n\n switch (plan.type) {\n case \"agent-partials\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n break;\n case \"templates\":\n await this.handleAgentPartials(outputBase, flags.force, directOutput, true);\n break;\n case \"skills\":\n await this.handleSkills(\n skillsDestination(projectDir, directOutput, outputBase),\n flags.force,\n plan.sourceResult,\n );\n break;\n case \"all\": {\n // The partials carry the templates as one unit, so they arrive once and obey --force.\n await this.handleAgentPartials(outputBase, flags.force, directOutput, false);\n await this.handleSkills(\n skillsDestination(projectDir, directOutput, outputBase),\n flags.force,\n plan.sourceResult,\n );\n break;\n }\n default: {\n const _exhaustive: never = plan;\n return _exhaustive;\n }\n }\n }\n\n /**\n * Writes a minimal config where there is none. A refusal is reported as incomplete work rather\n * than thrown, because the ejection has already landed.\n */\n private async ensureConfig(\n projectDir: string,\n sourceResult: SourceLoadResult | undefined,\n ): Promise<void> {\n // Named before the write, which may create the provider folder.\n const configTsRel = relativeConfigPath(projectDir, providerInUse(projectDir));\n\n try {\n const configResult = await ensureMinimalConfig({\n projectDir,\n ...(sourceResult !== undefined && { sourceResult }),\n });\n if (configResult.created) {\n this.logSuccess(`Created ${configTsRel}`);\n }\n } catch (error) {\n this.reportIncompleteWork(\n `Could not create ${configTsRel}: ${getErrorMessage(error)}`,\n INCOMPLETE_WORK_RECOVERY.INSPECT_INSTALLATION,\n );\n }\n }\n\n private async handleAgentPartials(\n outputBase: string,\n force: boolean,\n directOutput: boolean,\n templatesOnly: boolean,\n ): Promise<void> {\n const result = await ejectAgentPartials({\n outputBase,\n force,\n directOutput,\n templatesOnly,\n });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n if (result.skippedSubAgents.length > 0) {\n this.warn(subAgentsAlreadyThere(result.destDir, result.skippedSubAgents));\n }\n\n if (result.templatesSkipped) {\n this.warn(\n \"Agent templates already exist — skipping templates, only ejecting agent partials.\",\n );\n }\n\n this.logSuccess(\n `${templatesOnly ? \"Agent templates\" : \"Agent partials\"} ejected to ${result.destDir}`,\n );\n this.log(\n templatesOnly\n ? \"You can now customize agent templates locally.\"\n : INFO_MESSAGES.AGENT_PARTIALS_CUSTOMIZABLE,\n );\n }\n\n private async handleSkills(\n destinationDir: string,\n force: boolean,\n sourceResult: SourceLoadResult,\n ): Promise<void> {\n const result = await ejectSkills({ destinationDir, force, sourceResult, matrix });\n\n if (result.skipped) {\n this.warn(result.skipReason);\n return;\n }\n\n if (result.skippedSkillCount > 0) {\n this.warn(skillsAlreadyThere(destinationDir, result.skippedSkillCount));\n }\n\n this.logSuccess(\n `${plural(result.copiedSkills.length, \"skill\")} ejected to ${destinationDir} from ${result.sourceLabel}`,\n );\n this.log(\"You can now customize skill content locally.\");\n }\n}\n\nfunction expandHome(outputPath: string): string {\n return outputPath.startsWith(\"~\") ? path.join(os.homedir(), outputPath.slice(1)) : outputPath;\n}\n\n/** Some of what an eject copies was already there: named, with the rest copied beside it. */\nfunction subAgentsAlreadyThere(destDir: string, subAgents: readonly string[]): string {\n return `Agent partials already exist at ${destDir} — skipped ${plural(subAgents.length, \"sub-agent\")}: ${subAgents.join(\", \")}. Use --force to overwrite them.`;\n}\n\n/** Counted rather than named: a re-run into a nearly full folder skips most of the marketplace. */\nfunction skillsAlreadyThere(destinationDir: string, skippedCount: number): string {\n return `Skills already exist at ${destinationDir} — skipped ${plural(skippedCount, \"skill\")}. Use --force to overwrite them.`;\n}\n\n/** Those of `names` already at `dir`, file or folder: what an eject without --force leaves. */\nasync function alreadyIn<Name extends string>(\n dir: string,\n names: readonly Name[],\n): Promise<Name[]> {\n const checked = await Promise.all(\n names.map(async (name) => ({ name, there: await fileExists(path.join(dir, name)) })),\n );\n return checked.filter(({ there }) => there).map(({ name }) => name);\n}\n\ntype EjectAgentPartialsOptions = {\n outputBase: string;\n force: boolean;\n directOutput?: boolean;\n templatesOnly?: boolean;\n};\n\ntype EjectAgentPartialsResult =\n | {\n skipped: true;\n skipReason: string;\n }\n | {\n skipped: false;\n destDir: string;\n /** The sub-agents left as they were, by name, bytewise-sorted. */\n skippedSubAgents: string[];\n templatesSkipped: boolean;\n };\n\nfunction resolveEjectDestDir(\n outputBase: string,\n directOutput: boolean,\n templatesOnly: boolean,\n): string {\n if (directOutput) return outputBase;\n const agentsDir = path.join(outputBase, path.basename(DIRS.agents));\n return templatesOnly ? path.join(agentsDir, path.basename(DIRS.templates)) : agentsDir;\n}\n\nasync function ejectAgentPartials(\n options: EjectAgentPartialsOptions,\n): Promise<EjectAgentPartialsResult> {\n const { outputBase, force, directOutput = false, templatesOnly = false } = options;\n const destDir = resolveEjectDestDir(outputBase, directOutput, templatesOnly);\n\n return templatesOnly ? ejectTemplates(destDir, force) : ejectSubAgentPartials(destDir, force);\n}\n\n/** Whole or not at all: a templates folder already there is kept unless --force. */\nasync function ejectTemplates(destDir: string, force: boolean): Promise<EjectAgentPartialsResult> {\n const sourceDir = path.join(PROJECT_ROOT, DIRS.templates);\n\n if (!(await directoryExists(sourceDir))) {\n return { skipped: true, skipReason: \"No agent templates found in CLI.\" };\n }\n\n if ((await directoryExists(destDir)) && !force) {\n return {\n skipped: true,\n skipReason: `Agent templates already exist at ${destDir}. Use --force to overwrite.`,\n };\n }\n\n await ensureDir(destDir);\n await copy(sourceDir, destDir);\n return { skipped: false, destDir, skippedSubAgents: [], templatesSkipped: false };\n}\n\n/** Unit by unit: one already there is kept unless --force, and the rest are copied beside it. */\nasync function ejectSubAgentPartials(\n destDir: string,\n force: boolean,\n): Promise<EjectAgentPartialsResult> {\n const sourceDir = path.join(PROJECT_ROOT, DIRS.agents);\n\n if (!(await directoryExists(sourceDir))) {\n return { skipped: true, skipReason: \"No agent partials found in CLI.\" };\n }\n\n const units = await partialUnitsIn(sourceDir);\n const present = force ? [] : await alreadyIn(destDir, units);\n const absent = units.filter((unit) => !present.includes(unit));\n\n if (absent.length === 0) {\n return {\n skipped: true,\n skipReason: `Agent partials already exist at ${destDir}. Use --force to overwrite.`,\n };\n }\n\n await copyUnits(absent, sourceDir, destDir);\n\n return {\n skipped: false,\n destDir,\n skippedSubAgents: subAgentNames(present),\n templatesSkipped: present.some(isTemplatesUnit),\n };\n}\n\nconst TEMPLATES_UNIT = path.basename(DIRS.templates);\n\nfunction isTemplatesUnit(unit: string): boolean {\n return unit === TEMPLATES_UNIT;\n}\n\n/**\n * What a re-eject keeps or copies whole: each sub-agent's directory, as `<category>/<agent>`, and\n * the templates. A category folder is not one, so a file of the user's in it is written beside.\n */\nasync function partialUnitsIn(agentsSourceDir: string): Promise<string[]> {\n const entries = await listDirectories(agentsSourceDir);\n const categories = entries.filter((entry) => !isTemplatesUnit(entry));\n const subAgentDirs = await Promise.all(\n categories.map((category) => subAgentDirsOf(agentsSourceDir, category)),\n );\n return [...entries.filter(isTemplatesUnit), ...subAgentDirs.flat()];\n}\n\nasync function subAgentDirsOf(agentsSourceDir: string, category: string): Promise<string[]> {\n const agents = await listDirectories(path.join(agentsSourceDir, category));\n return agents.map((agent) => path.join(category, agent));\n}\n\n/** As the skipped-list warning names them: by directory name, bytewise-sorted. */\nfunction subAgentNames(units: readonly string[]): string[] {\n return units\n .filter((unit) => !isTemplatesUnit(unit))\n .map((unit) => path.basename(unit))\n .sort(bytewise);\n}\n\n/** `copy` makes the folders above each unit. */\nasync function copyUnits(\n units: readonly string[],\n sourceDir: string,\n destDir: string,\n): Promise<void> {\n for (const unit of units) {\n await copy(path.join(sourceDir, unit), path.join(destDir, unit));\n }\n}\n\nfunction skillsDestination(projectDir: string, directOutput: boolean, outputBase: string): string {\n return directOutput ? outputBase : installedSkillsDir(projectDir);\n}\n\ntype EjectSkillsOptions = {\n destinationDir: string;\n force: boolean;\n sourceResult: SourceLoadResult;\n matrix: MergedSkillsMatrix;\n};\n\ntype EjectSkillsResult =\n | {\n skipped: true;\n skipReason: string;\n }\n | {\n skipped: false;\n copiedSkills: CopiedSkill[];\n /** How many skills were left as they were. */\n skippedSkillCount: number;\n sourceLabel: string;\n };\n\n/**\n * Only the loaded marketplace's own skills, each copied from the marketplace: others' are not on\n * disk here. One already in the destination is skipped unless --force; a local copy anywhere else\n * is the user's own and is left out either way.\n */\nasync function ejectSkills(options: EjectSkillsOptions): Promise<EjectSkillsResult> {\n const { destinationDir, force, sourceResult, matrix } = options;\n\n const marketplaceSkillIds = [...sourceResult.marketplaceSkillIds];\n const alreadyThere = force ? [] : await alreadyIn(destinationDir, marketplaceSkillIds);\n const notThere = marketplaceSkillIds.filter((skillId) => !alreadyThere.includes(skillId));\n const skillIds = notThere.filter(\n (skillId) => !isLocalCopyElsewhere(matrix.skills[skillId], destinationDir),\n );\n\n if (skillIds.length === 0 && alreadyThere.length > 0) {\n return {\n skipped: true,\n skipReason: `Skills already exist at ${destinationDir}. Use --force to overwrite.`,\n };\n }\n\n if (skillIds.length === 0) {\n return { skipped: true, skipReason: \"No skills found in the marketplace to eject.\" };\n }\n\n await ensureDir(destinationDir);\n\n const copiedSkills = await copyMarketplaceSkillsToLocalFlattened(\n skillIds,\n destinationDir,\n sourceResult,\n );\n\n const sourceLabel = sourceResult.isLocal\n ? sourceResult.sourcePath\n : sourceResult.marketplace || sourceResult.sourceConfig.source;\n\n return {\n skipped: false,\n copiedSkills,\n skippedSkillCount: alreadyThere.length,\n sourceLabel,\n };\n}\n\n/** Local, and not the copy at `<destinationDir>/<id>`, which is where an eject writes the skill. */\nfunction isLocalCopyElsewhere(skill: ResolvedSkill | undefined, destinationDir: string): boolean {\n if (!skill?.local) return false;\n if (!skill.localPath) return true;\n return path.resolve(skill.localPath) !== path.resolve(destinationDir, skill.id);\n}\n\n/** Where the host of the installation `projectDir` roots reads skills. */\nfunction installedSkillsDir(projectDir: string): string {\n const scope = isHomeDirectory(projectDir) ? \"global\" : \"project\";\n return resolveInstallPaths(projectDir, scope).skillsDir;\n}\n\ntype EnsureMinimalConfigOptions = {\n projectDir: string;\n sourceResult?: SourceLoadResult;\n};\n\ntype EnsureMinimalConfigResult = {\n configPath: string;\n created: boolean;\n};\n\nasync function ensureMinimalConfig(\n options: EnsureMinimalConfigOptions,\n): Promise<EnsureMinimalConfigResult> {\n const { projectDir, sourceResult } = options;\n\n const provider = providerInUse(projectDir);\n const tsConfigPath = getProjectConfigPath(projectDir, provider);\n\n if (await fileExists(tsConfigPath)) {\n return { configPath: tsConfigPath, created: false };\n }\n\n // ABORT on an unreadable global config: the invented file would record a marketplace from nowhere.\n const resolvedConfig =\n sourceResult?.sourceConfig ?? (await resolveSource({ caller: \"stored\", projectDir }));\n const source = resolvedConfig.source || undefined;\n\n // At home the invented config is the global manifest, which needs its config-types sibling.\n if (isHomeDirectory(projectDir)) {\n await ensureBlankPair(provider);\n if (source) await recordSourceInGlobal(projectDir, source);\n return { configPath: tsConfigPath, created: true };\n }\n\n await writeProjectPartial(\n projectDir,\n {\n skills: [],\n agents: [],\n ...(source ? { marketplace: source } : {}),\n ...(resolvedConfig.marketplace ? { marketplaceName: resolvedConfig.marketplace } : {}),\n },\n { fallbackName: path.basename(projectDir) },\n );\n\n return { configPath: tsConfigPath, created: true };\n}\n\n/** At home the config is the global manifest projects inline from, so it goes through the gate. */\nasync function recordSourceInGlobal(projectDir: string, source: string): Promise<void> {\n await mutateGlobal(\n { kind: \"set-source\", source, fallbackName: path.basename(projectDir) },\n lazyGateDeps(projectDir),\n );\n}\n"],"mappings":"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","names":["matrix"]}
@@ -4,26 +4,26 @@ import {
4
4
  Init,
5
5
  formatDashboardText,
6
6
  runDashboardFlow
7
- } from "../chunk-APWMMZOK.js";
8
- import "../chunk-I3WF6L43.js";
9
- import "../chunk-TVEDNGVP.js";
10
- import "../chunk-QCX66KBM.js";
7
+ } from "../chunk-3F5LT433.js";
8
+ import "../chunk-XYBHH3M5.js";
9
+ import "../chunk-H6WUOW5F.js";
10
+ import "../chunk-SN64WNWE.js";
11
11
  import "../chunk-OZXAJNLA.js";
12
12
  import "../chunk-P6CYS4JK.js";
13
- import "../chunk-H5E6IO2L.js";
14
- import "../chunk-6PGXTLA4.js";
15
- import "../chunk-R7GKQBZJ.js";
16
- import "../chunk-REHVGFJE.js";
17
- import "../chunk-7BHDKEGK.js";
18
- import "../chunk-IXVGBUWI.js";
19
- import "../chunk-EFXVYQGT.js";
13
+ import "../chunk-C2BSCEDN.js";
14
+ import "../chunk-U672FZVC.js";
15
+ import "../chunk-CKBWEWHZ.js";
16
+ import "../chunk-XMQIWPIR.js";
17
+ import "../chunk-JNRACLNS.js";
18
+ import "../chunk-EC3JXT23.js";
19
+ import "../chunk-MQZNDK5F.js";
20
20
  import "../chunk-KIK5EZYD.js";
21
- import "../chunk-FQF6VHO3.js";
22
- import "../chunk-ORO2T4K2.js";
23
- import "../chunk-IAQFZFWD.js";
24
- import "../chunk-E45IT3HC.js";
25
- import "../chunk-AIBVAYHS.js";
26
- import "../chunk-WUSEZFER.js";
21
+ import "../chunk-5CFHP6Z5.js";
22
+ import "../chunk-JTMSFBCA.js";
23
+ import "../chunk-FACDJH6O.js";
24
+ import "../chunk-ENET4IF6.js";
25
+ import "../chunk-UE4Z3YMB.js";
26
+ import "../chunk-U46LYYRA.js";
27
27
  import "../chunk-GHHJYNAN.js";
28
28
  export {
29
29
  Dashboard,
@@ -3,17 +3,17 @@ import {
3
3
  render
4
4
  } from "../chunk-KIK5EZYD.js";
5
5
  import {
6
- SkillAgentSummary,
7
- computeScopeDiff
8
- } from "../chunk-FQF6VHO3.js";
6
+ SkillAgentSummary
7
+ } from "../chunk-5CFHP6Z5.js";
9
8
  import {
9
+ BaseCommand,
10
10
  otherInstallationsInThisScope,
11
11
  providerFlag,
12
12
  providerNamedBy
13
- } from "../chunk-ORO2T4K2.js";
13
+ } from "../chunk-JTMSFBCA.js";
14
14
  import {
15
- BaseCommand
16
- } from "../chunk-IAQFZFWD.js";
15
+ computeScopeDiff
16
+ } from "../chunk-FACDJH6O.js";
17
17
  import {
18
18
  INSTALL_MODE_LABELS,
19
19
  chooseProviderForThisRun,
@@ -21,15 +21,15 @@ import {
21
21
  formatInstallationDisplay,
22
22
  getInstallationInfo,
23
23
  loadProjectConfig
24
- } from "../chunk-E45IT3HC.js";
24
+ } from "../chunk-ENET4IF6.js";
25
25
  import {
26
26
  getSkillEntryDisplayName
27
- } from "../chunk-AIBVAYHS.js";
27
+ } from "../chunk-UE4Z3YMB.js";
28
28
  import {
29
29
  CLI_COLORS,
30
30
  CLI_INVOKE_COMMAND,
31
31
  DEFAULT_BRANDING
32
- } from "../chunk-WUSEZFER.js";
32
+ } from "../chunk-U46LYYRA.js";
33
33
  import "../chunk-GHHJYNAN.js";
34
34
 
35
35
  // src/cli/commands/list.tsx
@@ -86,6 +86,7 @@ var List = class _List extends BaseCommand {
86
86
  }
87
87
  async run() {
88
88
  const { flags } = await this.parse(_List);
89
+ await this.sayWhenTheGlobalInstallationStandsIn(providerNamedBy(flags.provider));
89
90
  await this.sayWhichInstallationThisIs(flags.provider);
90
91
  await this.ensureConfigReadable(process.cwd());
91
92
  const installation = await detectInstallation();
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/list.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\n\nimport { Box, Text, useApp } from \"ink\";\nimport { render } from \"../components/render.js\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { CLI_INVOKE_COMMAND, CLI_COLORS, DEFAULT_BRANDING } from \"../consts.js\";\nimport { chooseProviderForThisRun } from \"../lib/installation/install-layout.js\";\nimport {\n otherInstallationsInThisScope,\n providerFlag,\n providerNamedBy,\n} from \"../lib/installation/provider-flag.js\";\nimport { getInstallationInfo, formatInstallationDisplay } from \"../lib/plugins/index.js\";\nimport {\n detectInstallation,\n INSTALL_MODE_LABELS,\n type Installation,\n} from \"../lib/installation/installation.js\";\nimport { loadProjectConfig } from \"../lib/configuration/project-config.js\";\nimport { computeScopeDiff, type SkillDiffRow } from \"../lib/configuration/scope-diff.js\";\nimport { getSkillEntryDisplayName } from \"../lib/matrix/matrix-provider.js\";\nimport { SkillAgentSummary } from \"../components/common/skill-agent-summary.js\";\nimport type { AgentScopeConfig, ProjectConfig, SkillConfig, SkillScope } from \"../types/config.js\";\n\ntype ListViewProps = {\n mode: string;\n source?: string | undefined;\n skillConfigs: SkillConfig[];\n agentConfigs: AgentScopeConfig[];\n};\n\ntype ActiveRoster = Pick<ListViewProps, \"skillConfigs\" | \"agentConfigs\">;\n\n/** The label never shrinks: a value too long for the line wraps beside it instead. */\nconst HeaderRow: React.FC<{ label: string; value: string }> = ({ label, value }) => (\n <Box flexDirection=\"row\" columnGap={1}>\n <Box flexShrink={0}>\n <Text color={CLI_COLORS.WARNING} bold>\n {label}\n </Text>\n </Box>\n <Text color={CLI_COLORS.NEUTRAL}>{value}</Text>\n </Box>\n);\n\nconst ListView: React.FC<ListViewProps> = ({ mode, source, skillConfigs, agentConfigs }) => {\n const { exit } = useApp();\n\n useEffect(() => {\n const timer = setTimeout(() => exit(), 0);\n return () => clearTimeout(timer);\n }, [exit]);\n\n return (\n <Box flexDirection=\"column\" paddingX={1} paddingY={1}>\n <Box flexDirection=\"column\" marginBottom={1}>\n <HeaderRow label=\"Mode\" value={mode} />\n {source && <HeaderRow label=\"Marketplace\" value={source} />}\n </Box>\n\n {/* Installed and current are one configuration, so every row reads unchanged. */}\n <SkillAgentSummary\n skillConfigs={skillConfigs}\n agentConfigs={agentConfigs}\n installedSkillConfigs={skillConfigs}\n installedAgentConfigs={agentConfigs}\n isInitMode={false}\n />\n </Box>\n );\n};\n\nexport default class List extends BaseCommand {\n static summary = \"Show installation information\";\n static description = `Display details about the ${DEFAULT_BRANDING.NAME} installation (local or plugin mode)`;\n static aliases = [\"ls\"];\n\n static flags = { provider: providerFlag() };\n\n static examples = [\n {\n description: \"Show current installation details\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n ];\n\n /** Names the other installation in this scope; reports rather than refuses, like `doctor`. */\n private async sayWhichInstallationThisIs(providerFlagValue: string | undefined): Promise<void> {\n const named = providerNamedBy(providerFlagValue);\n if (named !== undefined) {\n chooseProviderForThisRun(named);\n return;\n }\n\n const line = await otherInstallationsInThisScope(process.cwd());\n if (line !== null) this.log(line);\n }\n\n async run(): Promise<void> {\n const { flags } = await this.parse(List);\n await this.sayWhichInstallationThisIs(flags.provider);\n await this.ensureConfigReadable(process.cwd());\n\n const installation = await detectInstallation();\n if (!installation) return this.reportNoInstallation();\n\n const loaded = await loadProjectConfig(installation.projectDir);\n if (loaded === null) return this.printInstallationInfo([]);\n if (!process.stdin.isTTY) {\n return this.printInstallationInfo(skillLinesOf(activeRosterOf(loaded.config)));\n }\n\n await showListView(installation, loaded.config);\n }\n\n private reportNoInstallation(): void {\n this.log(\"No installation found.\");\n this.log(`Run '${CLI_INVOKE_COMMAND} init' to create one.`);\n }\n\n private async printInstallationInfo(skillLines: string[]): Promise<void> {\n const info = await getInstallationInfo();\n if (!info) return;\n\n this.log(\"\");\n this.log(formatInstallationDisplay(info, skillLines));\n this.log(\"\");\n }\n}\n\nasync function showListView(installation: Installation, config: ProjectConfig): Promise<void> {\n const { waitUntilExit, clear } = render(\n <ListView\n mode={INSTALL_MODE_LABELS[installation.mode]}\n source={config.marketplace}\n {...activeRosterOf(config)}\n />,\n );\n\n await waitUntilExit();\n clear();\n}\n\nfunction activeRosterOf(config: ProjectConfig): ActiveRoster {\n return {\n skillConfigs: config.skills.filter((skill) => !skill.excluded),\n agentConfigs: config.agents.filter((agent) => !agent.excluded),\n };\n}\n\n/** The panel's skill rows, read as it reads them: project rows first, each under the panel's name. */\nfunction skillLinesOf({ skillConfigs, agentConfigs }: ActiveRoster): string[] {\n const { projectSkillRows, globalSkillRows } = computeScopeDiff({\n currentSkills: skillConfigs,\n currentAgents: agentConfigs,\n installedSkillConfigs: skillConfigs,\n installedAgentConfigs: agentConfigs,\n isInitMode: false,\n });\n\n return [\n ...projectSkillRows.map((row) => skillLine(row, \"project\")),\n ...globalSkillRows.map((row) => skillLine(row, \"global\")),\n ];\n}\n\nfunction skillLine(row: SkillDiffRow, scope: SkillScope): string {\n return `${getSkillEntryDisplayName(row)} (${scope})`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/list.tsx"],"sourcesContent":["import React, { useEffect } from \"react\";\n\nimport { Box, Text, useApp } from \"ink\";\nimport { render } from \"../components/render.js\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { CLI_INVOKE_COMMAND, CLI_COLORS, DEFAULT_BRANDING } from \"../consts.js\";\nimport { chooseProviderForThisRun } from \"../lib/installation/install-layout.js\";\nimport {\n otherInstallationsInThisScope,\n providerFlag,\n providerNamedBy,\n} from \"../lib/installation/provider-flag.js\";\nimport { getInstallationInfo, formatInstallationDisplay } from \"../lib/plugins/index.js\";\nimport {\n detectInstallation,\n INSTALL_MODE_LABELS,\n type Installation,\n} from \"../lib/installation/installation.js\";\nimport { loadProjectConfig } from \"../lib/configuration/project-config.js\";\nimport { computeScopeDiff, type SkillDiffRow } from \"../lib/configuration/scope-diff.js\";\nimport { getSkillEntryDisplayName } from \"../lib/matrix/matrix-provider.js\";\nimport { SkillAgentSummary } from \"../components/common/skill-agent-summary.js\";\nimport type { AgentScopeConfig, ProjectConfig, SkillConfig, SkillScope } from \"../types/config.js\";\n\ntype ListViewProps = {\n mode: string;\n source?: string | undefined;\n skillConfigs: SkillConfig[];\n agentConfigs: AgentScopeConfig[];\n};\n\ntype ActiveRoster = Pick<ListViewProps, \"skillConfigs\" | \"agentConfigs\">;\n\n/** The label never shrinks: a value too long for the line wraps beside it instead. */\nconst HeaderRow: React.FC<{ label: string; value: string }> = ({ label, value }) => (\n <Box flexDirection=\"row\" columnGap={1}>\n <Box flexShrink={0}>\n <Text color={CLI_COLORS.WARNING} bold>\n {label}\n </Text>\n </Box>\n <Text color={CLI_COLORS.NEUTRAL}>{value}</Text>\n </Box>\n);\n\nconst ListView: React.FC<ListViewProps> = ({ mode, source, skillConfigs, agentConfigs }) => {\n const { exit } = useApp();\n\n useEffect(() => {\n const timer = setTimeout(() => exit(), 0);\n return () => clearTimeout(timer);\n }, [exit]);\n\n return (\n <Box flexDirection=\"column\" paddingX={1} paddingY={1}>\n <Box flexDirection=\"column\" marginBottom={1}>\n <HeaderRow label=\"Mode\" value={mode} />\n {source && <HeaderRow label=\"Marketplace\" value={source} />}\n </Box>\n\n {/* Installed and current are one configuration, so every row reads unchanged. */}\n <SkillAgentSummary\n skillConfigs={skillConfigs}\n agentConfigs={agentConfigs}\n installedSkillConfigs={skillConfigs}\n installedAgentConfigs={agentConfigs}\n isInitMode={false}\n />\n </Box>\n );\n};\n\nexport default class List extends BaseCommand {\n static summary = \"Show installation information\";\n static description = `Display details about the ${DEFAULT_BRANDING.NAME} installation (local or plugin mode)`;\n static aliases = [\"ls\"];\n\n static flags = { provider: providerFlag() };\n\n static examples = [\n {\n description: \"Show current installation details\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n ];\n\n /** Names the other installation in this scope; reports rather than refuses, like `doctor`. */\n private async sayWhichInstallationThisIs(providerFlagValue: string | undefined): Promise<void> {\n const named = providerNamedBy(providerFlagValue);\n if (named !== undefined) {\n chooseProviderForThisRun(named);\n return;\n }\n\n const line = await otherInstallationsInThisScope(process.cwd());\n if (line !== null) this.log(line);\n }\n\n async run(): Promise<void> {\n const { flags } = await this.parse(List);\n await this.sayWhenTheGlobalInstallationStandsIn(providerNamedBy(flags.provider));\n await this.sayWhichInstallationThisIs(flags.provider);\n await this.ensureConfigReadable(process.cwd());\n\n const installation = await detectInstallation();\n if (!installation) return this.reportNoInstallation();\n\n const loaded = await loadProjectConfig(installation.projectDir);\n if (loaded === null) return this.printInstallationInfo([]);\n if (!process.stdin.isTTY) {\n return this.printInstallationInfo(skillLinesOf(activeRosterOf(loaded.config)));\n }\n\n await showListView(installation, loaded.config);\n }\n\n private reportNoInstallation(): void {\n this.log(\"No installation found.\");\n this.log(`Run '${CLI_INVOKE_COMMAND} init' to create one.`);\n }\n\n private async printInstallationInfo(skillLines: string[]): Promise<void> {\n const info = await getInstallationInfo();\n if (!info) return;\n\n this.log(\"\");\n this.log(formatInstallationDisplay(info, skillLines));\n this.log(\"\");\n }\n}\n\nasync function showListView(installation: Installation, config: ProjectConfig): Promise<void> {\n const { waitUntilExit, clear } = render(\n <ListView\n mode={INSTALL_MODE_LABELS[installation.mode]}\n source={config.marketplace}\n {...activeRosterOf(config)}\n />,\n );\n\n await waitUntilExit();\n clear();\n}\n\nfunction activeRosterOf(config: ProjectConfig): ActiveRoster {\n return {\n skillConfigs: config.skills.filter((skill) => !skill.excluded),\n agentConfigs: config.agents.filter((agent) => !agent.excluded),\n };\n}\n\n/** The panel's skill rows, read as it reads them: project rows first, each under the panel's name. */\nfunction skillLinesOf({ skillConfigs, agentConfigs }: ActiveRoster): string[] {\n const { projectSkillRows, globalSkillRows } = computeScopeDiff({\n currentSkills: skillConfigs,\n currentAgents: agentConfigs,\n installedSkillConfigs: skillConfigs,\n installedAgentConfigs: agentConfigs,\n isInitMode: false,\n });\n\n return [\n ...projectSkillRows.map((row) => skillLine(row, \"project\")),\n ...globalSkillRows.map((row) => skillLine(row, \"global\")),\n ];\n}\n\nfunction skillLine(row: SkillDiffRow, scope: SkillScope): string {\n return `${getSkillEntryDisplayName(row)} (${scope})`;\n}\n"],"mappings":"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","names":[]}
@@ -2,14 +2,15 @@
2
2
  import {
3
3
  BaseCommand,
4
4
  EXIT_CODES
5
- } from "../../chunk-IAQFZFWD.js";
5
+ } from "../../chunk-JTMSFBCA.js";
6
+ import "../../chunk-FACDJH6O.js";
6
7
  import {
7
8
  isDirectoryEmpty,
8
9
  validateKebabCaseName,
9
10
  validateMarketplaceName,
10
11
  writeFile
11
- } from "../../chunk-E45IT3HC.js";
12
- import "../../chunk-AIBVAYHS.js";
12
+ } from "../../chunk-ENET4IF6.js";
13
+ import "../../chunk-UE4Z3YMB.js";
13
14
  import {
14
15
  CLI_INVOKE_COMMAND,
15
16
  DEFAULT_VERSION,
@@ -19,7 +20,7 @@ import {
19
20
  SKILL_RULES_PATH,
20
21
  STACKS_FILE_PATH,
21
22
  STANDARD_FILES
22
- } from "../../chunk-WUSEZFER.js";
23
+ } from "../../chunk-U46LYYRA.js";
23
24
  import "../../chunk-GHHJYNAN.js";
24
25
 
25
26
  // src/cli/commands/new/marketplace.ts
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/cli/commands/new/marketplace.ts","../../../src/cli/lib/marketplace-scaffold.ts"],"sourcesContent":["import { Args } from \"@oclif/core\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../../base-command.js\";\nimport { CLI_INVOKE_COMMAND, EDITOR_URL, SKILLS_DIR_PATH } from \"../../consts.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { validateMarketplaceName } from \"../../lib/marketplace-generator.js\";\nimport { exampleSkillId, writeMarketplaceScaffold } from \"../../lib/marketplace-scaffold.js\";\nimport { validateKebabCaseName } from \"../../lib/validate-kebab-name.js\";\nimport { isDirectoryEmpty } from \"../../utils/fs.js\";\n\nconst RESERVED_NAME_WAY_OUT = `run '${CLI_INVOKE_COMMAND} new marketplace <other-name>'`;\n\n/** No `--force` on purpose: it would overwrite work this command did not author. */\nfunction occupiedDirectoryError(marketplaceDir: string): string {\n return (\n `${marketplaceDir} already holds files. A scaffold writes a whole marketplace, ` +\n `so it will not write into a directory that already has contents. Choose another ` +\n `name, or empty that directory first.`\n );\n}\n\nexport default class NewMarketplace extends BaseCommand {\n static summary = \"Scaffold a marketplace of your own\";\n\n static description =\n \"Create a directory holding everything the CLI needs to read a marketplace: a package.json \" +\n \"carrying its identity, the three config files, and one example skill already named in the \" +\n \"marketplace's own namespace. It scaffolds only — run 'build plugins' and 'build marketplace' \" +\n \"to publish what you have written.\";\n\n static examples = [\n {\n description: \"Scaffold a marketplace named acme into ./acme\",\n command: \"<%= config.bin %> <%= command.id %> acme\",\n },\n ];\n\n static args = {\n name: Args.string({\n description:\n \"Name of the marketplace (kebab-case). Becomes the directory, the package.json name, \" +\n \"and the prefix every skill id must carry.\",\n required: true,\n }),\n };\n\n async run(): Promise<void> {\n const { args } = await this.parse(NewMarketplace);\n const marketplaceName = args.name;\n const marketplaceDir = path.join(process.cwd(), marketplaceName);\n\n this.refuseUnusableName(marketplaceName);\n await this.refuseOccupiedDirectory(marketplaceDir);\n\n try {\n const written = await writeMarketplaceScaffold(marketplaceDir, marketplaceName);\n this.reportCreated(marketplaceName, marketplaceDir, written);\n this.reportNextSteps(marketplaceName, marketplaceDir);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /** `build marketplace`'s name rules, enforced at creation rather than at publish. */\n private refuseUnusableName(marketplaceName: string): void {\n const kebabError = validateKebabCaseName(marketplaceName, \"Marketplace\");\n if (kebabError) {\n this.error(kebabError, { exit: EXIT_CODES.INVALID_ARGS });\n }\n\n // The scaffolded package.json uses this name, so it is also the package name.\n const reservedError = validateMarketplaceName(\n marketplaceName,\n marketplaceName,\n RESERVED_NAME_WAY_OUT,\n );\n if (reservedError) {\n this.error(reservedError, { exit: EXIT_CODES.ERROR });\n }\n }\n\n private async refuseOccupiedDirectory(marketplaceDir: string): Promise<void> {\n if (await isDirectoryEmpty(marketplaceDir)) return;\n\n this.error(occupiedDirectoryError(marketplaceDir), { exit: EXIT_CODES.ERROR });\n }\n\n private reportCreated(\n marketplaceName: string,\n marketplaceDir: string,\n written: readonly string[],\n ): void {\n this.log(\"\");\n this.logSuccess(`Created marketplace '${marketplaceName}' at ${marketplaceDir}`);\n for (const relPath of written) {\n this.log(` ${relPath}`);\n }\n }\n\n private reportNextSteps(marketplaceName: string, marketplaceDir: string): void {\n const skillDir = path.join(SKILLS_DIR_PATH, exampleSkillId(marketplaceName));\n const steps = [\n `cd ${marketplaceName}`,\n \"Replace the placeholder 'author' in package.json with your own handle — it is what 'build marketplace' records as this marketplace's owner\",\n `Replace ${skillDir}/ with a skill of your own. Every skill id must begin with '${marketplaceName}-'`,\n `${CLI_INVOKE_COMMAND} build plugins`,\n `${CLI_INVOKE_COMMAND} build marketplace`,\n `Push it to GitHub, then add it from the Marketplace button at ${EDITOR_URL}`,\n `${CLI_INVOKE_COMMAND} init --from <id> --marketplace ${marketplaceDir} (from a project — tests your local changes against a configuration built there)`,\n ];\n\n this.log(\"\");\n this.log(\"Next steps:\");\n for (const [index, step] of steps.entries()) {\n this.log(` ${index + 1}. ${step}`);\n }\n this.log(\"\");\n }\n}\n","import path from \"path\";\n\nimport {\n DEFAULT_VERSION,\n SKILL_CATEGORIES_PATH,\n SKILL_RULES_PATH,\n SKILLS_DIR_PATH,\n STACKS_FILE_PATH,\n STANDARD_FILES,\n} from \"../consts.js\";\nimport { writeFile } from \"../utils/fs.js\";\n\ntype ScaffoldFile = {\n /** Path relative to the marketplace root. */\n relPath: string;\n contents: string;\n};\n\nconst EXAMPLE_SKILL_SUFFIX = \"example-skill\";\n\n/** `web` rather than an invented domain, which would reach no sub-agent. */\nconst EXAMPLE_DOMAIN = \"web\";\n\n/** No built-in category holds this key, so declaring it adds one rather than redefining another. */\nconst EXAMPLE_CATEGORY = `${EXAMPLE_DOMAIN}-example`;\n\n/** Not namespaced: the namespace rule governs ids, not slugs. */\nconst EXAMPLE_SLUG = \"example-skill\";\n\n/** Where the scaffolded category sorts among the categories a marketplace grows later. */\nconst EXAMPLE_CATEGORY_ORDER = 1;\n\nconst INITIAL_PACKAGE_VERSION = \"0.1.0\";\n\nconst EXAMPLE_STACK_AGENT = \"web-developer\";\n\n/** Prefixed with the marketplace name, which `build marketplace` requires of every id. */\nexport function exampleSkillId(marketplaceName: string): string {\n return `${marketplaceName}-${EXAMPLE_SKILL_SUFFIX}`;\n}\n\n/** Writes exactly what the marketplace guide promises; a config pair would look installed. */\nexport async function writeMarketplaceScaffold(\n marketplaceDir: string,\n marketplaceName: string,\n): Promise<string[]> {\n const files = scaffoldFiles(marketplaceName);\n\n await Promise.all(\n files.map((file) => writeFile(path.join(marketplaceDir, file.relPath), file.contents)),\n );\n\n return files.map((file) => file.relPath);\n}\n\nfunction scaffoldFiles(marketplaceName: string): ScaffoldFile[] {\n const skillId = exampleSkillId(marketplaceName);\n const skillDir = path.join(SKILLS_DIR_PATH, skillId);\n\n return [\n { relPath: STANDARD_FILES.PACKAGE_JSON, contents: packageJson(marketplaceName) },\n { relPath: SKILL_CATEGORIES_PATH, contents: skillCategoriesModule() },\n { relPath: SKILL_RULES_PATH, contents: skillRulesModule() },\n { relPath: STACKS_FILE_PATH, contents: stacksModule(marketplaceName, skillId) },\n { relPath: path.join(skillDir, STANDARD_FILES.SKILL_MD), contents: skillMd(skillId) },\n {\n relPath: path.join(skillDir, STANDARD_FILES.METADATA_YAML),\n contents: metadataYaml(marketplaceName),\n },\n ];\n}\n\n/** The loader reads only a default export, so the export form is load-bearing. */\nfunction configModule(comment: string, data: unknown): string {\n return `${comment}\\nexport default ${JSON.stringify(data, null, 2)};\\n`;\n}\n\n/** `author` is the marketplace's own handle, a placeholder the next steps say to replace. */\nfunction packageJson(marketplaceName: string): string {\n return `${JSON.stringify(\n {\n name: marketplaceName,\n version: INITIAL_PACKAGE_VERSION,\n description: `Skills curated for ${marketplaceName}'s conventions`,\n author: { name: authorHandle(marketplaceName) },\n },\n null,\n 2,\n )}\\n`;\n}\n\nfunction authorHandle(marketplaceName: string): string {\n return `@${marketplaceName}`;\n}\n\nfunction skillCategoriesModule(): string {\n return configModule(\"// The categories this marketplace's skills fall into.\", {\n version: DEFAULT_VERSION,\n categories: {\n [EXAMPLE_CATEGORY]: {\n id: EXAMPLE_CATEGORY,\n displayName: \"Example\",\n description: \"Replace this with a category of your own\",\n domain: EXAMPLE_DOMAIN,\n exclusive: false,\n order: EXAMPLE_CATEGORY_ORDER,\n },\n },\n });\n}\n\n/** Version only: rules name skills by the CLI's slug union, which a marketplace's own lack. */\nfunction skillRulesModule(): string {\n return configModule(\n [\n \"// Relationships between skills — conflicts, requires, alternatives.\",\n \"//\",\n \"// Rules may only name skills the public catalogue carries; this marketplace's own\",\n \"// skills cannot be named here yet, and a rule that names one will not load.\",\n ].join(\"\\n\"),\n { version: DEFAULT_VERSION },\n );\n}\n\nfunction stacksModule(marketplaceName: string, skillId: string): string {\n return configModule(\"// The stacks this marketplace offers.\", {\n stacks: [\n {\n id: `${marketplaceName}-starter`,\n name: `${marketplaceName} starter`,\n description: `Every skill ${marketplaceName} ships`,\n agents: {\n [EXAMPLE_STACK_AGENT]: {\n [EXAMPLE_CATEGORY]: [{ id: skillId }],\n },\n },\n },\n ],\n });\n}\n\n/** The frontmatter id is also the directory name (`doctor` compares them). */\nfunction skillMd(skillId: string): string {\n return `---\nname: ${skillId}\ndescription: A placeholder skill — replace it with one of your own\n---\n\n# Example Skill\n\nThis is where a skill's content goes: the conventions, patterns and rules you want\nevery sub-agent carrying it to follow.\n\nReplace this file and the \\`${STANDARD_FILES.METADATA_YAML}\\` beside it, and rename the\ndirectory to the id your skill should publish under.\n`;\n}\n\nfunction metadataYaml(marketplaceName: string): string {\n return [\n \"custom: true\",\n `domain: ${EXAMPLE_DOMAIN}`,\n `author: \"${authorHandle(marketplaceName)}\"`,\n \"displayName: Example Skill\",\n `category: ${EXAMPLE_CATEGORY}`,\n `slug: ${EXAMPLE_SLUG}`,\n 'cliDescription: \"A placeholder skill to replace with your own\"',\n 'usageGuidance: \"Use when you need a worked example of this marketplace\\'s skill shape\"',\n \"\",\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":["path","path"]}
1
+ {"version":3,"sources":["../../../src/cli/commands/new/marketplace.ts","../../../src/cli/lib/marketplace-scaffold.ts"],"sourcesContent":["import { Args } from \"@oclif/core\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../../base-command.js\";\nimport { CLI_INVOKE_COMMAND, EDITOR_URL, SKILLS_DIR_PATH } from \"../../consts.js\";\nimport { EXIT_CODES } from \"../../lib/exit-codes.js\";\nimport { validateMarketplaceName } from \"../../lib/marketplace-generator.js\";\nimport { exampleSkillId, writeMarketplaceScaffold } from \"../../lib/marketplace-scaffold.js\";\nimport { validateKebabCaseName } from \"../../lib/validate-kebab-name.js\";\nimport { isDirectoryEmpty } from \"../../utils/fs.js\";\n\nconst RESERVED_NAME_WAY_OUT = `run '${CLI_INVOKE_COMMAND} new marketplace <other-name>'`;\n\n/** No `--force` on purpose: it would overwrite work this command did not author. */\nfunction occupiedDirectoryError(marketplaceDir: string): string {\n return (\n `${marketplaceDir} already holds files. A scaffold writes a whole marketplace, ` +\n `so it will not write into a directory that already has contents. Choose another ` +\n `name, or empty that directory first.`\n );\n}\n\nexport default class NewMarketplace extends BaseCommand {\n static summary = \"Scaffold a marketplace of your own\";\n\n static description =\n \"Create a directory holding everything the CLI needs to read a marketplace: a package.json \" +\n \"carrying its identity, the three config files, and one example skill already named in the \" +\n \"marketplace's own namespace. It scaffolds only — run 'build plugins' and 'build marketplace' \" +\n \"to publish what you have written.\";\n\n static examples = [\n {\n description: \"Scaffold a marketplace named acme into ./acme\",\n command: \"<%= config.bin %> <%= command.id %> acme\",\n },\n ];\n\n static args = {\n name: Args.string({\n description:\n \"Name of the marketplace (kebab-case). Becomes the directory, the package.json name, \" +\n \"and the prefix every skill id must carry.\",\n required: true,\n }),\n };\n\n async run(): Promise<void> {\n const { args } = await this.parse(NewMarketplace);\n const marketplaceName = args.name;\n const marketplaceDir = path.join(process.cwd(), marketplaceName);\n\n this.refuseUnusableName(marketplaceName);\n await this.refuseOccupiedDirectory(marketplaceDir);\n\n try {\n const written = await writeMarketplaceScaffold(marketplaceDir, marketplaceName);\n this.reportCreated(marketplaceName, marketplaceDir, written);\n this.reportNextSteps(marketplaceName, marketplaceDir);\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /** `build marketplace`'s name rules, enforced at creation rather than at publish. */\n private refuseUnusableName(marketplaceName: string): void {\n const kebabError = validateKebabCaseName(marketplaceName, \"Marketplace\");\n if (kebabError) {\n this.error(kebabError, { exit: EXIT_CODES.INVALID_ARGS });\n }\n\n // The scaffolded package.json uses this name, so it is also the package name.\n const reservedError = validateMarketplaceName(\n marketplaceName,\n marketplaceName,\n RESERVED_NAME_WAY_OUT,\n );\n if (reservedError) {\n this.error(reservedError, { exit: EXIT_CODES.ERROR });\n }\n }\n\n private async refuseOccupiedDirectory(marketplaceDir: string): Promise<void> {\n if (await isDirectoryEmpty(marketplaceDir)) return;\n\n this.error(occupiedDirectoryError(marketplaceDir), { exit: EXIT_CODES.ERROR });\n }\n\n private reportCreated(\n marketplaceName: string,\n marketplaceDir: string,\n written: readonly string[],\n ): void {\n this.log(\"\");\n this.logSuccess(`Created marketplace '${marketplaceName}' at ${marketplaceDir}`);\n for (const relPath of written) {\n this.log(` ${relPath}`);\n }\n }\n\n private reportNextSteps(marketplaceName: string, marketplaceDir: string): void {\n const skillDir = path.join(SKILLS_DIR_PATH, exampleSkillId(marketplaceName));\n const steps = [\n `cd ${marketplaceName}`,\n \"Replace the placeholder 'author' in package.json with your own handle — it is what 'build marketplace' records as this marketplace's owner\",\n `Replace ${skillDir}/ with a skill of your own. Every skill id must begin with '${marketplaceName}-'`,\n `${CLI_INVOKE_COMMAND} build plugins`,\n `${CLI_INVOKE_COMMAND} build marketplace`,\n `Push it to GitHub, then add it from the Marketplace button at ${EDITOR_URL}`,\n `${CLI_INVOKE_COMMAND} init --from <id> --marketplace ${marketplaceDir} (from a project — tests your local changes against a configuration built there)`,\n ];\n\n this.log(\"\");\n this.log(\"Next steps:\");\n for (const [index, step] of steps.entries()) {\n this.log(` ${index + 1}. ${step}`);\n }\n this.log(\"\");\n }\n}\n","import path from \"path\";\n\nimport {\n DEFAULT_VERSION,\n SKILL_CATEGORIES_PATH,\n SKILL_RULES_PATH,\n SKILLS_DIR_PATH,\n STACKS_FILE_PATH,\n STANDARD_FILES,\n} from \"../consts.js\";\nimport { writeFile } from \"../utils/fs.js\";\n\ntype ScaffoldFile = {\n /** Path relative to the marketplace root. */\n relPath: string;\n contents: string;\n};\n\nconst EXAMPLE_SKILL_SUFFIX = \"example-skill\";\n\n/** `web` rather than an invented domain, which would reach no sub-agent. */\nconst EXAMPLE_DOMAIN = \"web\";\n\n/** No built-in category holds this key, so declaring it adds one rather than redefining another. */\nconst EXAMPLE_CATEGORY = `${EXAMPLE_DOMAIN}-example`;\n\n/** Not namespaced: the namespace rule governs ids, not slugs. */\nconst EXAMPLE_SLUG = \"example-skill\";\n\n/** Where the scaffolded category sorts among the categories a marketplace grows later. */\nconst EXAMPLE_CATEGORY_ORDER = 1;\n\nconst INITIAL_PACKAGE_VERSION = \"0.1.0\";\n\nconst EXAMPLE_STACK_AGENT = \"web-developer\";\n\n/** Prefixed with the marketplace name, which `build marketplace` requires of every id. */\nexport function exampleSkillId(marketplaceName: string): string {\n return `${marketplaceName}-${EXAMPLE_SKILL_SUFFIX}`;\n}\n\n/** Writes exactly what the marketplace guide promises; a config pair would look installed. */\nexport async function writeMarketplaceScaffold(\n marketplaceDir: string,\n marketplaceName: string,\n): Promise<string[]> {\n const files = scaffoldFiles(marketplaceName);\n\n await Promise.all(\n files.map((file) => writeFile(path.join(marketplaceDir, file.relPath), file.contents)),\n );\n\n return files.map((file) => file.relPath);\n}\n\nfunction scaffoldFiles(marketplaceName: string): ScaffoldFile[] {\n const skillId = exampleSkillId(marketplaceName);\n const skillDir = path.join(SKILLS_DIR_PATH, skillId);\n\n return [\n { relPath: STANDARD_FILES.PACKAGE_JSON, contents: packageJson(marketplaceName) },\n { relPath: SKILL_CATEGORIES_PATH, contents: skillCategoriesModule() },\n { relPath: SKILL_RULES_PATH, contents: skillRulesModule() },\n { relPath: STACKS_FILE_PATH, contents: stacksModule(marketplaceName, skillId) },\n { relPath: path.join(skillDir, STANDARD_FILES.SKILL_MD), contents: skillMd(skillId) },\n {\n relPath: path.join(skillDir, STANDARD_FILES.METADATA_YAML),\n contents: metadataYaml(marketplaceName),\n },\n ];\n}\n\n/** The loader reads only a default export, so the export form is load-bearing. */\nfunction configModule(comment: string, data: unknown): string {\n return `${comment}\\nexport default ${JSON.stringify(data, null, 2)};\\n`;\n}\n\n/** `author` is the marketplace's own handle, a placeholder the next steps say to replace. */\nfunction packageJson(marketplaceName: string): string {\n return `${JSON.stringify(\n {\n name: marketplaceName,\n version: INITIAL_PACKAGE_VERSION,\n description: `Skills curated for ${marketplaceName}'s conventions`,\n author: { name: authorHandle(marketplaceName) },\n },\n null,\n 2,\n )}\\n`;\n}\n\nfunction authorHandle(marketplaceName: string): string {\n return `@${marketplaceName}`;\n}\n\nfunction skillCategoriesModule(): string {\n return configModule(\"// The categories this marketplace's skills fall into.\", {\n version: DEFAULT_VERSION,\n categories: {\n [EXAMPLE_CATEGORY]: {\n id: EXAMPLE_CATEGORY,\n displayName: \"Example\",\n description: \"Replace this with a category of your own\",\n domain: EXAMPLE_DOMAIN,\n exclusive: false,\n order: EXAMPLE_CATEGORY_ORDER,\n },\n },\n });\n}\n\n/** Version only: rules name skills by the CLI's slug union, which a marketplace's own lack. */\nfunction skillRulesModule(): string {\n return configModule(\n [\n \"// Relationships between skills — conflicts, requires, alternatives.\",\n \"//\",\n \"// Rules may only name skills the public catalogue carries; this marketplace's own\",\n \"// skills cannot be named here yet, and a rule that names one will not load.\",\n ].join(\"\\n\"),\n { version: DEFAULT_VERSION },\n );\n}\n\nfunction stacksModule(marketplaceName: string, skillId: string): string {\n return configModule(\"// The stacks this marketplace offers.\", {\n stacks: [\n {\n id: `${marketplaceName}-starter`,\n name: `${marketplaceName} starter`,\n description: `Every skill ${marketplaceName} ships`,\n agents: {\n [EXAMPLE_STACK_AGENT]: {\n [EXAMPLE_CATEGORY]: [{ id: skillId }],\n },\n },\n },\n ],\n });\n}\n\n/** The frontmatter id is also the directory name (`doctor` compares them). */\nfunction skillMd(skillId: string): string {\n return `---\nname: ${skillId}\ndescription: A placeholder skill — replace it with one of your own\n---\n\n# Example Skill\n\nThis is where a skill's content goes: the conventions, patterns and rules you want\nevery sub-agent carrying it to follow.\n\nReplace this file and the \\`${STANDARD_FILES.METADATA_YAML}\\` beside it, and rename the\ndirectory to the id your skill should publish under.\n`;\n}\n\nfunction metadataYaml(marketplaceName: string): string {\n return [\n \"custom: true\",\n `domain: ${EXAMPLE_DOMAIN}`,\n `author: \"${authorHandle(marketplaceName)}\"`,\n \"displayName: Example Skill\",\n `category: ${EXAMPLE_CATEGORY}`,\n `slug: ${EXAMPLE_SLUG}`,\n 'cliDescription: \"A placeholder skill to replace with your own\"',\n 'usageGuidance: \"Use when you need a worked example of this marketplace\\'s skill shape\"',\n \"\",\n ].join(\"\\n\");\n}\n"],"mappings":"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","names":["path","path"]}
@@ -1,26 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  loadSource
4
- } from "../chunk-R7GKQBZJ.js";
5
- import "../chunk-REHVGFJE.js";
6
- import "../chunk-7BHDKEGK.js";
7
- import "../chunk-IXVGBUWI.js";
8
- import "../chunk-EFXVYQGT.js";
4
+ } from "../chunk-CKBWEWHZ.js";
5
+ import "../chunk-XMQIWPIR.js";
6
+ import "../chunk-JNRACLNS.js";
7
+ import "../chunk-EC3JXT23.js";
8
+ import "../chunk-MQZNDK5F.js";
9
9
  import {
10
10
  BaseCommand
11
- } from "../chunk-IAQFZFWD.js";
11
+ } from "../chunk-JTMSFBCA.js";
12
+ import "../chunk-FACDJH6O.js";
12
13
  import {
14
+ INFO_MESSAGES,
13
15
  STATUS_MESSAGES
14
- } from "../chunk-E45IT3HC.js";
16
+ } from "../chunk-ENET4IF6.js";
15
17
  import {
16
18
  plural,
17
19
  stripTerminalControls,
18
20
  truncateText,
19
21
  typedValues
20
- } from "../chunk-AIBVAYHS.js";
22
+ } from "../chunk-UE4Z3YMB.js";
21
23
  import {
22
24
  EDITOR_ADDRESS
23
- } from "../chunk-WUSEZFER.js";
25
+ } from "../chunk-U46LYYRA.js";
24
26
  import "../chunk-GHHJYNAN.js";
25
27
 
26
28
  // src/cli/commands/search.ts
@@ -50,6 +52,9 @@ var Search = class _Search extends BaseCommand {
50
52
  static flags = {};
51
53
  async run() {
52
54
  const { args } = await this.parse(_Search);
55
+ await this.sayWhenTheProjectsConfigDeclaresNothing(
56
+ INFO_MESSAGES.DECLARES_NOTHING_TO_SEARCH_FROM
57
+ );
53
58
  await this.ensureConfigReadable(process.cwd());
54
59
  await this.runSearch(args.query);
55
60
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/search.ts"],"sourcesContent":["import { Args } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { EDITOR_ADDRESS } from \"../consts.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport type { ResolvedSkill } from \"../types/index.js\";\nimport { STATUS_MESSAGES } from \"../utils/messages.js\";\nimport { plural, stripTerminalControls, truncateText } from \"../utils/string.js\";\nimport { typedValues } from \"../utils/typed-object.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\n/** Plain strings: sanitised values are no longer known to be in their unions. */\ntype ResultRow = {\n id: string;\n name: string;\n source: string;\n category: string;\n description: string;\n};\n\nexport default class Search extends BaseCommand {\n static summary = \"Search the catalog of available skills\";\n static description =\n \"Read-only catalog browse. Searches the marketplace this installation reads from, \" +\n \"plus the local skills already on disk, by id, displayName, slug, description, or \" +\n `category. To install one, add it in ${EDITOR_ADDRESS}.`;\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Search by any keyword (matches id, name, description, category)\",\n command: \"<%= config.bin %> search state\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches id, displayName, slug, description, category)\",\n required: true,\n }),\n };\n\n static flags = {};\n\n async run(): Promise<void> {\n const { args } = await this.parse(Search);\n // The configs name the marketplace searched, so an unreadable one is not read past.\n await this.ensureConfigReadable(process.cwd());\n await this.runSearch(args.query);\n }\n\n private async runSearch(query: string): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n const results = skillsMatching(await loadSearchableSkills(), query);\n\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n return;\n }\n\n this.log(`Found ${plural(results.length, \"skill\")} matching \"${query}\"`);\n this.log(\"\");\n printResultsTable(results);\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n\n/** The marketplace matrix, with on-disk local skills already merged in by `loadSource`. */\nasync function loadSearchableSkills(): Promise<ResolvedSkill[]> {\n const { sourceResult } = await loadSource({ projectDir: process.cwd() });\n\n return typedValues(sourceResult.matrix.skills);\n}\n\n/** In display-name order, case aside. */\nfunction skillsMatching(skills: ResolvedSkill[], query: string): ResolvedSkill[] {\n return sortBy(\n skills.filter((skill) => matchesQuery(skill, query)),\n (skill) => skill.displayName.toLowerCase(),\n );\n}\n\nfunction printResultsTable(results: ResolvedSkill[]): void {\n printTable({\n data: results.map(toResultRow),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"name\", name: \"Name\" },\n { key: \"source\", name: \"Origin\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n}\n\n/** Strips terminal controls: a third-party marketplace's text could otherwise repaint the table. */\nfunction toResultRow(skill: ResolvedSkill): ResultRow {\n return {\n id: stripTerminalControls(skill.id),\n name: stripTerminalControls(skill.displayName),\n source: stripTerminalControls(activeSourceName(skill)),\n category: stripTerminalControls(skill.category),\n description: truncateText(skill.description, MAX_DESCRIPTION_WIDTH),\n };\n}\n\n/** `loadSource` always tags an origin, so an untagged skill is a bug, not a fallback case. */\nfunction activeSourceName(skill: ResolvedSkill): string {\n const { activeSource } = skill;\n if (!activeSource) {\n throw new Error(\n `Skill \"${skill.id}\" was loaded with no origin, so where it comes from is unknown`,\n );\n }\n return activeSource.name;\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n return [skill.id, skill.displayName, skill.slug, skill.description, skill.category].some(\n (field) => field.toLowerCase().includes(lowerQuery),\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/search.ts"],"sourcesContent":["import { Args } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { EDITOR_ADDRESS } from \"../consts.js\";\nimport { loadSource } from \"../lib/operations/index.js\";\nimport type { ResolvedSkill } from \"../types/index.js\";\nimport { INFO_MESSAGES, STATUS_MESSAGES } from \"../utils/messages.js\";\nimport { plural, stripTerminalControls, truncateText } from \"../utils/string.js\";\nimport { typedValues } from \"../utils/typed-object.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\n/** Plain strings: sanitised values are no longer known to be in their unions. */\ntype ResultRow = {\n id: string;\n name: string;\n source: string;\n category: string;\n description: string;\n};\n\nexport default class Search extends BaseCommand {\n static summary = \"Search the catalog of available skills\";\n static description =\n \"Read-only catalog browse. Searches the marketplace this installation reads from, \" +\n \"plus the local skills already on disk, by id, displayName, slug, description, or \" +\n `category. To install one, add it in ${EDITOR_ADDRESS}.`;\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Search by any keyword (matches id, name, description, category)\",\n command: \"<%= config.bin %> search state\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches id, displayName, slug, description, category)\",\n required: true,\n }),\n };\n\n static flags = {};\n\n async run(): Promise<void> {\n const { args } = await this.parse(Search);\n await this.sayWhenTheProjectsConfigDeclaresNothing(\n INFO_MESSAGES.DECLARES_NOTHING_TO_SEARCH_FROM,\n );\n // The configs name the marketplace searched, so an unreadable one is not read past.\n await this.ensureConfigReadable(process.cwd());\n await this.runSearch(args.query);\n }\n\n private async runSearch(query: string): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n const results = skillsMatching(await loadSearchableSkills(), query);\n\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n return;\n }\n\n this.log(`Found ${plural(results.length, \"skill\")} matching \"${query}\"`);\n this.log(\"\");\n printResultsTable(results);\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n\n/** The marketplace matrix, with on-disk local skills already merged in by `loadSource`. */\nasync function loadSearchableSkills(): Promise<ResolvedSkill[]> {\n const { sourceResult } = await loadSource({ projectDir: process.cwd() });\n\n return typedValues(sourceResult.matrix.skills);\n}\n\n/** In display-name order, case aside. */\nfunction skillsMatching(skills: ResolvedSkill[], query: string): ResolvedSkill[] {\n return sortBy(\n skills.filter((skill) => matchesQuery(skill, query)),\n (skill) => skill.displayName.toLowerCase(),\n );\n}\n\nfunction printResultsTable(results: ResolvedSkill[]): void {\n printTable({\n data: results.map(toResultRow),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"name\", name: \"Name\" },\n { key: \"source\", name: \"Origin\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n}\n\n/** Strips terminal controls: a third-party marketplace's text could otherwise repaint the table. */\nfunction toResultRow(skill: ResolvedSkill): ResultRow {\n return {\n id: stripTerminalControls(skill.id),\n name: stripTerminalControls(skill.displayName),\n source: stripTerminalControls(activeSourceName(skill)),\n category: stripTerminalControls(skill.category),\n description: truncateText(skill.description, MAX_DESCRIPTION_WIDTH),\n };\n}\n\n/** `loadSource` always tags an origin, so an untagged skill is a bug, not a fallback case. */\nfunction activeSourceName(skill: ResolvedSkill): string {\n const { activeSource } = skill;\n if (!activeSource) {\n throw new Error(\n `Skill \"${skill.id}\" was loaded with no origin, so where it comes from is unknown`,\n );\n }\n return activeSource.name;\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n return [skill.id, skill.displayName, skill.slug, skill.description, skill.category].some(\n (field) => field.toLowerCase().includes(lowerQuery),\n );\n}\n"],"mappings":"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","names":[]}
@@ -2,21 +2,20 @@
2
2
  import {
3
3
  publishSeedConfig,
4
4
  seedPayloadForInstallation
5
- } from "../chunk-3PJZ4QNJ.js";
5
+ } from "../chunk-B7AVWSK2.js";
6
6
  import {
7
7
  unofferablePlacementsFound
8
- } from "../chunk-ECPFYHDX.js";
9
- import "../chunk-QCX66KBM.js";
10
- import "../chunk-EFXVYQGT.js";
8
+ } from "../chunk-ZBI6GFJD.js";
9
+ import "../chunk-SN64WNWE.js";
10
+ import "../chunk-MQZNDK5F.js";
11
11
  import {
12
+ BaseCommand,
13
+ EXIT_CODES,
12
14
  providerFlag,
13
15
  providerNamedBy,
14
16
  refuseAnAmbiguousInstallation
15
- } from "../chunk-ORO2T4K2.js";
16
- import {
17
- BaseCommand,
18
- EXIT_CODES
19
- } from "../chunk-IAQFZFWD.js";
17
+ } from "../chunk-JTMSFBCA.js";
18
+ import "../chunk-FACDJH6O.js";
20
19
  import {
21
20
  formatZodErrors,
22
21
  getErrorMessage,
@@ -26,15 +25,15 @@ import {
26
25
  sharedIdNamesAFolder,
27
26
  sharedSkillsLeftBehind,
28
27
  warn
29
- } from "../chunk-E45IT3HC.js";
28
+ } from "../chunk-ENET4IF6.js";
30
29
  import {
31
30
  stripTerminalControls,
32
31
  truncateText,
33
32
  typedEntries
34
- } from "../chunk-AIBVAYHS.js";
33
+ } from "../chunk-UE4Z3YMB.js";
35
34
  import {
36
35
  installableSeedPayloadSchema
37
- } from "../chunk-WUSEZFER.js";
36
+ } from "../chunk-U46LYYRA.js";
38
37
  import "../chunk-GHHJYNAN.js";
39
38
 
40
39
  // src/cli/commands/share.ts
@@ -86,11 +85,11 @@ async function readAllOf(stream) {
86
85
  }
87
86
 
88
87
  // src/cli/commands/share.ts
89
- function caveatsAbout(payload, leftBehind) {
88
+ function caveatsAbout({ payload, leftBehind, namedBy }) {
90
89
  const { marketplace } = payload;
91
90
  return [
92
91
  ...isAFolder(marketplace) ? [sharedIdNamesAFolder(marketplace)] : [],
93
- ...leftBehind.length > 0 ? [sharedSkillsLeftBehind(leftBehind)] : []
92
+ ...leftBehind.length > 0 ? [sharedSkillsLeftBehind(leftBehind, namedBy)] : []
94
93
  ];
95
94
  }
96
95
  function isAFolder(marketplace) {
@@ -117,10 +116,12 @@ var Share = class _Share extends BaseCommand {
117
116
  async run() {
118
117
  const { flags } = await this.parse(_Share);
119
118
  if (!flags.stdin) {
119
+ const namedProvider = providerNamedBy(flags.provider);
120
+ await this.sayWhenTheGlobalInstallationStandsIn(namedProvider);
120
121
  await refuseAnAmbiguousInstallation(
121
122
  process.cwd(),
122
123
  "share",
123
- providerNamedBy(flags.provider),
124
+ namedProvider,
124
125
  (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS })
125
126
  );
126
127
  await this.ensureConfigReadable(process.cwd());
@@ -144,18 +145,15 @@ var Share = class _Share extends BaseCommand {
144
145
  if (!prepared.ok) {
145
146
  this.error(prepared.error, { exit: EXIT_CODES.ERROR });
146
147
  }
147
- this.refuseEjectedSkills(prepared.payload);
148
+ this.refuseEjectedSkills(prepared);
148
149
  this.log(`Sharing ${prepared.skills} skill(s) across ${prepared.agents} sub-agent(s)...`);
149
- return {
150
- payload: prepared.payload,
151
- caveats: caveatsAbout(prepared.payload, prepared.leftBehind)
152
- };
150
+ return { payload: prepared.payload, caveats: caveatsAbout(prepared) };
153
151
  }
154
152
  /** A share carries plugins only: an ejected skill is a local copy the user may have edited. */
155
- refuseEjectedSkills(payload) {
153
+ refuseEjectedSkills({ payload, namedBy }) {
156
154
  const ejected = ejectedSkillsIn(payload);
157
155
  if (ejected.length > 0) {
158
- this.error(shareRefusesEjectedSkills(ejected), { exit: EXIT_CODES.ERROR });
156
+ this.error(shareRefusesEjectedSkills(ejected, namedBy), { exit: EXIT_CODES.ERROR });
159
157
  }
160
158
  }
161
159
  /** The caller's configuration; no installation is read, so it owes no caveats. */