agents-inc 0.153.0 → 0.154.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/{chunk-EFU6P3B7.js → chunk-2IMYK4WN.js} +3 -3
- package/dist/{chunk-U2YSGBHA.js → chunk-4VCWL2IG.js} +33 -16
- package/dist/chunk-4VCWL2IG.js.map +1 -0
- package/dist/{chunk-ORJ5Y222.js → chunk-5MFJ24VM.js} +90 -24
- package/dist/chunk-5MFJ24VM.js.map +1 -0
- package/dist/{chunk-TY6CAOL7.js → chunk-7VZV4O6B.js} +3 -3
- package/dist/{chunk-4VYALFQZ.js → chunk-AKQ5QISO.js} +6 -6
- package/dist/{chunk-U2DNAHFE.js → chunk-AURY6RT6.js} +3 -3
- package/dist/{chunk-ACKC577F.js → chunk-B66SC72V.js} +3 -3
- package/dist/{chunk-WDAO3RUY.js → chunk-BZ4CZBOM.js} +3 -3
- package/dist/{chunk-NXQAY5U7.js → chunk-CBF4ZYV3.js} +4556 -4457
- package/dist/chunk-CBF4ZYV3.js.map +1 -0
- package/dist/{chunk-JFAUQDZM.js → chunk-CHNA5RVS.js} +3 -3
- package/dist/{chunk-2HC2SNRP.js → chunk-DRKSYJZ2.js} +1 -5
- package/dist/chunk-DRKSYJZ2.js.map +1 -0
- package/dist/{chunk-X5XJ6WKO.js → chunk-FMYHWKGG.js} +45 -4
- package/dist/chunk-FMYHWKGG.js.map +1 -0
- package/dist/{chunk-K7PJDWER.js → chunk-GUDGCFSF.js} +6 -6
- package/dist/{chunk-35VOK7XE.js → chunk-IPJOMAWC.js} +4355 -4355
- package/dist/{chunk-35VOK7XE.js.map → chunk-IPJOMAWC.js.map} +1 -1
- package/dist/{chunk-VGEBYCQZ.js → chunk-IXEDSKMH.js} +4 -15
- package/dist/chunk-IXEDSKMH.js.map +1 -0
- package/dist/{chunk-ZNDLUWWD.js → chunk-LA3JPESW.js} +3 -3
- package/dist/{chunk-M5HSTNYU.js → chunk-MJFIO5SX.js} +5 -23
- package/dist/chunk-MJFIO5SX.js.map +1 -0
- package/dist/{chunk-VECFAKM5.js → chunk-NFH6SA62.js} +4 -4
- package/dist/{chunk-R4SEU3DF.js → chunk-NKCY2ULI.js} +2 -2
- package/dist/{chunk-IO4VEW5U.js → chunk-ONWEOS77.js} +2 -2
- package/dist/{chunk-FRWKCE6R.js → chunk-PRJD5MMQ.js} +3 -3
- package/dist/{chunk-HEBPKK5L.js → chunk-QQTYMW7N.js} +11 -23
- package/dist/chunk-QQTYMW7N.js.map +1 -0
- package/dist/{chunk-KET3EVGX.js → chunk-QUDQTO3O.js} +3 -3
- package/dist/{chunk-BMGBA6HJ.js → chunk-R7JV22QK.js} +12 -12
- package/dist/{chunk-FIHTAFST.js → chunk-TUQF577Z.js} +30 -30
- package/dist/{chunk-FIHTAFST.js.map → chunk-TUQF577Z.js.map} +1 -1
- package/dist/{chunk-NXGMM5YN.js → chunk-UW44KSYL.js} +3 -3
- package/dist/{chunk-WG6V6VJV.js → chunk-WRRP47PY.js} +2 -2
- package/dist/{chunk-F7Z5I6GU.js → chunk-XMEIVWAS.js} +4 -4
- package/dist/{chunk-REKOWTIB.js → chunk-ZU6DAR4S.js} +42 -8
- package/dist/chunk-ZU6DAR4S.js.map +1 -0
- package/dist/commands/build/marketplace.js +6 -5
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +6 -6
- package/dist/commands/compile.js +48 -10
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/doctor.js +10 -10
- package/dist/commands/edit.js +93 -59
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +10 -10
- package/dist/commands/init.js +29 -29
- package/dist/commands/list.js +7 -7
- package/dist/commands/search.js +29 -21
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/uninstall.js +198 -147
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +5 -5
- package/dist/components/wizard/category-grid.js +3 -3
- package/dist/components/wizard/checkbox-grid.js +2 -2
- package/dist/components/wizard/domain-selection.js +8 -8
- package/dist/components/wizard/run-wizard-session.js +21 -21
- package/dist/components/wizard/skill-agent-summary.js +5 -5
- package/dist/components/wizard/source-grid.js +3 -3
- package/dist/components/wizard/stack-selection.js +5 -5
- package/dist/components/wizard/step-agents.js +8 -8
- package/dist/components/wizard/step-build.js +7 -7
- package/dist/components/wizard/step-confirm.js +8 -8
- package/dist/components/wizard/step-sources.js +7 -7
- package/dist/components/wizard/step-stack.js +6 -6
- package/dist/components/wizard/summary-panel.js +7 -7
- package/dist/components/wizard/wizard-layout.js +9 -9
- package/dist/components/wizard/wizard.js +20 -20
- package/dist/copy-local-skills-WVHJFRPK.js +14 -0
- package/dist/hooks/init.js +29 -29
- package/dist/load-agent-defs-5OT54J5M.js +15 -0
- package/dist/{loader-4U7UCE2Y.js → loader-JIZDTR4G.js} +2 -2
- package/dist/recompile-project-agents-VREEPBDV.js +20 -0
- package/dist/{source-loader-ZNSYJJCI.js → source-loader-OE6EJFPU.js} +4 -4
- package/dist/stores/wizard-store.js +4 -4
- package/package.json +1 -1
- package/src/schemas/plugin.schema.json +3 -0
- package/dist/chunk-2HC2SNRP.js.map +0 -1
- package/dist/chunk-HEBPKK5L.js.map +0 -1
- package/dist/chunk-M5HSTNYU.js.map +0 -1
- package/dist/chunk-NXQAY5U7.js.map +0 -1
- package/dist/chunk-ORJ5Y222.js.map +0 -1
- package/dist/chunk-REKOWTIB.js.map +0 -1
- package/dist/chunk-U2YSGBHA.js.map +0 -1
- package/dist/chunk-VGEBYCQZ.js.map +0 -1
- package/dist/chunk-X5XJ6WKO.js.map +0 -1
- package/dist/copy-local-skills-KF2RAVD3.js +0 -14
- package/dist/load-agent-defs-DGXGBU3Q.js +0 -15
- package/dist/recompile-project-agents-CJVBAWDJ.js +0 -20
- /package/dist/{chunk-EFU6P3B7.js.map → chunk-2IMYK4WN.js.map} +0 -0
- /package/dist/{chunk-TY6CAOL7.js.map → chunk-7VZV4O6B.js.map} +0 -0
- /package/dist/{chunk-4VYALFQZ.js.map → chunk-AKQ5QISO.js.map} +0 -0
- /package/dist/{chunk-U2DNAHFE.js.map → chunk-AURY6RT6.js.map} +0 -0
- /package/dist/{chunk-ACKC577F.js.map → chunk-B66SC72V.js.map} +0 -0
- /package/dist/{chunk-WDAO3RUY.js.map → chunk-BZ4CZBOM.js.map} +0 -0
- /package/dist/{chunk-JFAUQDZM.js.map → chunk-CHNA5RVS.js.map} +0 -0
- /package/dist/{chunk-K7PJDWER.js.map → chunk-GUDGCFSF.js.map} +0 -0
- /package/dist/{chunk-ZNDLUWWD.js.map → chunk-LA3JPESW.js.map} +0 -0
- /package/dist/{chunk-VECFAKM5.js.map → chunk-NFH6SA62.js.map} +0 -0
- /package/dist/{chunk-R4SEU3DF.js.map → chunk-NKCY2ULI.js.map} +0 -0
- /package/dist/{chunk-IO4VEW5U.js.map → chunk-ONWEOS77.js.map} +0 -0
- /package/dist/{chunk-FRWKCE6R.js.map → chunk-PRJD5MMQ.js.map} +0 -0
- /package/dist/{chunk-KET3EVGX.js.map → chunk-QUDQTO3O.js.map} +0 -0
- /package/dist/{chunk-BMGBA6HJ.js.map → chunk-R7JV22QK.js.map} +0 -0
- /package/dist/{chunk-NXGMM5YN.js.map → chunk-UW44KSYL.js.map} +0 -0
- /package/dist/{chunk-WG6V6VJV.js.map → chunk-WRRP47PY.js.map} +0 -0
- /package/dist/{chunk-F7Z5I6GU.js.map → chunk-XMEIVWAS.js.map} +0 -0
- /package/dist/{copy-local-skills-KF2RAVD3.js.map → copy-local-skills-WVHJFRPK.js.map} +0 -0
- /package/dist/{load-agent-defs-DGXGBU3Q.js.map → load-agent-defs-5OT54J5M.js.map} +0 -0
- /package/dist/{loader-4U7UCE2Y.js.map → loader-JIZDTR4G.js.map} +0 -0
- /package/dist/{recompile-project-agents-CJVBAWDJ.js.map → recompile-project-agents-VREEPBDV.js.map} +0 -0
- /package/dist/{source-loader-ZNSYJJCI.js.map → source-loader-OE6EJFPU.js.map} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/commands/edit.tsx"],"sourcesContent":["import path from \"path\";\n\nimport chalk from \"chalk\";\nimport { Flags } from \"@oclif/core\";\nimport { render } from \"../components/render.js\";\n\nimport { difference, indexBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { type WizardResultV2 } from \"../components/wizard/wizard.js\";\nimport { runWizardSession } from \"../components/wizard/run-wizard-session.js\";\nimport {\n CLI_INVOKE_COMMAND,\n CLI_COLORS,\n EDIT_PROJECT_SETUP_FLAG,\n EJECT_SOURCE,\n formatSourceDisplayName,\n} from \"../consts.js\";\nimport {\n detectProject,\n loadSource,\n copyLocalSkills,\n uninstallPluginSkills,\n loadAgentDefs,\n type AgentDefs,\n writeProjectConfig,\n type ConfigWriteResult,\n compileAgentsAllScopes,\n discoverInstalledSkills,\n} from \"../lib/operations/index.js\";\nimport { Spinner } from \"../components/common/spinner.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport {\n type Installation,\n detectMigrations,\n executeMigration,\n isHomeDirectory,\n installBaseDir,\n resolveInstallPaths,\n INSTALL_MODE_DESCRIPTIONS,\n} from \"../lib/installation/index.js\";\nimport { applyMigratedGlobalSources, mutateGlobal } from \"../lib/config-gate/index.js\";\nimport { matrix, getSkillById, getSkillDisplayName } from \"../lib/matrix/matrix-provider\";\nimport {\n activeAgentNames,\n activeAgentScopeMap,\n isActiveAt,\n} from \"../lib/configuration/scope-predicates.js\";\nimport type { SourceLoadResult } from \"../lib/loading/index.js\";\nimport {\n discoverAllPluginSkills,\n buildMarketplacePluginRef,\n toClaudePluginScope,\n} from \"../lib/plugins/index.js\";\nimport {\n deleteLocalSkill,\n migrateLocalSkillScope,\n unresolvedSkillRemovalReasons,\n} from \"../lib/skills/index.js\";\nimport type {\n SkillId,\n SkillConfig,\n AgentName,\n AgentScopeConfig,\n ProjectConfig,\n SkillScope,\n} from \"../types/index.js\";\nimport { claudePluginInstall, claudePluginUninstall } from \"../utils/exec.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { remove } from \"../utils/fs.js\";\nimport { type StartupMessage } from \"../utils/logger.js\";\nimport {\n ERROR_MESSAGES,\n INFO_MESSAGES,\n STATUS_MESSAGES,\n recompileSummary,\n} from \"../utils/messages.js\";\nimport { formatScopeTag } from \"../lib/wizard/index.js\";\nimport { typedKeys } from \"../utils/typed-object.js\";\n\n/** A scope transition (`from` → `to`) for a re-scoped skill or agent. */\ntype ScopeChange = { from: SkillScope; to: SkillScope };\n\n/**\n * The noun `edit`'s recompile summary counts in. `edit` recompiles every scope this\n * context owns in one pass, so it has no scope word to qualify with — `compile`,\n * which runs one scope at a time, does.\n */\nconst RECOMPILE_SUBJECT = \"agents\";\n\n/**\n * Dual-scope add/remove: the project half of a [P][G] pair was toggled while the\n * global half persists. Reported as a project-scope addition/removal; a\n * scope-change arrow line would falsely claim the global install moved.\n */\nfunction formatDualScopeTransition(displayName: string, to: SkillScope): string {\n const isAdd = to === \"project\";\n const prefix = isAdd ? \"+\" : \"-\";\n const color = isAdd ? CLI_COLORS.SUCCESS : CLI_COLORS.ERROR;\n return chalk.hex(color)(` ${prefix} ${displayName} [P]`);\n}\n\n/**\n * One re-scoped skill's line. A dual-scope toggle is the transition above rather than a\n * migration; a genuine `[G] → [P]` reads as an addition because the skill arrives in this\n * project, and every other direction is the amber `~` a move is written with.\n */\nfunction formatSkillScopeChangeLine(\n skillId: SkillId,\n change: ScopeChange,\n dualScopeSkillTransitions: ReadonlySet<SkillId>,\n): string {\n const displayName = getSkillDisplayName(skillId);\n if (dualScopeSkillTransitions.has(skillId)) {\n return formatDualScopeTransition(displayName, change.to);\n }\n\n const isGlobalToProject = change.from === \"global\" && change.to === \"project\";\n const prefix = isGlobalToProject ? \"+\" : \"~\";\n const color = isGlobalToProject ? CLI_COLORS.SUCCESS : CLI_COLORS.WARNING;\n return (\n chalk.hex(color)(` ${prefix} ${displayName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(scopeArrow(change))\n );\n}\n\n/**\n * The agent mirror of the line above, with two differences preserved from how this summary has\n * always read: there is no `[G] → [P]`-reads-as-addition arm — an agent that moves is a move —\n * and only the dual-scope arm carries the `(agent)` suffix, since a `~` line names no skill it\n * could be confused with.\n */\nfunction formatAgentScopeChangeLine(\n agentName: AgentName,\n change: ScopeChange,\n dualScopeAgentTransitions: ReadonlySet<AgentName>,\n): string {\n const agentSuffix = chalk.hex(CLI_COLORS.NEUTRAL)(\" (agent)\");\n if (dualScopeAgentTransitions.has(agentName)) {\n return formatDualScopeTransition(agentName, change.to) + agentSuffix;\n }\n\n return (\n chalk.hex(CLI_COLORS.WARNING)(` ~ ${agentName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(scopeArrow(change))\n );\n}\n\n/** The ` ([P] → [G])` half both lines above end with, in the tags the wizard writes scopes as. */\nfunction scopeArrow(change: ScopeChange): string {\n return ` (${formatScopeTag(change.from)} \\u2192 ${formatScopeTag(change.to)})`;\n}\n\n/**\n * The name this session's catalogue answers to — what a marketplace-dropped entry's removal\n * reason says the skill is not present in. The resolved marketplace where there is one,\n * otherwise the source string itself, which is what an installation pointed at a source that\n * never carried the skill has to be named by.\n */\nfunction loadedSourceLabel(sourceResult: SourceLoadResult): string {\n return sourceResult.marketplace ?? sourceResult.sourceConfig.source;\n}\n\n/** @internal Re-exported for testing — the transform itself lives inside the gate. */\nexport { applyMigratedGlobalSources };\n\ntype EditContext = {\n installation: Installation;\n projectConfig: ProjectConfig | null;\n projectDir: string;\n sourceResult: SourceLoadResult;\n startupMessages: StartupMessage[];\n currentSkillIds: SkillId[];\n};\n\nexport default class Edit extends BaseCommand {\n static summary = \"Edit skills in the plugin\";\n static description = \"Modify the currently installed skills via interactive wizard\";\n\n static examples = [\n {\n description: \"Open the edit wizard\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n ];\n\n static flags = {\n [EDIT_PROJECT_SETUP_FLAG]: Flags.boolean({\n description: \"Internal: this run continues an `init` project setup\",\n default: false,\n hidden: true,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Edit);\n const cwd = process.cwd();\n\n // Before anything renders: a config that cannot be read is recreated, not edited, and\n // refusing here is what keeps the refusal clean — past this point the wizard has already\n // copied skills and installed plugins by the time a config read fails.\n await this.ensureConfigReadable(cwd);\n\n const { unmount, clear: clearSpinner } = render(\n <Spinner label={STATUS_MESSAGES.LOADING_SKILLS} />,\n );\n const context = await this.loadContext();\n clearSpinner();\n unmount();\n\n // Still before anything renders, one layer below the config itself: an entry whose skill\n // IS installed and whose metadata.yaml describes it no longer would otherwise be dropped\n // from config.ts on the way out, over a file this refusal asks to be repaired instead.\n await this.ensureSavedSkillsReadable(\n context.projectConfig?.skills ?? [],\n context.sourceResult.matrix,\n context.projectDir,\n );\n\n const result = await this.runEditWizard(context, cwd);\n if (!result) this.error(\"Cancelled\", { exit: EXIT_CODES.CANCELLED });\n\n this.reportValidationErrors(result.validation);\n\n // Filter excluded entries ONCE — downstream methods receive only active entries\n const activeNewSkills = result.skills.filter((s) => !s.excluded);\n const activeNewAgents = result.agentConfigs.filter((a) => !a.excluded);\n const activeOldSkills = (context.projectConfig?.skills ?? []).filter((s) => !s.excluded);\n const activeOldAgents = (context.projectConfig?.agents ?? []).filter((a) => !a.excluded);\n\n const filteredResult: WizardResultV2 = {\n ...result,\n skills: activeNewSkills,\n agentConfigs: activeNewAgents,\n };\n const filteredOldConfig: ProjectConfig | null = context.projectConfig\n ? { ...context.projectConfig, skills: activeOldSkills, agents: activeOldAgents }\n : null;\n\n const changes = detectConfigChanges(filteredOldConfig, filteredResult, {\n newSkills: result.skills,\n oldSkills: context.projectConfig?.skills ?? [],\n newAgents: result.agentConfigs,\n oldAgents: context.projectConfig?.agents ?? [],\n });\n // `cc init` inside a project means \"set this project up\", so the project must be\n // materialised — `<project>/.claude-src/config.ts` + `config-types.ts` written and the\n // path registered in the global `projects[]` — even when the wizard produced no roster\n // change. At the home root there is no project to set up: the global install is what the\n // dashboard was shown for, so a no-change pass there stays an inspection, as does every\n // bare `cc edit`.\n const isProjectSetup = flags[EDIT_PROJECT_SETUP_FLAG] && !isHomeDirectory(cwd);\n\n if (!hasAnyChanges(changes)) {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(\"No changes made.\"));\n if (!isProjectSetup) return;\n await this.writeConfigAndCompile(result, context, cwd);\n this.logCompletionSummary(changes);\n return;\n }\n\n const removalReasons = await unresolvedSkillRemovalReasons(\n result.unresolvableSkillIds,\n activeOldSkills,\n context.projectDir,\n loadedSourceLabel(context.sourceResult),\n );\n this.logChangeSummary(\n changes,\n filteredResult.skills,\n filteredOldConfig?.skills ?? [],\n removalReasons,\n );\n const migratedSkillIds = await this.applyMigrations(\n changes,\n filteredResult,\n activeOldSkills,\n context,\n cwd,\n );\n await this.recordGlobalSourceMigrations(migratedSkillIds, filteredResult.skills, cwd, context);\n await this.applyScopeChanges(changes, filteredResult, context, cwd);\n await this.applySourceChanges(changes, activeOldSkills, cwd, migratedSkillIds);\n await this.applyPluginChanges(changes, filteredResult, activeOldSkills, context, cwd);\n await this.copyNewLocalSkills(changes, filteredResult, context, cwd);\n await this.removeDeletedLocalSkills(changes, activeOldSkills, cwd);\n await this.writeConfigAndCompile(result, context, cwd);\n await this.cleanupStaleAgentFiles(changes, activeOldAgents, cwd);\n this.logCompletionSummary(changes);\n }\n\n private async loadContext(): Promise<EditContext> {\n const detected = await detectProject();\n if (!detected) {\n this.error(ERROR_MESSAGES.NO_INSTALLATION, {\n exit: EXIT_CODES.ERROR,\n });\n }\n const { installation, config: projectConfig } = detected;\n\n // Use installation.projectDir for reads (loading config, discovering installed skills).\n // Use cwd for writes (config saves, plugin installs, scope migrations, recompilation output)\n // and for the global-scope check (determining whether editing from global context).\n const projectDir = installation.projectDir;\n\n let sourceResult: SourceLoadResult;\n let startupMessages: StartupMessage[] = [];\n try {\n // No source is named here: `edit` reads the one the installation stored.\n const loaded = await loadSource({ projectDir, captureStartupMessages: true });\n sourceResult = loaded.sourceResult;\n startupMessages = loaded.startupMessages;\n\n const sourceInfo = sourceResult.isLocal ? \"local\" : sourceResult.sourceConfig.sourceOrigin;\n startupMessages.push({\n level: \"info\",\n text: `Loaded ${Object.keys(matrix.skills).length} skills (${sourceInfo})`,\n });\n } catch (error) {\n this.handleError(error);\n }\n\n let currentSkillIds: SkillId[];\n try {\n const discoveredSkills = await discoverAllPluginSkills(projectDir);\n const pluginSkillIds = typedKeys(discoveredSkills);\n\n // Merge plugin-discovered skills with config skills (catches local skills and\n // global-scoped plugins that discoverAllPluginSkills doesn't find).\n // Exclude skills marked as excluded — they should not appear as selected in the build step.\n // They are still preserved in skillConfigs via installedSkillConfigs for info panel/confirm step.\n const excludedConfigIds = new Set(\n projectConfig?.skills.filter((s) => s.excluded).map((s) => s.id) ?? [],\n );\n const configSkillIds =\n projectConfig?.skills.filter((s) => !s.excluded).map((s) => s.id) ?? [];\n const filteredPluginSkillIds = pluginSkillIds.filter((id) => !excludedConfigIds.has(id));\n const mergedIds = new Set<SkillId>([...filteredPluginSkillIds, ...configSkillIds]);\n currentSkillIds = [...mergedIds];\n\n startupMessages.push({\n level: \"info\",\n text: `Found ${currentSkillIds.length} installed skills`,\n });\n } catch (error) {\n this.handleError(error);\n }\n\n return {\n installation,\n projectConfig,\n projectDir,\n sourceResult,\n startupMessages,\n currentSkillIds,\n };\n }\n\n private async runEditWizard(context: EditContext, cwd: string): Promise<WizardResultV2 | null> {\n const { projectConfig, currentSkillIds } = context;\n const selectedAgents = projectConfig?.agents && activeAgentNames(projectConfig.agents);\n\n return runWizardSession({\n hydrate: {\n initialStep: \"build\",\n ...(projectConfig?.selectedDomains !== undefined && {\n initialDomains: projectConfig.selectedDomains,\n }),\n ...(selectedAgents !== undefined && { initialAgents: selectedAgents }),\n installedSkillIds: currentSkillIds,\n ...(projectConfig?.skills !== undefined && { installedSkillConfigs: projectConfig.skills }),\n ...(projectConfig?.agents !== undefined && { installedAgentConfigs: projectConfig.agents }),\n isEditingFromGlobalScope: isHomeDirectory(cwd),\n },\n props: {\n version: this.config.version,\n initialAgents: selectedAgents,\n installedSkillIds: currentSkillIds,\n startupMessages: context.startupMessages,\n },\n onCancel: () => this.log(\"\\nEdit cancelled\"),\n clearTerminal: () => this.clearTerminal(),\n });\n }\n\n /**\n * Records, in the GLOBAL config, the install-mode migrations this run already performed\n * under `$HOME`.\n *\n * A project-context edit otherwise never writes global config (commit 403df46, \"never\n * modify global config from project-level operations\"), and `authoritativeScope: \"owned\"`\n * enforces that for the roster — an inherited global-active entry is read-only, so\n * `mergeGlobalConfigs` preserves it verbatim. That protection is correct for selection and\n * scope, but `executeMigration` resolves each skill's paths from ITS OWN scope: switching a\n * global-scoped skill's source has already copied it under `$HOME` (or deleted it) and\n * added/removed its user-scope plugin registration by the time the config is written.\n * Leaving the global config alone there protects nothing — it only makes the recorded\n * source contradict the filesystem and the plugin registry.\n *\n * So authority follows the work actually performed, and no further: only ids\n * `executeMigration` acted on this run are rewritten, and only their `source` field. Global\n * entries this session merely displayed, re-scoped or deselected are untouched, as are\n * `marketplace`, `stack`, `agents` and every other registered project's view of them.\n * Refusing the switch instead is not an option — driving a global-scope migration from a\n * project directory is a supported flow (`scope-aware-local-copy` lifecycle tests).\n *\n * Runs BEFORE `writeConfigAndCompile`, so the global config written here is the one\n * the wizard write reloads, keeps (existing wins in `mergeGlobalConfigs`) and inlines\n * into the project config — both files then tell the same story. That second write\n * classifies as a no-op against what this one left on disk, so the fan-out below\n * happens once.\n *\n * The migrated `source` decides the reference form a compiled agent emits, so every\n * OTHER registered project's config and agents are stale until this write fans out —\n * which is why it goes through the gate rather than straight to the file.\n */\n private async recordGlobalSourceMigrations(\n migratedSkillIds: Set<SkillId>,\n newSkills: SkillConfig[],\n cwd: string,\n context: EditContext,\n ): Promise<void> {\n // A global-context edit writes the whole global config from the wizard result already.\n if (isHomeDirectory(cwd)) return;\n\n const migratedSources = new Map(\n newSkills\n .filter((s) => migratedSkillIds.has(s.id) && isActiveAt(s, \"global\"))\n .map((s) => [s.id, s.source] as const),\n );\n if (migratedSources.size === 0) return;\n\n try {\n const report = await mutateGlobal(\n { kind: \"migrate-skill-sources\", sources: migratedSources },\n {\n // The deps contract in config-gate/deps.ts declares\n // `() => Promise<MergedSkillsMatrix>`; this caller happens to have its\n // matrix in hand already.\n // eslint-disable-next-line @typescript-eslint/require-await -- deps contract\n loadMatrix: async () => context.sourceResult.matrix,\n loadAgents: async () => (await loadAgentDefs({ projectDir: cwd })).agents,\n },\n );\n this.reportPropagatedRecompile(report);\n } catch (error) {\n this.warn(`Could not record global source change: ${getErrorMessage(error)}`);\n }\n }\n\n private logChangeSummary(\n changes: ConfigChanges,\n newSkills: SkillConfig[],\n oldSkills: SkillConfig[],\n removalReasons: ReadonlyMap<SkillId, string>,\n ): void {\n const {\n addedSkills,\n removedSkills,\n addedAgents,\n removedAgents,\n sourceChanges,\n scopeChanges,\n agentScopeChanges,\n dualScopeSkillTransitions,\n dualScopeAgentTransitions,\n } = changes;\n\n this.log(`\\n${chalk.hex(CLI_COLORS.WHITE).bold(\"Changes:\")}`);\n for (const skillId of addedSkills) {\n const scope = newSkills.find((s) => s.id === skillId)?.scope;\n const scopeLabel = scope ? ` ${formatScopeTag(scope)}` : \"\";\n this.log(\n chalk.hex(CLI_COLORS.SUCCESS)(` + ${getSkillById(skillId).displayName}${scopeLabel}`),\n );\n }\n for (const skillId of removedSkills) {\n const scope = oldSkills.find((s) => s.id === skillId)?.scope;\n const scopeLabel = scope ? ` ${formatScopeTag(scope)}` : \"\";\n const reason = removalReasons.get(skillId);\n this.log(\n chalk.hex(CLI_COLORS.ERROR)(` - ${getSkillDisplayName(skillId)}${scopeLabel}`) +\n (reason ? chalk.hex(CLI_COLORS.NEUTRAL)(` (${reason})`) : \"\"),\n );\n }\n for (const agentName of addedAgents) {\n this.log(\n chalk.hex(CLI_COLORS.SUCCESS)(` + ${agentName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(\" (agent)\"),\n );\n }\n for (const agentName of removedAgents) {\n this.log(\n chalk.hex(CLI_COLORS.ERROR)(` - ${agentName}`) + chalk.hex(CLI_COLORS.NEUTRAL)(\" (agent)\"),\n );\n }\n for (const [skillId, change] of sourceChanges) {\n const displayName = getSkillDisplayName(skillId);\n const fromLabel = formatSourceDisplayName(change.from);\n const toLabel = formatSourceDisplayName(change.to);\n this.log(\n chalk.hex(CLI_COLORS.WARNING)(` ~ ${displayName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(` (${fromLabel} \\u2192 ${toLabel})`),\n );\n }\n for (const [skillId, change] of scopeChanges) {\n this.log(formatSkillScopeChangeLine(skillId, change, dualScopeSkillTransitions));\n }\n for (const [agentName, change] of agentScopeChanges) {\n this.log(formatAgentScopeChangeLine(agentName, change, dualScopeAgentTransitions));\n }\n this.log(\"\");\n }\n\n private async applyMigrations(\n _changes: ConfigChanges,\n filteredResult: WizardResultV2,\n activeOldSkills: SkillConfig[],\n context: EditContext,\n cwd: string,\n ): Promise<Set<SkillId>> {\n const migrationPlan = detectMigrations(activeOldSkills, filteredResult.skills);\n const migratedSkillIds = new Set([\n ...migrationPlan.toEject.map((m) => m.id),\n ...migrationPlan.toPlugin.map((m) => m.id),\n ]);\n if (migratedSkillIds.size === 0) return migratedSkillIds;\n\n if (migrationPlan.toEject.length > 0) {\n this.logModeSwitch(migrationPlan.toEject.length, INSTALL_MODE_DESCRIPTIONS.eject);\n }\n if (migrationPlan.toPlugin.length > 0) {\n this.logModeSwitch(migrationPlan.toPlugin.length, INSTALL_MODE_DESCRIPTIONS.plugin);\n // Installing a plugin needs the marketplace REGISTERED and up to date with the\n // Claude CLI — the same precondition `applyPluginChanges` and `applyScopeChanges`\n // establish. Without it `claude plugin install` rejects every ref against a stale\n // local copy. Runs before `executeMigration` so an unresolvable marketplace exits\n // while the ejected working copies are still intact. Eject-side plugin uninstalls\n // are diagnostic-only, so only plugin-install work demands this.\n await this.requireMarketplaceOrExit(context.sourceResult, \"migrate skills to plugin mode\");\n // The install itself happens inside `executeMigration`, which deletes each skill's\n // working copy the moment that skill's plugin is registered — so the banner is\n // announced here and the outcome reported below, through the same surface `init`\n // and the newly-added-skill path narrate an install with.\n this.announcePluginInstall();\n }\n\n const migrationResult = await executeMigration(migrationPlan, cwd, context.sourceResult);\n\n for (const warning of migrationResult.warnings) {\n this.warn(warning);\n }\n\n // Reports what was installed and hard-errors on any failure: a migration whose\n // plugin could not be installed must not reach `recordGlobalSourceMigrations` or\n // `writeConfigAndCompile`, either of which would persist a marketplace `source`\n // for a skill with no plugin registration.\n if (migrationPlan.toPlugin.length > 0) {\n this.reportPluginInstalls(migrationResult.pluginInstalls);\n }\n\n return migratedSkillIds;\n }\n\n /** Names what this run is switching, in the words `init` describes an install mode with. */\n private logModeSwitch(count: number, modeDescription: string): void {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(`Switching ${count} skill(s) to ${modeDescription}`));\n }\n\n private async applyScopeChanges(\n changes: ConfigChanges,\n filteredResult: WizardResultV2,\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n const { scopeChanges } = changes;\n\n // Handle scope migrations (P->G or G->P) for eject-mode skills\n for (const [skillId, change] of scopeChanges) {\n const skillConfig = filteredResult.skills.find((s) => s.id === skillId);\n if (skillConfig?.source === EJECT_SOURCE) {\n await migrateLocalSkillScope(skillId, change.from, cwd);\n }\n }\n\n // Plugin scope migrations require a marketplace.\n // Compute eligible migrations first; only resolve/demand marketplace when there are any.\n const hasPluginScopeChanges = [...scopeChanges.keys()].some((skillId) => {\n const skillConfig = filteredResult.skills.find((s) => s.id === skillId);\n return skillConfig && skillConfig.source !== EJECT_SOURCE;\n });\n if (!hasPluginScopeChanges) return;\n\n const marketplace = await this.requireMarketplaceOrExit(\n context.sourceResult,\n \"migrate plugin skill scopes\",\n );\n\n const pluginScopeResult = await migratePluginSkillScopes(\n scopeChanges,\n filteredResult.skills,\n marketplace,\n cwd,\n );\n for (const item of pluginScopeResult.failed) {\n this.warn(`Failed to migrate plugin scope for ${item.id}: ${item.error}`);\n }\n }\n\n private async applySourceChanges(\n changes: ConfigChanges,\n activeOldSkills: SkillConfig[],\n cwd: string,\n migratedSkillIds: Set<SkillId>,\n ): Promise<void> {\n const { sourceChanges } = changes;\n\n // Handle remaining non-migration source changes (e.g., marketplace A -> marketplace B)\n for (const [skillId, change] of sourceChanges) {\n // Skip skills already handled by mode migration\n if (migratedSkillIds.has(skillId)) {\n continue;\n }\n if (change.from === EJECT_SOURCE) {\n const oldSkill = activeOldSkills.find((s) => s.id === skillId);\n const deleteDir = installBaseDir(cwd, oldSkill?.scope);\n await deleteLocalSkill(deleteDir, skillId);\n }\n }\n }\n\n private async applyPluginChanges(\n changes: ConfigChanges,\n filteredResult: WizardResultV2,\n activeOldSkills: SkillConfig[],\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n const { addedSkills, removedSkills } = changes;\n\n // Compute plugin-intent lists per-skill (ungated) — per-skill `source` drives install mode.\n const addedPluginSkills = filteredResult.skills.filter(\n (s) => addedSkills.includes(s.id) && s.source !== EJECT_SOURCE,\n );\n const removedPluginSkills = removedSkills.filter(\n (id) => activeOldSkills.find((s) => s.id === id)?.source !== EJECT_SOURCE,\n );\n\n if (addedPluginSkills.length === 0 && removedPluginSkills.length === 0) return;\n\n const marketplace = await this.requireMarketplaceOrExit(\n context.sourceResult,\n \"install or uninstall plugin skills\",\n );\n\n if (addedPluginSkills.length > 0) {\n await this.installPluginSkillsReported(addedPluginSkills, marketplace, cwd);\n }\n\n if (removedPluginSkills.length > 0) {\n const uninstallResult = await uninstallPluginSkills(\n removedPluginSkills,\n activeOldSkills,\n marketplace,\n cwd,\n );\n if (uninstallResult.uninstalled.length > 0) {\n this.log(\n chalk.hex(CLI_COLORS.NEUTRAL)(`Removed ${uninstallResult.uninstalled.length} plugin(s)`),\n );\n }\n for (const item of uninstallResult.failed) {\n this.warn(`Failed to uninstall plugin ${item.id}: ${item.error}`);\n }\n }\n }\n\n private async copyNewLocalSkills(\n changes: ConfigChanges,\n filteredResult: WizardResultV2,\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n const { addedSkills } = changes;\n\n // Copy newly added local-source skills to .claude/skills/ (split by scope)\n const addedLocalSkills = filteredResult.skills.filter(\n (s) => addedSkills.includes(s.id) && s.source === EJECT_SOURCE,\n );\n\n if (addedLocalSkills.length > 0) {\n const copyResult = await copyLocalSkills(addedLocalSkills, cwd, context.sourceResult);\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(`Copied ${copyResult.totalCopied} local skill(s)`));\n }\n }\n\n private async removeDeletedLocalSkills(\n changes: ConfigChanges,\n activeOldSkills: SkillConfig[],\n cwd: string,\n ): Promise<void> {\n const { removedSkills } = changes;\n\n // A fully-deselected eject-mode skill is a genuine uninstall — its copied directory under\n // .claude/skills/<id>/ must be removed from the scope it was installed at (D-233). Plugin\n // removals are handled by applyPluginChanges; source-change (eject->marketplace) deletions by\n // applySourceChanges. deleteLocalSkill is a no-op when the directory is absent.\n for (const skillId of removedSkills) {\n const oldSkill = activeOldSkills.find((s) => s.id === skillId);\n if (oldSkill?.source !== EJECT_SOURCE) continue;\n\n const deleteDir = installBaseDir(cwd, oldSkill.scope);\n await deleteLocalSkill(deleteDir, skillId);\n }\n }\n\n private async writeConfigAndCompile(\n result: WizardResultV2,\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n // Load agent definitions — needed for both config-types.ts and recompilation\n let agentDefsResult: AgentDefs;\n try {\n agentDefsResult = await loadAgentDefs({});\n } catch (error) {\n this.handleError(error);\n }\n\n // Persist wizard result to config.ts and config-types.ts (split by scope when in project context)\n let configResult: ConfigWriteResult | undefined;\n try {\n configResult = await writeProjectConfig({\n wizardResult: result,\n sourceResult: context.sourceResult,\n projectDir: cwd,\n agents: agentDefsResult.agents,\n // A full `cc edit` pass is authoritative over the roster it owns, so deselected entries\n // are removed rather than union-preserved (D-233 Scenario C). Global-context edit owns\n // the entire config (\"all\"); a project edit owns only project-scoped entries and its own\n // tombstones (\"owned\"), never inherited global-active entries.\n authoritativeScope: isHomeDirectory(cwd) ? \"all\" : \"owned\",\n });\n } catch (error) {\n this.warn(`Could not update config: ${getErrorMessage(error)}`);\n }\n\n try {\n const agentScopeMap = activeAgentScopeMap(result.agentConfigs);\n const { allSkills } = await discoverInstalledSkills(cwd);\n const compilationResult = await compileAgentsAllScopes({\n projectDir: cwd,\n sourcePath: agentDefsResult.sourcePath,\n skills: allSkills,\n agentScopeMap,\n });\n\n const { compiled, rewritten, failed, warnings } = compilationResult;\n const summary = recompileSummary(\n rewritten.length,\n compiled.length - rewritten.length,\n RECOMPILE_SUBJECT,\n );\n\n if (failed.length > 0) {\n this.log(\n chalk.hex(CLI_COLORS.NEUTRAL)(summary) +\n chalk.hex(CLI_COLORS.WARNING)(` (${failed.length} failed)`),\n );\n for (const warning of warnings) {\n this.warn(warning);\n }\n } else if (compiled.length > 0) {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(summary));\n } else {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(INFO_MESSAGES.NO_AGENTS_TO_RECOMPILE));\n }\n } catch (error) {\n this.warn(`Agent recompilation failed: ${getErrorMessage(error)}`);\n this.log(`You can manually recompile with '${CLI_INVOKE_COMMAND} compile'.`);\n }\n\n if (configResult) {\n this.reportPropagatedRecompile(configResult.propagation);\n }\n }\n\n private async cleanupStaleAgentFiles(\n changes: ConfigChanges,\n oldAgents: AgentScopeConfig[],\n cwd: string,\n ): Promise<void> {\n const { agentScopeChanges, removedAgents } = changes;\n\n // Clean up old agent .md files after scope changes.\n // Recompilation wrote the new file to the correct scope directory;\n // now delete the stale copy from the old scope directory.\n // Only clean up for P→G direction. G→P is an override — the global\n // installation stays untouched; the project copy overrides it.\n for (const [agentName, change] of agentScopeChanges) {\n if (change.from === \"global\") continue;\n\n const oldAgentPath = path.join(\n resolveInstallPaths(cwd, \"project\").agentsDir,\n `${agentName}.md`,\n );\n try {\n await remove(oldAgentPath);\n } catch (error) {\n this.warn(`Could not remove old agent file ${oldAgentPath}: ${getErrorMessage(error)}`);\n }\n }\n\n // Deselected agents are a genuine uninstall — recompilation never rewrites their .md, so\n // delete the compiled file from the scope it was installed at (D-233). remove() is a no-op\n // when the file is absent.\n for (const agentName of removedAgents) {\n const oldScope = oldAgents.find((a) => a.name === agentName)?.scope ?? \"project\";\n const agentPath = path.join(resolveInstallPaths(cwd, oldScope).agentsDir, `${agentName}.md`);\n try {\n await remove(agentPath);\n } catch (error) {\n this.warn(`Could not remove agent file ${agentPath}: ${getErrorMessage(error)}`);\n }\n }\n }\n\n private logCompletionSummary(_changes: ConfigChanges): void {\n this.log(`\\n${chalk.hex(CLI_COLORS.SUCCESS)(\"\\u2713 Done\")}\\n`);\n }\n}\n\n/** @internal Exported for testing */\nexport type ConfigChanges = {\n addedSkills: SkillId[];\n removedSkills: SkillId[];\n addedAgents: AgentName[];\n removedAgents: AgentName[];\n sourceChanges: Map<SkillId, { from: string; to: string }>;\n scopeChanges: Map<SkillId, ScopeChange>;\n agentScopeChanges: Map<AgentName, ScopeChange>;\n /**\n * Skill ids whose `scopeChanges` entry is a dual-scope add/remove — the project\n * half of a `[P][G]` pair was toggled while the global half persists — NOT a true\n * single-entry migration. The disk-side scope work still flows through\n * `scopeChanges`; this set only steers the completion-summary display so a\n * dual-scope addition is not misreported as a `[G] → [P]` migration.\n */\n dualScopeSkillTransitions: Set<SkillId>;\n /** Agent equivalent of `dualScopeSkillTransitions`. */\n dualScopeAgentTransitions: Set<AgentName>;\n};\n\n/** Full (tombstone-inclusive) entry lists used to classify dual-scope transitions. */\ntype FullScopeEntries = {\n newSkills: SkillConfig[];\n oldSkills: SkillConfig[];\n newAgents: AgentScopeConfig[];\n oldAgents: AgentScopeConfig[];\n};\n\n/**\n * @internal Exported for testing\n *\n * `oldConfig` / `wizardResult` carry the ACTIVE (tombstone-filtered) entries used\n * for add/remove/source/scope diffing. `fullEntries`, when provided, carries the\n * unfiltered lists (including excluded tombstones) used ONLY to tell a genuine\n * scope migration apart from a dual-scope add/remove. When omitted, every scope\n * change is treated as a migration (the pre-dual-scope behaviour).\n */\nexport function detectConfigChanges(\n oldConfig: ProjectConfig | null,\n wizardResult: WizardResultV2,\n fullEntries?: FullScopeEntries,\n): ConfigChanges {\n const oldSkillIds = oldConfig?.skills.map((s) => s.id) ?? [];\n const newSkillIds = wizardResult.skills.map((s) => s.id);\n const oldAgentNames = oldConfig?.agents.map((a) => a.name) ?? [];\n const newAgentNames = wizardResult.agentConfigs.map((a) => a.name);\n\n const oldSkillsById = indexBy(oldConfig?.skills ?? [], (s) => s.id);\n const oldAgentsByName = indexBy(oldConfig?.agents ?? [], (a) => a.name);\n\n const scopeChanges = detectPropertyChanges(\n wizardResult.skills,\n oldSkillsById,\n (s) => s.id,\n (s) => s.scope,\n );\n const agentScopeChanges = detectPropertyChanges(\n wizardResult.agentConfigs,\n oldAgentsByName,\n (a) => a.name,\n (a) => a.scope,\n );\n\n return {\n addedSkills: difference(newSkillIds, oldSkillIds),\n removedSkills: difference(oldSkillIds, newSkillIds),\n addedAgents: difference(newAgentNames, oldAgentNames),\n removedAgents: difference(oldAgentNames, newAgentNames),\n sourceChanges: detectPropertyChanges(\n wizardResult.skills,\n oldSkillsById,\n (s) => s.id,\n (s) => s.source,\n ),\n scopeChanges,\n agentScopeChanges,\n dualScopeSkillTransitions: detectDualScopeTransitions(\n scopeChanges,\n fullEntries?.newSkills ?? [],\n fullEntries?.oldSkills ?? [],\n (s) => s.id,\n ),\n dualScopeAgentTransitions: detectDualScopeTransitions(\n agentScopeChanges,\n fullEntries?.newAgents ?? [],\n fullEntries?.oldAgents ?? [],\n (a) => a.name,\n ),\n };\n}\n\nfunction detectPropertyChanges<T, K extends string, V>(\n newItems: T[],\n oldByKey: Record<string, T>,\n getKey: (item: T) => K,\n getValue: (item: T) => V,\n): Map<K, { from: V; to: V }> {\n const changes = new Map<K, { from: V; to: V }>();\n for (const item of newItems) {\n const key = getKey(item);\n const old = oldByKey[key];\n if (old && getValue(old) !== getValue(item)) {\n changes.set(key, { from: getValue(old), to: getValue(item) });\n }\n }\n return changes;\n}\n\n/**\n * A scope change is a dual-scope transition (not a migration) when the canonical\n * dual-scope tombstone — an excluded global entry — sits alongside it:\n * - G→P add: the NEW state keeps a global tombstone, so the global install\n * survives and the project half was merely added.\n * - P→G remove: the OLD state held a global tombstone, so the pair was already\n * dual-scope and the project half was merely removed.\n * Either way the item occupied both scopes, so `[X] → [Y]` would misdescribe it.\n */\nfunction detectDualScopeTransitions<\n K extends string,\n T extends { scope: SkillScope; excluded?: boolean },\n>(scopeChanges: Map<K, ScopeChange>, fullNew: T[], fullOld: T[], getKey: (item: T) => K): Set<K> {\n const hasGlobalTombstone = (items: T[], key: K): boolean =>\n items.some((item) => getKey(item) === key && item.scope === \"global\" && item.excluded === true);\n\n const result = new Set<K>();\n for (const [key, change] of scopeChanges) {\n if (change.from === \"global\" && change.to === \"project\" && hasGlobalTombstone(fullNew, key)) {\n result.add(key);\n } else if (\n change.from === \"project\" &&\n change.to === \"global\" &&\n hasGlobalTombstone(fullOld, key)\n ) {\n result.add(key);\n }\n }\n return result;\n}\n\nfunction hasAnyChanges(changes: ConfigChanges): boolean {\n return (\n changes.addedSkills.length > 0 ||\n changes.removedSkills.length > 0 ||\n changes.addedAgents.length > 0 ||\n changes.removedAgents.length > 0 ||\n changes.sourceChanges.size > 0 ||\n changes.scopeChanges.size > 0 ||\n changes.agentScopeChanges.size > 0\n );\n}\n\n/** @internal Exported for testing */\nexport type PluginScopeMigrationResult = {\n migrated: SkillId[];\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/** @internal Exported for testing */\nexport async function migratePluginSkillScopes(\n scopeChanges: Map<SkillId, ScopeChange>,\n skills: Pick<SkillConfig, \"id\" | \"source\">[],\n marketplace: string,\n projectDir: string,\n): Promise<PluginScopeMigrationResult> {\n const migrated: SkillId[] = [];\n const failed: PluginScopeMigrationResult[\"failed\"] = [];\n\n for (const [skillId, change] of scopeChanges) {\n const skillConfig = skills.find((s) => s.id === skillId);\n if (!skillConfig || skillConfig.source === EJECT_SOURCE) {\n continue;\n }\n\n const newPluginScope = toClaudePluginScope(change.to);\n const pluginRef = buildMarketplacePluginRef(skillId, marketplace);\n\n try {\n // global→project: keep the global registration, just add project scope.\n // The global plugin must remain for other projects.\n // project→global: uninstall the project-scope registration, install global.\n if (change.from === \"project\") {\n await claudePluginUninstall(pluginRef, \"project\", projectDir);\n }\n await claudePluginInstall(pluginRef, newPluginScope, projectDir);\n migrated.push(skillId);\n } catch (error) {\n failed.push({ id: skillId, error: getErrorMessage(error) });\n }\n }\n\n return { migrated, failed };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/commands/edit.tsx"],"sourcesContent":["import path from \"path\";\n\nimport chalk from \"chalk\";\nimport { Flags } from \"@oclif/core\";\nimport { render } from \"../components/render.js\";\n\nimport { difference, indexBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { type WizardResultV2 } from \"../components/wizard/wizard.js\";\nimport { runWizardSession } from \"../components/wizard/run-wizard-session.js\";\nimport {\n CLI_INVOKE_COMMAND,\n CLI_COLORS,\n EDIT_PROJECT_SETUP_FLAG,\n EJECT_SOURCE,\n formatSourceDisplayName,\n} from \"../consts.js\";\nimport {\n detectProject,\n loadSource,\n copyLocalSkills,\n uninstallPluginSkills,\n loadAgentDefs,\n type AgentDefs,\n writeProjectConfig,\n type ConfigWriteResult,\n compileAgentsAllScopes,\n discoverInstalledSkills,\n removeCompiledAgents,\n type RemoveCompiledAgentsOptions,\n} from \"../lib/operations/index.js\";\nimport { Spinner } from \"../components/common/spinner.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport {\n type Installation,\n detectMigrations,\n executeMigration,\n isHomeDirectory,\n installBaseDir,\n resolveInstallPaths,\n INSTALL_MODE_DESCRIPTIONS,\n} from \"../lib/installation/index.js\";\nimport { applyMigratedGlobalSources, mutateGlobal } from \"../lib/config-gate/index.js\";\nimport { matrix, getSkillById, getSkillDisplayName } from \"../lib/matrix/matrix-provider\";\nimport {\n activeAgentNames,\n activeAgentScopeMap,\n isActiveAt,\n} from \"../lib/configuration/scope-predicates.js\";\nimport type { SourceLoadResult } from \"../lib/loading/index.js\";\nimport {\n discoverAllPluginSkills,\n buildMarketplacePluginRef,\n toClaudePluginScope,\n} from \"../lib/plugins/index.js\";\nimport {\n deleteLocalSkill,\n migrateLocalSkillScope,\n unresolvedSkillRemovalReasons,\n} from \"../lib/skills/index.js\";\nimport type {\n SkillId,\n SkillConfig,\n AgentName,\n AgentScopeConfig,\n ProjectConfig,\n SkillScope,\n} from \"../types/index.js\";\nimport { claudePluginInstall, claudePluginUninstall } from \"../utils/exec.js\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { type StartupMessage } from \"../utils/logger.js\";\nimport {\n ERROR_MESSAGES,\n INFO_MESSAGES,\n STATUS_MESSAGES,\n localSkillsCopied,\n recompileSummary,\n} from \"../utils/messages.js\";\nimport { formatScopeTag } from \"../lib/wizard/index.js\";\nimport { typedKeys } from \"../utils/typed-object.js\";\n\n/** A scope transition (`from` → `to`) for a re-scoped skill or agent. */\ntype ScopeChange = { from: SkillScope; to: SkillScope };\n\n/**\n * The noun `edit`'s recompile summary counts in. `edit` recompiles every scope this\n * context owns in one pass, so it has no scope word to qualify with — `compile`,\n * which runs one scope at a time, does.\n */\nconst RECOMPILE_SUBJECT = \"agents\";\n\n/**\n * Dual-scope add/remove: the project half of a [P][G] pair was toggled while the\n * global half persists. Reported as a project-scope addition/removal; a\n * scope-change arrow line would falsely claim the global install moved.\n */\nfunction formatDualScopeTransition(displayName: string, to: SkillScope): string {\n const isAdd = to === \"project\";\n const prefix = isAdd ? \"+\" : \"-\";\n const color = isAdd ? CLI_COLORS.SUCCESS : CLI_COLORS.ERROR;\n return chalk.hex(color)(` ${prefix} ${displayName} [P]`);\n}\n\n/**\n * One re-scoped skill's line. A dual-scope toggle is the transition above rather than a\n * migration; a genuine `[G] → [P]` reads as an addition because the skill arrives in this\n * project, and every other direction is the amber `~` a move is written with.\n */\nfunction formatSkillScopeChangeLine(\n skillId: SkillId,\n change: ScopeChange,\n dualScopeSkillTransitions: ReadonlySet<SkillId>,\n): string {\n const displayName = getSkillDisplayName(skillId);\n if (dualScopeSkillTransitions.has(skillId)) {\n return formatDualScopeTransition(displayName, change.to);\n }\n\n const isGlobalToProject = change.from === \"global\" && change.to === \"project\";\n const prefix = isGlobalToProject ? \"+\" : \"~\";\n const color = isGlobalToProject ? CLI_COLORS.SUCCESS : CLI_COLORS.WARNING;\n return (\n chalk.hex(color)(` ${prefix} ${displayName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(scopeArrow(change))\n );\n}\n\n/**\n * The agent mirror of the line above, with two differences preserved from how this summary has\n * always read: there is no `[G] → [P]`-reads-as-addition arm — an agent that moves is a move —\n * and only the dual-scope arm carries the `(agent)` suffix, since a `~` line names no skill it\n * could be confused with.\n */\nfunction formatAgentScopeChangeLine(\n agentName: AgentName,\n change: ScopeChange,\n dualScopeAgentTransitions: ReadonlySet<AgentName>,\n): string {\n const agentSuffix = chalk.hex(CLI_COLORS.NEUTRAL)(\" (agent)\");\n if (dualScopeAgentTransitions.has(agentName)) {\n return formatDualScopeTransition(agentName, change.to) + agentSuffix;\n }\n\n return (\n chalk.hex(CLI_COLORS.WARNING)(` ~ ${agentName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(scopeArrow(change))\n );\n}\n\n/** The ` ([P] → [G])` half both lines above end with, in the tags the wizard writes scopes as. */\nfunction scopeArrow(change: ScopeChange): string {\n return ` (${formatScopeTag(change.from)} \\u2192 ${formatScopeTag(change.to)})`;\n}\n\n/**\n * The name this session's catalogue answers to — what a marketplace-dropped entry's removal\n * reason says the skill is not present in. The resolved marketplace where there is one,\n * otherwise the source string itself, which is what an installation pointed at a source that\n * never carried the skill has to be named by.\n */\nfunction loadedSourceLabel(sourceResult: SourceLoadResult): string {\n return sourceResult.marketplace ?? sourceResult.sourceConfig.source;\n}\n\n/** @internal Re-exported for testing — the transform itself lives inside the gate. */\nexport { applyMigratedGlobalSources };\n\ntype EditContext = {\n installation: Installation;\n projectConfig: ProjectConfig | null;\n projectDir: string;\n sourceResult: SourceLoadResult;\n startupMessages: StartupMessage[];\n currentSkillIds: SkillId[];\n};\n\nexport default class Edit extends BaseCommand {\n static summary = \"Edit skills in the plugin\";\n static description = \"Modify the currently installed skills via interactive wizard\";\n\n static examples = [\n {\n description: \"Open the edit wizard\",\n command: \"<%= config.bin %> <%= command.id %>\",\n },\n ];\n\n static flags = {\n [EDIT_PROJECT_SETUP_FLAG]: Flags.boolean({\n description: \"Internal: this run continues an `init` project setup\",\n default: false,\n hidden: true,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Edit);\n const cwd = process.cwd();\n\n // Before anything renders: a config that cannot be read is recreated, not edited, and\n // refusing here is what keeps the refusal clean — past this point the wizard has already\n // copied skills and installed plugins by the time a config read fails.\n await this.ensureConfigReadable(cwd);\n\n const context = await this.loadContextUnderSpinner();\n\n // Still before anything renders, one layer below the config itself: an entry whose skill\n // IS installed and whose metadata.yaml describes it no longer would otherwise be dropped\n // from config.ts on the way out, over a file this refusal asks to be repaired instead.\n await this.ensureSavedSkillsReadable(\n context.projectConfig?.skills ?? [],\n context.sourceResult.matrix,\n context.projectDir,\n );\n\n const result = await this.runEditWizard(context, cwd);\n if (!result) this.error(\"Cancelled\", { exit: EXIT_CODES.CANCELLED });\n\n this.reportValidationErrors(result.validation);\n\n // Filter excluded entries ONCE — downstream methods receive only active entries\n const activeNewSkills = result.skills.filter((s) => !s.excluded);\n const activeNewAgents = result.agentConfigs.filter((a) => !a.excluded);\n const activeOldSkills = (context.projectConfig?.skills ?? []).filter((s) => !s.excluded);\n const activeOldAgents = (context.projectConfig?.agents ?? []).filter((a) => !a.excluded);\n\n const filteredResult: WizardResultV2 = {\n ...result,\n skills: activeNewSkills,\n agentConfigs: activeNewAgents,\n };\n const filteredOldConfig: ProjectConfig | null = context.projectConfig\n ? { ...context.projectConfig, skills: activeOldSkills, agents: activeOldAgents }\n : null;\n\n const changes = detectConfigChanges(filteredOldConfig, filteredResult, {\n newSkills: result.skills,\n oldSkills: context.projectConfig?.skills ?? [],\n newAgents: result.agentConfigs,\n oldAgents: context.projectConfig?.agents ?? [],\n });\n // `cc init` inside a project means \"set this project up\", so the project must be\n // materialised — `<project>/.claude-src/config.ts` + `config-types.ts` written and the\n // path registered in the global `projects[]` — even when the wizard produced no roster\n // change. At the home root there is no project to set up: the global install is what the\n // dashboard was shown for, so a no-change pass there stays an inspection, as does every\n // bare `cc edit`.\n const isProjectSetup = flags[EDIT_PROJECT_SETUP_FLAG] && !isHomeDirectory(cwd);\n\n if (!hasAnyChanges(changes)) {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(\"No changes made.\"));\n if (!isProjectSetup) return;\n await this.writeConfigAndCompile(result, context, cwd);\n this.logCompletionSummary(changes);\n return;\n }\n\n const removalReasons = await unresolvedSkillRemovalReasons(\n result.unresolvableSkillIds,\n activeOldSkills,\n context.projectDir,\n loadedSourceLabel(context.sourceResult),\n );\n this.logChangeSummary(\n changes,\n filteredResult.skills,\n filteredOldConfig?.skills ?? [],\n removalReasons,\n );\n const migratedSkillIds = await this.applyMigrations(\n changes,\n filteredResult,\n activeOldSkills,\n context,\n cwd,\n );\n await this.recordGlobalSourceMigrations(migratedSkillIds, filteredResult.skills, cwd, context);\n await this.applyScopeChanges(changes, filteredResult, context, cwd);\n await this.applySourceChanges(changes, activeOldSkills, cwd, migratedSkillIds);\n await this.applyPluginChanges(changes, filteredResult, activeOldSkills, context, cwd);\n await this.copyNewLocalSkills(changes, filteredResult, context, cwd);\n await this.removeDeletedLocalSkills(changes, activeOldSkills, cwd);\n await this.writeConfigAndCompile(result, context, cwd);\n await this.cleanupStaleAgentFiles(changes, activeOldAgents, cwd);\n this.logCompletionSummary(changes);\n }\n\n /**\n * The load below, behind a spinner that comes down whichever way the await ends.\n *\n * The cleanup is a `finally` because all three of `loadContext`'s refusals are raised\n * while this spinner is mounted, and oclif would otherwise paint its error under an Ink\n * tree still repainting over it. Never a `catch`: the throw reaches oclif untouched, or\n * both the error rendering and the pinned exit codes change with it.\n */\n private async loadContextUnderSpinner(): Promise<EditContext> {\n const { unmount, clear: clearSpinner } = render(\n <Spinner label={STATUS_MESSAGES.LOADING_SKILLS} />,\n );\n try {\n return await this.loadContext();\n } finally {\n clearSpinner();\n unmount();\n }\n }\n\n private async loadContext(): Promise<EditContext> {\n const detected = await detectProject();\n if (!detected) {\n this.error(ERROR_MESSAGES.NO_INSTALLATION, {\n exit: EXIT_CODES.ERROR,\n });\n }\n const { installation, config: projectConfig } = detected;\n\n // Use installation.projectDir for reads (loading config, discovering installed skills).\n // Use cwd for writes (config saves, plugin installs, scope migrations, recompilation output)\n // and for the global-scope check (determining whether editing from global context).\n const projectDir = installation.projectDir;\n\n let sourceResult: SourceLoadResult;\n let startupMessages: StartupMessage[] = [];\n try {\n // No source is named here: `edit` reads the one the installation stored.\n const loaded = await loadSource({ projectDir, captureStartupMessages: true });\n sourceResult = loaded.sourceResult;\n startupMessages = loaded.startupMessages;\n\n const sourceInfo = sourceResult.isLocal ? \"local\" : sourceResult.sourceConfig.sourceOrigin;\n startupMessages.push({\n level: \"info\",\n text: `Loaded ${Object.keys(matrix.skills).length} skills (${sourceInfo})`,\n });\n } catch (error) {\n this.handleError(error);\n }\n\n let currentSkillIds: SkillId[];\n try {\n const discoveredSkills = await discoverAllPluginSkills(projectDir);\n const pluginSkillIds = typedKeys(discoveredSkills);\n\n // Merge plugin-discovered skills with config skills (catches local skills and\n // global-scoped plugins that discoverAllPluginSkills doesn't find).\n // Exclude skills marked as excluded — they should not appear as selected in the build step.\n // They are still preserved in skillConfigs via installedSkillConfigs for info panel/confirm step.\n const excludedConfigIds = new Set(\n projectConfig?.skills.filter((s) => s.excluded).map((s) => s.id) ?? [],\n );\n const configSkillIds =\n projectConfig?.skills.filter((s) => !s.excluded).map((s) => s.id) ?? [];\n const filteredPluginSkillIds = pluginSkillIds.filter((id) => !excludedConfigIds.has(id));\n const mergedIds = new Set<SkillId>([...filteredPluginSkillIds, ...configSkillIds]);\n currentSkillIds = [...mergedIds];\n\n startupMessages.push({\n level: \"info\",\n text: `Found ${currentSkillIds.length} installed skills`,\n });\n } catch (error) {\n this.handleError(error);\n }\n\n return {\n installation,\n projectConfig,\n projectDir,\n sourceResult,\n startupMessages,\n currentSkillIds,\n };\n }\n\n private async runEditWizard(context: EditContext, cwd: string): Promise<WizardResultV2 | null> {\n const { projectConfig, currentSkillIds } = context;\n const selectedAgents = projectConfig?.agents && activeAgentNames(projectConfig.agents);\n\n return runWizardSession({\n hydrate: {\n initialStep: \"build\",\n ...(projectConfig?.selectedDomains !== undefined && {\n initialDomains: projectConfig.selectedDomains,\n }),\n ...(selectedAgents !== undefined && { initialAgents: selectedAgents }),\n installedSkillIds: currentSkillIds,\n ...(projectConfig?.skills !== undefined && { installedSkillConfigs: projectConfig.skills }),\n ...(projectConfig?.agents !== undefined && { installedAgentConfigs: projectConfig.agents }),\n isEditingFromGlobalScope: isHomeDirectory(cwd),\n },\n props: {\n version: this.config.version,\n initialAgents: selectedAgents,\n installedSkillIds: currentSkillIds,\n startupMessages: context.startupMessages,\n },\n onCancel: () => this.log(\"\\nEdit cancelled\"),\n clearTerminal: () => this.clearTerminal(),\n });\n }\n\n /**\n * Records, in the GLOBAL config, the install-mode migrations this run already performed\n * under `$HOME`.\n *\n * A project-context edit otherwise never writes global config (commit 403df46, \"never\n * modify global config from project-level operations\"), and `authoritativeScope: \"owned\"`\n * enforces that for the roster — an inherited global-active entry is read-only, so\n * `mergeGlobalConfigs` preserves it verbatim. That protection is correct for selection and\n * scope, but `executeMigration` resolves each skill's paths from ITS OWN scope: switching a\n * global-scoped skill's source has already copied it under `$HOME` (or deleted it) and\n * added/removed its user-scope plugin registration by the time the config is written.\n * Leaving the global config alone there protects nothing — it only makes the recorded\n * source contradict the filesystem and the plugin registry.\n *\n * So authority follows the work actually performed, and no further: only ids\n * `executeMigration` acted on this run are rewritten, and only their `source` field. Global\n * entries this session merely displayed, re-scoped or deselected are untouched, as are\n * `marketplace`, `stack`, `agents` and every other registered project's view of them.\n *\n * Driving a global-scope migration from a project directory is NOT a supported flow, and this\n * method is no longer the thing that permits it. The wizard now refuses it at source: the two\n * bulk install-mode keys are withdrawn, and `setInstallMode` ignores a project-context call\n * against a global slot the hydration snapshot owns — the same authority the Sources grid\n * already enforced by rendering that row inert. What still reaches here is the residue that\n * authority leaves legitimate: a mode change committed on the project half of a `[P][G]` pair\n * and then carried to global scope by a P->G collapse (`s`) in the same session. The entry is\n * the project's own to configure at the moment it is configured, and global at the moment it\n * is written — so the migration is real, and the global config must record it.\n *\n * Runs BEFORE `writeConfigAndCompile`, so the global config written here is the one\n * the wizard write reloads, keeps (existing wins in `mergeGlobalConfigs`) and inlines\n * into the project config — both files then tell the same story. That second write\n * classifies as a no-op against what this one left on disk, so the fan-out below\n * happens once.\n *\n * The migrated `source` decides the reference form a compiled agent emits, so every\n * OTHER registered project's config and agents are stale until this write fans out —\n * which is why it goes through the gate rather than straight to the file.\n */\n private async recordGlobalSourceMigrations(\n migratedSkillIds: Set<SkillId>,\n newSkills: SkillConfig[],\n cwd: string,\n context: EditContext,\n ): Promise<void> {\n // A global-context edit writes the whole global config from the wizard result already.\n if (isHomeDirectory(cwd)) return;\n\n const migratedSources = new Map(\n newSkills\n .filter((s) => migratedSkillIds.has(s.id) && isActiveAt(s, \"global\"))\n .map((s) => [s.id, s.source] as const),\n );\n if (migratedSources.size === 0) return;\n\n try {\n const report = await mutateGlobal(\n { kind: \"migrate-skill-sources\", sources: migratedSources },\n {\n // The deps contract in config-gate/deps.ts declares\n // `() => Promise<MergedSkillsMatrix>`; this caller happens to have its\n // matrix in hand already.\n // eslint-disable-next-line @typescript-eslint/require-await -- deps contract\n loadMatrix: async () => context.sourceResult.matrix,\n loadAgents: async () => (await loadAgentDefs({ projectDir: cwd })).agents,\n },\n );\n this.reportPropagatedRecompile(report);\n } catch (error) {\n this.warn(`Could not record global source change: ${getErrorMessage(error)}`);\n }\n }\n\n private logChangeSummary(\n changes: ConfigChanges,\n newSkills: SkillConfig[],\n oldSkills: SkillConfig[],\n removalReasons: ReadonlyMap<SkillId, string>,\n ): void {\n const {\n addedSkills,\n removedSkills,\n addedAgents,\n removedAgents,\n sourceChanges,\n scopeChanges,\n agentScopeChanges,\n dualScopeSkillTransitions,\n dualScopeAgentTransitions,\n } = changes;\n\n this.log(`\\n${chalk.hex(CLI_COLORS.WHITE).bold(\"Changes:\")}`);\n for (const skillId of addedSkills) {\n const scope = newSkills.find((s) => s.id === skillId)?.scope;\n const scopeLabel = scope ? ` ${formatScopeTag(scope)}` : \"\";\n this.log(\n chalk.hex(CLI_COLORS.SUCCESS)(` + ${getSkillById(skillId).displayName}${scopeLabel}`),\n );\n }\n for (const skillId of removedSkills) {\n const scope = oldSkills.find((s) => s.id === skillId)?.scope;\n const scopeLabel = scope ? ` ${formatScopeTag(scope)}` : \"\";\n const reason = removalReasons.get(skillId);\n this.log(\n chalk.hex(CLI_COLORS.ERROR)(` - ${getSkillDisplayName(skillId)}${scopeLabel}`) +\n (reason ? chalk.hex(CLI_COLORS.NEUTRAL)(` (${reason})`) : \"\"),\n );\n }\n for (const agentName of addedAgents) {\n this.log(\n chalk.hex(CLI_COLORS.SUCCESS)(` + ${agentName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(\" (agent)\"),\n );\n }\n for (const agentName of removedAgents) {\n this.log(\n chalk.hex(CLI_COLORS.ERROR)(` - ${agentName}`) + chalk.hex(CLI_COLORS.NEUTRAL)(\" (agent)\"),\n );\n }\n for (const [skillId, change] of sourceChanges) {\n const displayName = getSkillDisplayName(skillId);\n const fromLabel = formatSourceDisplayName(change.from);\n const toLabel = formatSourceDisplayName(change.to);\n this.log(\n chalk.hex(CLI_COLORS.WARNING)(` ~ ${displayName}`) +\n chalk.hex(CLI_COLORS.NEUTRAL)(` (${fromLabel} \\u2192 ${toLabel})`),\n );\n }\n for (const [skillId, change] of scopeChanges) {\n this.log(formatSkillScopeChangeLine(skillId, change, dualScopeSkillTransitions));\n }\n for (const [agentName, change] of agentScopeChanges) {\n this.log(formatAgentScopeChangeLine(agentName, change, dualScopeAgentTransitions));\n }\n this.log(\"\");\n }\n\n private async applyMigrations(\n _changes: ConfigChanges,\n filteredResult: WizardResultV2,\n activeOldSkills: SkillConfig[],\n context: EditContext,\n cwd: string,\n ): Promise<Set<SkillId>> {\n const migrationPlan = detectMigrations(activeOldSkills, filteredResult.skills);\n const migratedSkillIds = new Set([\n ...migrationPlan.toEject.map((m) => m.id),\n ...migrationPlan.toPlugin.map((m) => m.id),\n ]);\n if (migratedSkillIds.size === 0) return migratedSkillIds;\n\n if (migrationPlan.toEject.length > 0) {\n this.logModeSwitch(migrationPlan.toEject.length, INSTALL_MODE_DESCRIPTIONS.eject);\n }\n if (migrationPlan.toPlugin.length > 0) {\n this.logModeSwitch(migrationPlan.toPlugin.length, INSTALL_MODE_DESCRIPTIONS.plugin);\n // Installing a plugin needs the marketplace REGISTERED and up to date with the\n // Claude CLI — the same precondition `applyPluginChanges` and `applyScopeChanges`\n // establish. Without it `claude plugin install` rejects every ref against a stale\n // local copy. Runs before `executeMigration` so an unresolvable marketplace exits\n // while the ejected working copies are still intact. Eject-side plugin uninstalls\n // are diagnostic-only, so only plugin-install work demands this.\n await this.requireMarketplaceOrExit(context.sourceResult, \"migrate skills to plugin mode\");\n // The install itself happens inside `executeMigration`, which deletes each skill's\n // working copy the moment that skill's plugin is registered — so the banner is\n // announced here and the outcome reported below, through the same surface `init`\n // and the newly-added-skill path narrate an install with.\n this.announcePluginInstall();\n }\n\n const migrationResult = await executeMigration(migrationPlan, cwd, context.sourceResult);\n\n for (const warning of migrationResult.warnings) {\n this.warn(warning);\n }\n\n // The eject direction's own account of what it did. `executeMigration` copies each\n // skill before it attempts the plugin uninstall, so the count is the work that\n // landed; the uninstall is best-effort and diagnostic-only, and its successes stay\n // at verbose level while its failures are already in `warnings` above.\n if (migrationPlan.toEject.length > 0) {\n this.log(\n chalk.hex(CLI_COLORS.NEUTRAL)(localSkillsCopied(migrationResult.ejectedSkills.length)),\n );\n }\n\n // Reports what was installed and hard-errors on any failure: a migration whose\n // plugin could not be installed must not reach `recordGlobalSourceMigrations` or\n // `writeConfigAndCompile`, either of which would persist a marketplace `source`\n // for a skill with no plugin registration.\n if (migrationPlan.toPlugin.length > 0) {\n this.reportPluginInstalls(migrationResult.pluginInstalls);\n }\n\n return migratedSkillIds;\n }\n\n /** Names what this run is switching, in the words `init` describes an install mode with. */\n private logModeSwitch(count: number, modeDescription: string): void {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(`Switching ${count} skill(s) to ${modeDescription}`));\n }\n\n private async applyScopeChanges(\n changes: ConfigChanges,\n filteredResult: WizardResultV2,\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n const { scopeChanges } = changes;\n\n // Handle scope migrations (P->G or G->P) for eject-mode skills\n for (const [skillId, change] of scopeChanges) {\n const skillConfig = filteredResult.skills.find((s) => s.id === skillId);\n if (skillConfig?.source === EJECT_SOURCE) {\n await migrateLocalSkillScope(skillId, change.from, cwd);\n }\n }\n\n // Plugin scope migrations require a marketplace.\n // Compute eligible migrations first; only resolve/demand marketplace when there are any.\n const hasPluginScopeChanges = [...scopeChanges.keys()].some((skillId) => {\n const skillConfig = filteredResult.skills.find((s) => s.id === skillId);\n return skillConfig && skillConfig.source !== EJECT_SOURCE;\n });\n if (!hasPluginScopeChanges) return;\n\n const marketplace = await this.requireMarketplaceOrExit(\n context.sourceResult,\n \"migrate plugin skill scopes\",\n );\n\n const pluginScopeResult = await migratePluginSkillScopes(\n scopeChanges,\n filteredResult.skills,\n marketplace,\n cwd,\n );\n for (const item of pluginScopeResult.failed) {\n this.warn(`Failed to migrate plugin scope for ${item.id}: ${item.error}`);\n }\n }\n\n private async applySourceChanges(\n changes: ConfigChanges,\n activeOldSkills: SkillConfig[],\n cwd: string,\n migratedSkillIds: Set<SkillId>,\n ): Promise<void> {\n const { sourceChanges } = changes;\n\n // Handle remaining non-migration source changes (e.g., marketplace A -> marketplace B)\n for (const [skillId, change] of sourceChanges) {\n // Skip skills already handled by mode migration\n if (migratedSkillIds.has(skillId)) {\n continue;\n }\n if (change.from === EJECT_SOURCE) {\n const oldSkill = activeOldSkills.find((s) => s.id === skillId);\n const deleteDir = installBaseDir(cwd, oldSkill?.scope);\n await deleteLocalSkill(deleteDir, skillId);\n }\n }\n }\n\n private async applyPluginChanges(\n changes: ConfigChanges,\n filteredResult: WizardResultV2,\n activeOldSkills: SkillConfig[],\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n const { addedSkills, removedSkills } = changes;\n\n // Compute plugin-intent lists per-skill (ungated) — per-skill `source` drives install mode.\n const addedPluginSkills = filteredResult.skills.filter(\n (s) => addedSkills.includes(s.id) && s.source !== EJECT_SOURCE,\n );\n const removedPluginSkills = removedSkills.filter(\n (id) => activeOldSkills.find((s) => s.id === id)?.source !== EJECT_SOURCE,\n );\n\n if (addedPluginSkills.length === 0 && removedPluginSkills.length === 0) return;\n\n const marketplace = await this.requireMarketplaceOrExit(\n context.sourceResult,\n \"install or uninstall plugin skills\",\n );\n\n if (addedPluginSkills.length > 0) {\n await this.installPluginSkillsReported(addedPluginSkills, marketplace, cwd);\n }\n\n if (removedPluginSkills.length > 0) {\n const uninstallResult = await uninstallPluginSkills(\n removedPluginSkills,\n activeOldSkills,\n marketplace,\n cwd,\n );\n if (uninstallResult.uninstalled.length > 0) {\n this.log(\n chalk.hex(CLI_COLORS.NEUTRAL)(`Removed ${uninstallResult.uninstalled.length} plugin(s)`),\n );\n }\n for (const item of uninstallResult.failed) {\n this.warn(`Failed to uninstall plugin ${item.id}: ${item.error}`);\n }\n }\n }\n\n private async copyNewLocalSkills(\n changes: ConfigChanges,\n filteredResult: WizardResultV2,\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n const { addedSkills } = changes;\n\n // Copy newly added local-source skills to .claude/skills/ (split by scope)\n const addedLocalSkills = filteredResult.skills.filter(\n (s) => addedSkills.includes(s.id) && s.source === EJECT_SOURCE,\n );\n\n if (addedLocalSkills.length > 0) {\n const copyResult = await copyLocalSkills(addedLocalSkills, cwd, context.sourceResult);\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(localSkillsCopied(copyResult.totalCopied)));\n }\n }\n\n private async removeDeletedLocalSkills(\n changes: ConfigChanges,\n activeOldSkills: SkillConfig[],\n cwd: string,\n ): Promise<void> {\n const { removedSkills } = changes;\n\n // A fully-deselected eject-mode skill is a genuine uninstall — its copied directory under\n // .claude/skills/<id>/ must be removed from the scope it was installed at (D-233). Plugin\n // removals are handled by applyPluginChanges; source-change (eject->marketplace) deletions by\n // applySourceChanges. deleteLocalSkill is a no-op when the directory is absent.\n for (const skillId of removedSkills) {\n const oldSkill = activeOldSkills.find((s) => s.id === skillId);\n if (oldSkill?.source !== EJECT_SOURCE) continue;\n\n const deleteDir = installBaseDir(cwd, oldSkill.scope);\n await deleteLocalSkill(deleteDir, skillId);\n }\n }\n\n private async writeConfigAndCompile(\n result: WizardResultV2,\n context: EditContext,\n cwd: string,\n ): Promise<void> {\n // Load agent definitions — needed for both config-types.ts and recompilation\n let agentDefsResult: AgentDefs;\n try {\n agentDefsResult = await loadAgentDefs({});\n } catch (error) {\n this.handleError(error);\n }\n\n // Persist wizard result to config.ts and config-types.ts (split by scope when in project context)\n let configResult: ConfigWriteResult | undefined;\n try {\n configResult = await writeProjectConfig({\n wizardResult: result,\n sourceResult: context.sourceResult,\n projectDir: cwd,\n agents: agentDefsResult.agents,\n // A full `cc edit` pass is authoritative over the roster it owns, so deselected entries\n // are removed rather than union-preserved (D-233 Scenario C). Global-context edit owns\n // the entire config (\"all\"); a project edit owns only project-scoped entries and its own\n // tombstones (\"owned\"), never inherited global-active entries.\n authoritativeScope: isHomeDirectory(cwd) ? \"all\" : \"owned\",\n });\n } catch (error) {\n this.warn(`Could not update config: ${getErrorMessage(error)}`);\n }\n\n if (configResult) {\n this.reportUnassignedSkills(configResult.config);\n }\n\n try {\n const agentScopeMap = activeAgentScopeMap(result.agentConfigs);\n const { allSkills } = await discoverInstalledSkills(cwd);\n const compilationResult = await compileAgentsAllScopes({\n projectDir: cwd,\n sourcePath: agentDefsResult.sourcePath,\n skills: allSkills,\n agentScopeMap,\n });\n\n const { compiled, rewritten, failed, warnings } = compilationResult;\n const summary = recompileSummary(\n rewritten.length,\n compiled.length - rewritten.length,\n RECOMPILE_SUBJECT,\n );\n\n if (failed.length > 0) {\n this.log(\n chalk.hex(CLI_COLORS.NEUTRAL)(summary) +\n chalk.hex(CLI_COLORS.WARNING)(` (${failed.length} failed)`),\n );\n for (const warning of warnings) {\n this.warn(warning);\n }\n } else if (compiled.length > 0) {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(summary));\n } else {\n this.log(chalk.hex(CLI_COLORS.NEUTRAL)(INFO_MESSAGES.NO_AGENTS_TO_RECOMPILE));\n }\n } catch (error) {\n this.warn(`Agent recompilation failed: ${getErrorMessage(error)}`);\n this.log(`You can manually recompile with '${CLI_INVOKE_COMMAND} compile'.`);\n }\n\n if (configResult) {\n this.reportPropagatedRecompile(configResult.propagation);\n }\n }\n\n private async cleanupStaleAgentFiles(\n changes: ConfigChanges,\n oldAgents: AgentScopeConfig[],\n cwd: string,\n ): Promise<void> {\n for (const removal of planStaleAgentRemovals(changes, oldAgents, cwd)) {\n const { failed } = await removeCompiledAgents(removal);\n\n for (const { name, error } of failed) {\n const agentPath = path.join(removal.agentsDir, `${name}.md`);\n this.warn(`Could not remove agent file ${agentPath}: ${error}`);\n }\n }\n }\n\n private logCompletionSummary(_changes: ConfigChanges): void {\n this.log(`\\n${chalk.hex(CLI_COLORS.SUCCESS)(\"\\u2713 Done\")}\\n`);\n }\n}\n\n/** @internal Exported for testing */\nexport type ConfigChanges = {\n addedSkills: SkillId[];\n removedSkills: SkillId[];\n addedAgents: AgentName[];\n removedAgents: AgentName[];\n sourceChanges: Map<SkillId, { from: string; to: string }>;\n scopeChanges: Map<SkillId, ScopeChange>;\n agentScopeChanges: Map<AgentName, ScopeChange>;\n /**\n * Skill ids whose `scopeChanges` entry is a dual-scope add/remove — the project\n * half of a `[P][G]` pair was toggled while the global half persists — NOT a true\n * single-entry migration. The disk-side scope work still flows through\n * `scopeChanges`; this set only steers the completion-summary display so a\n * dual-scope addition is not misreported as a `[G] → [P]` migration.\n */\n dualScopeSkillTransitions: Set<SkillId>;\n /** Agent equivalent of `dualScopeSkillTransitions`. */\n dualScopeAgentTransitions: Set<AgentName>;\n};\n\n/** Full (tombstone-inclusive) entry lists used to classify dual-scope transitions. */\ntype FullScopeEntries = {\n newSkills: SkillConfig[];\n oldSkills: SkillConfig[];\n newAgents: AgentScopeConfig[];\n oldAgents: AgentScopeConfig[];\n};\n\n/**\n * @internal Exported for testing\n *\n * `oldConfig` / `wizardResult` carry the ACTIVE (tombstone-filtered) entries used\n * for add/remove/source/scope diffing. `fullEntries`, when provided, carries the\n * unfiltered lists (including excluded tombstones) used ONLY to tell a genuine\n * scope migration apart from a dual-scope add/remove. When omitted, every scope\n * change is treated as a migration (the pre-dual-scope behaviour).\n */\nexport function detectConfigChanges(\n oldConfig: ProjectConfig | null,\n wizardResult: WizardResultV2,\n fullEntries?: FullScopeEntries,\n): ConfigChanges {\n const oldSkillIds = oldConfig?.skills.map((s) => s.id) ?? [];\n const newSkillIds = wizardResult.skills.map((s) => s.id);\n const oldAgentNames = oldConfig?.agents.map((a) => a.name) ?? [];\n const newAgentNames = wizardResult.agentConfigs.map((a) => a.name);\n\n const oldSkillsById = indexBy(oldConfig?.skills ?? [], (s) => s.id);\n const oldAgentsByName = indexBy(oldConfig?.agents ?? [], (a) => a.name);\n\n const scopeChanges = detectPropertyChanges(\n wizardResult.skills,\n oldSkillsById,\n (s) => s.id,\n (s) => s.scope,\n );\n const agentScopeChanges = detectPropertyChanges(\n wizardResult.agentConfigs,\n oldAgentsByName,\n (a) => a.name,\n (a) => a.scope,\n );\n\n return {\n addedSkills: difference(newSkillIds, oldSkillIds),\n removedSkills: difference(oldSkillIds, newSkillIds),\n addedAgents: difference(newAgentNames, oldAgentNames),\n removedAgents: difference(oldAgentNames, newAgentNames),\n sourceChanges: detectPropertyChanges(\n wizardResult.skills,\n oldSkillsById,\n (s) => s.id,\n (s) => s.source,\n ),\n scopeChanges,\n agentScopeChanges,\n dualScopeSkillTransitions: detectDualScopeTransitions(\n scopeChanges,\n fullEntries?.newSkills ?? [],\n fullEntries?.oldSkills ?? [],\n (s) => s.id,\n ),\n dualScopeAgentTransitions: detectDualScopeTransitions(\n agentScopeChanges,\n fullEntries?.newAgents ?? [],\n fullEntries?.oldAgents ?? [],\n (a) => a.name,\n ),\n };\n}\n\nfunction detectPropertyChanges<T, K extends string, V>(\n newItems: T[],\n oldByKey: Record<string, T>,\n getKey: (item: T) => K,\n getValue: (item: T) => V,\n): Map<K, { from: V; to: V }> {\n const changes = new Map<K, { from: V; to: V }>();\n for (const item of newItems) {\n const key = getKey(item);\n const old = oldByKey[key];\n if (old && getValue(old) !== getValue(item)) {\n changes.set(key, { from: getValue(old), to: getValue(item) });\n }\n }\n return changes;\n}\n\n/**\n * A scope change is a dual-scope transition (not a migration) when the canonical\n * dual-scope tombstone — an excluded global entry — sits alongside it:\n * - G→P add: the NEW state keeps a global tombstone, so the global install\n * survives and the project half was merely added.\n * - P→G remove: the OLD state held a global tombstone, so the pair was already\n * dual-scope and the project half was merely removed.\n * Either way the item occupied both scopes, so `[X] → [Y]` would misdescribe it.\n */\nfunction detectDualScopeTransitions<\n K extends string,\n T extends { scope: SkillScope; excluded?: boolean },\n>(scopeChanges: Map<K, ScopeChange>, fullNew: T[], fullOld: T[], getKey: (item: T) => K): Set<K> {\n const hasGlobalTombstone = (items: T[], key: K): boolean =>\n items.some((item) => getKey(item) === key && item.scope === \"global\" && item.excluded === true);\n\n const result = new Set<K>();\n for (const [key, change] of scopeChanges) {\n if (change.from === \"global\" && change.to === \"project\" && hasGlobalTombstone(fullNew, key)) {\n result.add(key);\n } else if (\n change.from === \"project\" &&\n change.to === \"global\" &&\n hasGlobalTombstone(fullOld, key)\n ) {\n result.add(key);\n }\n }\n return result;\n}\n\ntype StaleAgent = { name: AgentName; scope: SkillScope };\n\n/** Every scope a stale compiled agent can be sitting at. */\nconst STALE_AGENT_SCOPES = [\"project\", \"global\"] as const satisfies readonly SkillScope[];\n\n/** The scope a deselected agent was installed at, for one absent from the old roster. */\nconst UNRECORDED_AGENT_SCOPE: SkillScope = \"project\";\n\nfunction installedScope(name: AgentName, oldAgents: AgentScopeConfig[]): SkillScope {\n return oldAgents.find((agent) => agent.name === name)?.scope ?? UNRECORDED_AGENT_SCOPE;\n}\n\n/**\n * The compiled files an edit leaves stale, one removal per scope directory that\n * holds any: the project copy a P→G move superseded, plus every deselected agent\n * at the scope it was installed at.\n *\n * G→P moves are absent deliberately — that direction is an override, so the global\n * installation stays untouched and the project copy shadows it. A scope with\n * nothing to remove is absent too: only a directory this edit actually removed\n * from is a directory this edit may tidy.\n */\nfunction planStaleAgentRemovals(\n changes: ConfigChanges,\n oldAgents: AgentScopeConfig[],\n cwd: string,\n): RemoveCompiledAgentsOptions[] {\n const supersededByGlobal = [...changes.agentScopeChanges]\n .filter(([, change]) => change.from !== \"global\")\n .map(([name]): StaleAgent => ({ name, scope: \"project\" }));\n\n const deselected = changes.removedAgents.map((name): StaleAgent => ({\n name,\n scope: installedScope(name, oldAgents),\n }));\n\n const stale = [...supersededByGlobal, ...deselected];\n const removalAtScope = (scope: SkillScope): RemoveCompiledAgentsOptions => ({\n agentsDir: resolveInstallPaths(cwd, scope).agentsDir,\n agents: stale.filter((agent) => agent.scope === scope).map((agent) => agent.name),\n });\n\n return STALE_AGENT_SCOPES.map(removalAtScope).filter((removal) => removal.agents.length > 0);\n}\n\nfunction hasAnyChanges(changes: ConfigChanges): boolean {\n return (\n changes.addedSkills.length > 0 ||\n changes.removedSkills.length > 0 ||\n changes.addedAgents.length > 0 ||\n changes.removedAgents.length > 0 ||\n changes.sourceChanges.size > 0 ||\n changes.scopeChanges.size > 0 ||\n changes.agentScopeChanges.size > 0\n );\n}\n\n/** @internal Exported for testing */\nexport type PluginScopeMigrationResult = {\n migrated: SkillId[];\n failed: Array<{ id: SkillId; error: string }>;\n};\n\n/** @internal Exported for testing */\nexport async function migratePluginSkillScopes(\n scopeChanges: Map<SkillId, ScopeChange>,\n skills: Pick<SkillConfig, \"id\" | \"source\">[],\n marketplace: string,\n projectDir: string,\n): Promise<PluginScopeMigrationResult> {\n const migrated: SkillId[] = [];\n const failed: PluginScopeMigrationResult[\"failed\"] = [];\n\n for (const [skillId, change] of scopeChanges) {\n const skillConfig = skills.find((s) => s.id === skillId);\n if (!skillConfig || skillConfig.source === EJECT_SOURCE) {\n continue;\n }\n\n const newPluginScope = toClaudePluginScope(change.to);\n const pluginRef = buildMarketplacePluginRef(skillId, marketplace);\n\n try {\n // global→project: keep the global registration, just add project scope.\n // The global plugin must remain for other projects.\n // project→global: uninstall the project-scope registration, install global.\n if (change.from === \"project\") {\n await claudePluginUninstall(pluginRef, \"project\", projectDir);\n }\n await claudePluginInstall(pluginRef, newPluginScope, projectDir);\n migrated.push(skillId);\n } catch (error) {\n failed.push({ id: skillId, error: getErrorMessage(error) });\n }\n }\n\n return { migrated, failed };\n}\n"],"mappings":"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","names":[]}
|
package/dist/commands/eject.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadSource
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-XMEIVWAS.js";
|
|
5
|
+
import "../chunk-ZU6DAR4S.js";
|
|
6
|
+
import "../chunk-UW44KSYL.js";
|
|
7
|
+
import "../chunk-PRJD5MMQ.js";
|
|
8
|
+
import "../chunk-TUQF577Z.js";
|
|
9
9
|
import {
|
|
10
10
|
BaseCommand,
|
|
11
11
|
EXIT_CODES
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import "../chunk-
|
|
12
|
+
} from "../chunk-FMYHWKGG.js";
|
|
13
|
+
import "../chunk-7VZV4O6B.js";
|
|
14
14
|
import "../chunk-K3O3YQYG.js";
|
|
15
15
|
import {
|
|
16
16
|
copySkillsToLocalFlattened,
|
|
@@ -22,17 +22,17 @@ import {
|
|
|
22
22
|
mutateGlobal,
|
|
23
23
|
resolveSource,
|
|
24
24
|
writeProjectPartial
|
|
25
|
-
} from "../chunk-
|
|
25
|
+
} from "../chunk-CBF4ZYV3.js";
|
|
26
26
|
import {
|
|
27
27
|
copy,
|
|
28
28
|
directoryExists,
|
|
29
29
|
ensureDir,
|
|
30
30
|
fileExists,
|
|
31
31
|
listDirectories
|
|
32
|
-
} from "../chunk-
|
|
32
|
+
} from "../chunk-4VCWL2IG.js";
|
|
33
33
|
import {
|
|
34
34
|
matrix
|
|
35
|
-
} from "../chunk-
|
|
35
|
+
} from "../chunk-IPJOMAWC.js";
|
|
36
36
|
import {
|
|
37
37
|
typedKeys
|
|
38
38
|
} from "../chunk-VASLW636.js";
|
package/dist/commands/init.js
CHANGED
|
@@ -5,48 +5,48 @@ import {
|
|
|
5
5
|
getDashboardData,
|
|
6
6
|
runDashboardFlow,
|
|
7
7
|
showDashboard
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-5MFJ24VM.js";
|
|
9
9
|
import "../chunk-XGMOXMS4.js";
|
|
10
10
|
import "../chunk-OJJLYHM3.js";
|
|
11
11
|
import "../chunk-ZBPEFQ4G.js";
|
|
12
|
-
import "../chunk-
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-QUDQTO3O.js";
|
|
13
|
+
import "../chunk-R7JV22QK.js";
|
|
14
|
+
import "../chunk-MJFIO5SX.js";
|
|
15
15
|
import "../chunk-NSJ2S7R5.js";
|
|
16
16
|
import "../chunk-JC7DBPRD.js";
|
|
17
|
-
import "../chunk-
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
20
|
-
import "../chunk-
|
|
21
|
-
import "../chunk-
|
|
22
|
-
import "../chunk-
|
|
23
|
-
import "../chunk-
|
|
24
|
-
import "../chunk-
|
|
17
|
+
import "../chunk-GUDGCFSF.js";
|
|
18
|
+
import "../chunk-BZ4CZBOM.js";
|
|
19
|
+
import "../chunk-NKCY2ULI.js";
|
|
20
|
+
import "../chunk-NFH6SA62.js";
|
|
21
|
+
import "../chunk-IXEDSKMH.js";
|
|
22
|
+
import "../chunk-AURY6RT6.js";
|
|
23
|
+
import "../chunk-WRRP47PY.js";
|
|
24
|
+
import "../chunk-2IMYK4WN.js";
|
|
25
25
|
import "../chunk-TSIU7DME.js";
|
|
26
26
|
import "../chunk-XVAQG2CV.js";
|
|
27
|
-
import "../chunk-
|
|
27
|
+
import "../chunk-LA3JPESW.js";
|
|
28
28
|
import "../chunk-J27W6TXS.js";
|
|
29
|
-
import "../chunk-
|
|
30
|
-
import "../chunk-
|
|
31
|
-
import "../chunk-
|
|
29
|
+
import "../chunk-AKQ5QISO.js";
|
|
30
|
+
import "../chunk-CHNA5RVS.js";
|
|
31
|
+
import "../chunk-ONWEOS77.js";
|
|
32
32
|
import "../chunk-V3ENMW7G.js";
|
|
33
|
-
import "../chunk-
|
|
33
|
+
import "../chunk-DRKSYJZ2.js";
|
|
34
34
|
import "../chunk-Q5FLW4JG.js";
|
|
35
35
|
import "../chunk-6CNRMCFM.js";
|
|
36
|
-
import "../chunk-
|
|
37
|
-
import "../chunk-
|
|
38
|
-
import "../chunk-
|
|
39
|
-
import "../chunk-
|
|
40
|
-
import "../chunk-
|
|
41
|
-
import "../chunk-
|
|
36
|
+
import "../chunk-XMEIVWAS.js";
|
|
37
|
+
import "../chunk-ZU6DAR4S.js";
|
|
38
|
+
import "../chunk-UW44KSYL.js";
|
|
39
|
+
import "../chunk-PRJD5MMQ.js";
|
|
40
|
+
import "../chunk-TUQF577Z.js";
|
|
41
|
+
import "../chunk-B66SC72V.js";
|
|
42
42
|
import "../chunk-JFLVEFFP.js";
|
|
43
|
-
import "../chunk-
|
|
44
|
-
import "../chunk-
|
|
45
|
-
import "../chunk-
|
|
43
|
+
import "../chunk-QQTYMW7N.js";
|
|
44
|
+
import "../chunk-FMYHWKGG.js";
|
|
45
|
+
import "../chunk-7VZV4O6B.js";
|
|
46
46
|
import "../chunk-K3O3YQYG.js";
|
|
47
|
-
import "../chunk-
|
|
48
|
-
import "../chunk-
|
|
49
|
-
import "../chunk-
|
|
47
|
+
import "../chunk-CBF4ZYV3.js";
|
|
48
|
+
import "../chunk-4VCWL2IG.js";
|
|
49
|
+
import "../chunk-IPJOMAWC.js";
|
|
50
50
|
import "../chunk-VASLW636.js";
|
|
51
51
|
import "../chunk-R54KIGN2.js";
|
|
52
52
|
import "../chunk-VZRO7RYT.js";
|
package/dist/commands/list.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
SkillAgentSummary
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-B66SC72V.js";
|
|
5
5
|
import {
|
|
6
6
|
render
|
|
7
7
|
} from "../chunk-JFLVEFFP.js";
|
|
8
8
|
import {
|
|
9
9
|
hydrateWizardStore
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-QQTYMW7N.js";
|
|
11
11
|
import {
|
|
12
12
|
BaseCommand
|
|
13
|
-
} from "../chunk-
|
|
14
|
-
import "../chunk-
|
|
13
|
+
} from "../chunk-FMYHWKGG.js";
|
|
14
|
+
import "../chunk-7VZV4O6B.js";
|
|
15
15
|
import "../chunk-K3O3YQYG.js";
|
|
16
16
|
import {
|
|
17
17
|
INSTALL_MODE_LABELS,
|
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
formatInstallationDisplay,
|
|
20
20
|
getInstallationInfo,
|
|
21
21
|
loadProjectConfig
|
|
22
|
-
} from "../chunk-
|
|
23
|
-
import "../chunk-
|
|
24
|
-
import "../chunk-
|
|
22
|
+
} from "../chunk-CBF4ZYV3.js";
|
|
23
|
+
import "../chunk-4VCWL2IG.js";
|
|
24
|
+
import "../chunk-IPJOMAWC.js";
|
|
25
25
|
import "../chunk-VASLW636.js";
|
|
26
26
|
import {
|
|
27
27
|
CLI_COLORS,
|
package/dist/commands/search.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadSource
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
6
|
-
import "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-XMEIVWAS.js";
|
|
5
|
+
import "../chunk-ZU6DAR4S.js";
|
|
6
|
+
import "../chunk-UW44KSYL.js";
|
|
7
|
+
import "../chunk-PRJD5MMQ.js";
|
|
8
|
+
import "../chunk-TUQF577Z.js";
|
|
9
9
|
import {
|
|
10
10
|
BaseCommand
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-FMYHWKGG.js";
|
|
12
|
+
import "../chunk-7VZV4O6B.js";
|
|
13
13
|
import "../chunk-K3O3YQYG.js";
|
|
14
14
|
import {
|
|
15
15
|
STATUS_MESSAGES,
|
|
16
16
|
truncateText
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
17
|
+
} from "../chunk-CBF4ZYV3.js";
|
|
18
|
+
import "../chunk-4VCWL2IG.js";
|
|
19
|
+
import "../chunk-IPJOMAWC.js";
|
|
20
20
|
import {
|
|
21
21
|
typedValues
|
|
22
22
|
} from "../chunk-VASLW636.js";
|
|
@@ -28,7 +28,6 @@ import { Args } from "@oclif/core";
|
|
|
28
28
|
import { printTable } from "@oclif/table";
|
|
29
29
|
import { sortBy } from "remeda";
|
|
30
30
|
var MAX_DESCRIPTION_WIDTH = 50;
|
|
31
|
-
var PRIMARY_SOURCE_NAME = "marketplace";
|
|
32
31
|
var Search = class _Search extends BaseCommand {
|
|
33
32
|
static summary = "Search the catalog of available skills";
|
|
34
33
|
static description = "Read-only catalog browse. Searches the marketplace this installation reads from, plus the local skills already on disk, by id, displayName, slug, description, or category. Use `edit` to install what it finds.";
|
|
@@ -71,14 +70,10 @@ var Search = class _Search extends BaseCommand {
|
|
|
71
70
|
);
|
|
72
71
|
this.log("");
|
|
73
72
|
printTable({
|
|
74
|
-
data: results.map(
|
|
75
|
-
id: skill.displayName,
|
|
76
|
-
source: skill.sourceName,
|
|
77
|
-
category: skill.category,
|
|
78
|
-
description: truncateText(skill.description, MAX_DESCRIPTION_WIDTH)
|
|
79
|
-
})),
|
|
73
|
+
data: results.map(toResultRow),
|
|
80
74
|
columns: [
|
|
81
75
|
{ key: "id", name: "ID" },
|
|
76
|
+
{ key: "name", name: "Name" },
|
|
82
77
|
{ key: "source", name: "Source" },
|
|
83
78
|
{ key: "category", name: "Category" },
|
|
84
79
|
{ key: "description", name: "Description" }
|
|
@@ -93,10 +88,23 @@ var Search = class _Search extends BaseCommand {
|
|
|
93
88
|
};
|
|
94
89
|
async function loadSearchableSkills() {
|
|
95
90
|
const { sourceResult } = await loadSource({ projectDir: process.cwd() });
|
|
96
|
-
return typedValues(sourceResult.matrix.skills)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
91
|
+
return typedValues(sourceResult.matrix.skills);
|
|
92
|
+
}
|
|
93
|
+
function toResultRow(skill) {
|
|
94
|
+
return {
|
|
95
|
+
id: skill.id,
|
|
96
|
+
name: skill.displayName,
|
|
97
|
+
source: activeSourceName(skill),
|
|
98
|
+
category: skill.category,
|
|
99
|
+
description: truncateText(skill.description, MAX_DESCRIPTION_WIDTH)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function activeSourceName(skill) {
|
|
103
|
+
const { activeSource } = skill;
|
|
104
|
+
if (!activeSource) {
|
|
105
|
+
throw new Error(`Skill "${skill.id}" was loaded without a source, so its origin is unknown`);
|
|
106
|
+
}
|
|
107
|
+
return activeSource.name;
|
|
100
108
|
}
|
|
101
109
|
function matchesQuery(skill, query) {
|
|
102
110
|
const lowerQuery = query.toLowerCase();
|
|
@@ -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 { loadSource } from \"../lib/operations/index.js\";\nimport type { ResolvedSkill } from \"../types/index.js\";\nimport { STATUS_MESSAGES } from \"../utils/messages.js\";\nimport { truncateText } from \"../utils/string.js\";\nimport { typedValues } from \"../utils/typed-object.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\
|
|
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 { loadSource } from \"../lib/operations/index.js\";\nimport type { ResolvedSkill } from \"../types/index.js\";\nimport { STATUS_MESSAGES } from \"../utils/messages.js\";\nimport { truncateText } from \"../utils/string.js\";\nimport { typedValues } from \"../utils/typed-object.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\n\n/**\n * One row of the results table. `id` and `category` are the skill's own values; `name`, `source`\n * and `description` are rendered for the cell, so they are plain strings.\n */\ntype ResultRow = Pick<ResolvedSkill, \"id\" | \"category\"> & {\n name: string;\n source: 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. Use `edit` to install what it finds.\";\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.runSearch(args.query);\n }\n\n private async runSearch(query: string): Promise<void> {\n try {\n this.log(STATUS_MESSAGES.LOADING_SKILLS);\n\n const allSkills = await loadSearchableSkills();\n\n const results = sortBy(\n allSkills.filter((skill) => matchesQuery(skill, query)),\n (r) => r.displayName.toLowerCase(),\n );\n\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n return;\n }\n\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${query}\"`,\n );\n this.log(\"\");\n\n printTable({\n data: results.map(toResultRow),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"name\", name: \"Name\" },\n { key: \"source\", name: \"Source\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n\n/**\n * Every skill the catalog can offer: the marketplace matrix, which `loadSource` has already\n * merged the on-disk local skills into. There is no second source to reach for — the\n * registered-extras array this used to fan out over was withdrawn with the marketplace axis\n * (CLI-450), so the read is one load and no network beyond it.\n */\nasync function loadSearchableSkills(): Promise<ResolvedSkill[]> {\n const { sourceResult } = await loadSource({ projectDir: process.cwd() });\n\n return typedValues(sourceResult.matrix.skills);\n}\n\n/**\n * The machine id and the display name are different answers and get a column each — `edit`\n * takes the id, a human reads the name.\n */\nfunction toResultRow(skill: ResolvedSkill): ResultRow {\n return {\n id: skill.id,\n name: skill.displayName,\n source: activeSourceName(skill),\n category: skill.category,\n description: truncateText(skill.description, MAX_DESCRIPTION_WIDTH),\n };\n}\n\n/**\n * Where this installation reads the skill from: the local copy when one is on disk, otherwise\n * the marketplace the load resolved. Both names are written by the tagging pass\n * (`loadSkillsFromAllSources`), which `loadSource` always runs — a skill that reached the table\n * untagged would have no origin to report, so say so rather than name one it might not have.\n */\nfunction activeSourceName(skill: ResolvedSkill): string {\n const { activeSource } = skill;\n if (!activeSource) {\n throw new Error(`Skill \"${skill.id}\" was loaded without a source, so its origin is unknown`);\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":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,YAAY;AACrB,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AASvB,IAAM,wBAAwB;AAY9B,IAAqB,SAArB,MAAqB,gBAAe,YAAY;AAAA,EAC9C,OAAO,UAAU;AAAA,EACjB,OAAO,cACL;AAAA,EAIF,OAAO,WAAW;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,OAAO,OAAO;AAAA,IACZ,OAAO,KAAK,OAAO;AAAA,MACjB,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,QAAQ,CAAC;AAAA,EAEhB,MAAM,MAAqB;AACzB,UAAM,EAAE,KAAK,IAAI,MAAM,KAAK,MAAM,OAAM;AACxC,UAAM,KAAK,UAAU,KAAK,KAAK;AAAA,EACjC;AAAA,EAEA,MAAc,UAAU,OAA8B;AACpD,QAAI;AACF,WAAK,IAAI,gBAAgB,cAAc;AAEvC,YAAM,YAAY,MAAM,qBAAqB;AAE7C,YAAM,UAAU;AAAA,QACd,UAAU,OAAO,CAAC,UAAU,aAAa,OAAO,KAAK,CAAC;AAAA,QACtD,CAAC,MAAM,EAAE,YAAY,YAAY;AAAA,MACnC;AAEA,WAAK,IAAI,EAAE;AACX,UAAI,QAAQ,WAAW,GAAG;AACxB,aAAK,KAAK,6BAA6B,KAAK,GAAG;AAC/C;AAAA,MACF;AAEA,WAAK;AAAA,QACH,SAAS,QAAQ,MAAM,SAAS,QAAQ,WAAW,IAAI,KAAK,GAAG,cAAc,KAAK;AAAA,MACpF;AACA,WAAK,IAAI,EAAE;AAEX,iBAAW;AAAA,QACT,MAAM,QAAQ,IAAI,WAAW;AAAA,QAC7B,SAAS;AAAA,UACP,EAAE,KAAK,MAAM,MAAM,KAAK;AAAA,UACxB,EAAE,KAAK,QAAQ,MAAM,OAAO;AAAA,UAC5B,EAAE,KAAK,UAAU,MAAM,SAAS;AAAA,UAChC,EAAE,KAAK,YAAY,MAAM,WAAW;AAAA,UACpC,EAAE,KAAK,eAAe,MAAM,cAAc;AAAA,QAC5C;AAAA,QACA,eAAe,EAAE,MAAM,KAAK;AAAA,MAC9B,CAAC;AACD,WAAK,IAAI,EAAE;AAAA,IACb,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AACF;AAQA,eAAe,uBAAiD;AAC9D,QAAM,EAAE,aAAa,IAAI,MAAM,WAAW,EAAE,YAAY,QAAQ,IAAI,EAAE,CAAC;AAEvE,SAAO,YAAY,aAAa,OAAO,MAAM;AAC/C;AAMA,SAAS,YAAY,OAAiC;AACpD,SAAO;AAAA,IACL,IAAI,MAAM;AAAA,IACV,MAAM,MAAM;AAAA,IACZ,QAAQ,iBAAiB,KAAK;AAAA,IAC9B,UAAU,MAAM;AAAA,IAChB,aAAa,aAAa,MAAM,aAAa,qBAAqB;AAAA,EACpE;AACF;AAQA,SAAS,iBAAiB,OAA8B;AACtD,QAAM,EAAE,aAAa,IAAI;AACzB,MAAI,CAAC,cAAc;AACjB,UAAM,IAAI,MAAM,UAAU,MAAM,EAAE,yDAAyD;AAAA,EAC7F;AACA,SAAO,aAAa;AACtB;AAEA,SAAS,aAAa,OAAsB,OAAwB;AAClE,QAAM,aAAa,MAAM,YAAY;AACrC,SAAO,CAAC,MAAM,IAAI,MAAM,aAAa,MAAM,MAAM,MAAM,aAAa,MAAM,QAAQ,EAAE;AAAA,IAClF,CAAC,UAAU,MAAM,YAAY,EAAE,SAAS,UAAU;AAAA,EACpD;AACF;","names":[]}
|