agents-inc 0.174.0 → 0.176.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +115 -0
  2. package/dist/{chunk-APWMMZOK.js → chunk-3F5LT433.js} +157 -53
  3. package/dist/chunk-3F5LT433.js.map +1 -0
  4. package/dist/chunk-5CFHP6Z5.js +109 -0
  5. package/dist/chunk-5CFHP6Z5.js.map +1 -0
  6. package/dist/{chunk-3PJZ4QNJ.js → chunk-B7AVWSK2.js} +21 -11
  7. package/dist/chunk-B7AVWSK2.js.map +1 -0
  8. package/dist/{chunk-H5E6IO2L.js → chunk-C2BSCEDN.js} +9 -11
  9. package/dist/chunk-C2BSCEDN.js.map +1 -0
  10. package/dist/{chunk-R7GKQBZJ.js → chunk-CKBWEWHZ.js} +96 -52
  11. package/dist/chunk-CKBWEWHZ.js.map +1 -0
  12. package/dist/{chunk-IXVGBUWI.js → chunk-EC3JXT23.js} +5 -5
  13. package/dist/{chunk-E45IT3HC.js → chunk-ENET4IF6.js} +998 -472
  14. package/dist/chunk-ENET4IF6.js.map +1 -0
  15. package/dist/{chunk-FQF6VHO3.js → chunk-FACDJH6O.js} +12 -105
  16. package/dist/chunk-FACDJH6O.js.map +1 -0
  17. package/dist/{chunk-TVEDNGVP.js → chunk-H6WUOW5F.js} +2 -2
  18. package/dist/{chunk-7BHDKEGK.js → chunk-JNRACLNS.js} +3 -3
  19. package/dist/{chunk-IAQFZFWD.js → chunk-JTMSFBCA.js} +231 -24
  20. package/dist/chunk-JTMSFBCA.js.map +1 -0
  21. package/dist/{chunk-EFXVYQGT.js → chunk-MQZNDK5F.js} +39 -40
  22. package/dist/chunk-MQZNDK5F.js.map +1 -0
  23. package/dist/{chunk-QCX66KBM.js → chunk-SN64WNWE.js} +3 -3
  24. package/dist/{chunk-WUSEZFER.js → chunk-U46LYYRA.js} +3 -2
  25. package/dist/{chunk-WUSEZFER.js.map → chunk-U46LYYRA.js.map} +1 -1
  26. package/dist/{chunk-6PGXTLA4.js → chunk-U672FZVC.js} +2 -2
  27. package/dist/{chunk-AIBVAYHS.js → chunk-UE4Z3YMB.js} +2 -2
  28. package/dist/chunk-UE4Z3YMB.js.map +1 -0
  29. package/dist/{chunk-REHVGFJE.js → chunk-XMQIWPIR.js} +84 -32
  30. package/dist/chunk-XMQIWPIR.js.map +1 -0
  31. package/dist/{chunk-I3WF6L43.js → chunk-XYBHH3M5.js} +2 -2
  32. package/dist/{chunk-ECPFYHDX.js → chunk-ZBI6GFJD.js} +11 -11
  33. package/dist/chunk-ZBI6GFJD.js.map +1 -0
  34. package/dist/commands/build/marketplace.js +5 -4
  35. package/dist/commands/build/marketplace.js.map +1 -1
  36. package/dist/commands/build/plugins.js +7 -6
  37. package/dist/commands/build/plugins.js.map +1 -1
  38. package/dist/commands/compile.js +20 -16
  39. package/dist/commands/compile.js.map +1 -1
  40. package/dist/commands/doctor.js +106 -87
  41. package/dist/commands/doctor.js.map +1 -1
  42. package/dist/commands/edit.js +76 -48
  43. package/dist/commands/edit.js.map +1 -1
  44. package/dist/commands/eject.js +31 -18
  45. package/dist/commands/eject.js.map +1 -1
  46. package/dist/commands/init.js +17 -17
  47. package/dist/commands/list.js +10 -9
  48. package/dist/commands/list.js.map +1 -1
  49. package/dist/commands/new/marketplace.js +5 -4
  50. package/dist/commands/new/marketplace.js.map +1 -1
  51. package/dist/commands/search.js +14 -9
  52. package/dist/commands/search.js.map +1 -1
  53. package/dist/commands/share.js +20 -22
  54. package/dist/commands/share.js.map +1 -1
  55. package/dist/commands/uninstall.js +24 -19
  56. package/dist/commands/uninstall.js.map +1 -1
  57. package/dist/commands/update.js +110 -31
  58. package/dist/commands/update.js.map +1 -1
  59. package/dist/components/common/select-list.js +2 -2
  60. package/dist/components/common/skill-agent-summary.js +4 -3
  61. package/dist/components/common/summary-panel.js +5 -4
  62. package/dist/hooks/init.js +24 -25
  63. package/dist/hooks/init.js.map +1 -1
  64. package/dist/load-agent-defs-5BSECHE6.js +14 -0
  65. package/dist/{recompile-project-agents-KYK44C24.js → recompile-project-agents-U3UGHPWG.js} +8 -8
  66. package/dist/{source-loader-G5I4RNUP.js → source-loader-E2Y5MMN5.js} +4 -4
  67. package/package.json +1 -1
  68. package/dist/chunk-3PJZ4QNJ.js.map +0 -1
  69. package/dist/chunk-AIBVAYHS.js.map +0 -1
  70. package/dist/chunk-APWMMZOK.js.map +0 -1
  71. package/dist/chunk-E45IT3HC.js.map +0 -1
  72. package/dist/chunk-ECPFYHDX.js.map +0 -1
  73. package/dist/chunk-EFXVYQGT.js.map +0 -1
  74. package/dist/chunk-FQF6VHO3.js.map +0 -1
  75. package/dist/chunk-H5E6IO2L.js.map +0 -1
  76. package/dist/chunk-IAQFZFWD.js.map +0 -1
  77. package/dist/chunk-ORO2T4K2.js +0 -96
  78. package/dist/chunk-ORO2T4K2.js.map +0 -1
  79. package/dist/chunk-R7GKQBZJ.js.map +0 -1
  80. package/dist/chunk-REHVGFJE.js.map +0 -1
  81. package/dist/load-agent-defs-5U5KAURA.js +0 -14
  82. /package/dist/{chunk-IXVGBUWI.js.map → chunk-EC3JXT23.js.map} +0 -0
  83. /package/dist/{chunk-TVEDNGVP.js.map → chunk-H6WUOW5F.js.map} +0 -0
  84. /package/dist/{chunk-7BHDKEGK.js.map → chunk-JNRACLNS.js.map} +0 -0
  85. /package/dist/{chunk-QCX66KBM.js.map → chunk-SN64WNWE.js.map} +0 -0
  86. /package/dist/{chunk-6PGXTLA4.js.map → chunk-U672FZVC.js.map} +0 -0
  87. /package/dist/{chunk-I3WF6L43.js.map → chunk-XYBHH3M5.js.map} +0 -0
  88. /package/dist/{load-agent-defs-5U5KAURA.js.map → load-agent-defs-5BSECHE6.js.map} +0 -0
  89. /package/dist/{recompile-project-agents-KYK44C24.js.map → recompile-project-agents-U3UGHPWG.js.map} +0 -0
  90. /package/dist/{source-loader-G5I4RNUP.js.map → source-loader-E2Y5MMN5.js.map} +0 -0
@@ -1,32 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  unofferablePlacementsFound
4
- } from "../chunk-ECPFYHDX.js";
4
+ } from "../chunk-ZBI6GFJD.js";
5
5
  import {
6
6
  hostCompileNotices
7
- } from "../chunk-6PGXTLA4.js";
7
+ } from "../chunk-U672FZVC.js";
8
8
  import {
9
9
  detectBothInstallations,
10
10
  reconcileTypesFromDisk
11
- } from "../chunk-R7GKQBZJ.js";
11
+ } from "../chunk-CKBWEWHZ.js";
12
12
  import {
13
13
  compileAgents,
14
14
  discoverInstalledSkills
15
- } from "../chunk-REHVGFJE.js";
15
+ } from "../chunk-XMQIWPIR.js";
16
16
  import {
17
17
  loadAgentDefs
18
- } from "../chunk-7BHDKEGK.js";
19
- import "../chunk-IXVGBUWI.js";
20
- import "../chunk-EFXVYQGT.js";
18
+ } from "../chunk-JNRACLNS.js";
19
+ import "../chunk-EC3JXT23.js";
20
+ import "../chunk-MQZNDK5F.js";
21
21
  import {
22
+ BaseCommand,
23
+ EXIT_CODES,
22
24
  providerFlag,
23
25
  providerNamedBy,
24
26
  refuseAnAmbiguousInstallation
25
- } from "../chunk-ORO2T4K2.js";
27
+ } from "../chunk-JTMSFBCA.js";
26
28
  import {
27
- BaseCommand,
28
- EXIT_CODES
29
- } from "../chunk-IAQFZFWD.js";
29
+ namedByActiveEntries
30
+ } from "../chunk-FACDJH6O.js";
30
31
  import {
31
32
  ConfigLoadError,
32
33
  ERROR_MESSAGES,
@@ -49,15 +50,15 @@ import {
49
50
  skillMetadataUnusableDetail,
50
51
  skillMetadataUnusableError,
51
52
  verbose
52
- } from "../chunk-E45IT3HC.js";
53
+ } from "../chunk-ENET4IF6.js";
53
54
  import {
54
55
  plural
55
- } from "../chunk-AIBVAYHS.js";
56
+ } from "../chunk-UE4Z3YMB.js";
56
57
  import {
57
58
  STANDARD_FILES,
58
59
  effectivelyExcludedSkillIds,
59
60
  isActiveAt
60
- } from "../chunk-WUSEZFER.js";
61
+ } from "../chunk-U46LYYRA.js";
61
62
  import "../chunk-GHHJYNAN.js";
62
63
 
63
64
  // src/cli/commands/compile.ts
@@ -83,10 +84,12 @@ var Compile = class _Compile extends BaseCommand {
83
84
  const { flags } = await this.parse(_Compile);
84
85
  setVerbose(flags.verbose);
85
86
  const cwd = process.cwd();
87
+ const namedProvider = providerNamedBy(flags.provider);
88
+ await this.sayWhenTheGlobalInstallationStandsIn(namedProvider);
86
89
  await refuseAnAmbiguousInstallation(
87
90
  cwd,
88
91
  "compile",
89
- providerNamedBy(flags.provider),
92
+ namedProvider,
90
93
  (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS })
91
94
  );
92
95
  await this.ensureConfigReadable(cwd);
@@ -202,8 +205,9 @@ var Compile = class _Compile extends BaseCommand {
202
205
  async warnScopeDroppedStackPairs(projectDir) {
203
206
  const loaded = await loadProjectConfig(projectDir);
204
207
  if (!loaded?.config.stack) return;
208
+ const namedBy = namedByActiveEntries(loaded.config.skills);
205
209
  for (const [skillId, agentNames] of findScopeDroppedStackPairs(loaded.config)) {
206
- this.warn(scopeBlockedStackAssignment(agentNames, skillId));
210
+ this.warn(scopeBlockedStackAssignment(agentNames, skillId, namedBy));
207
211
  }
208
212
  }
209
213
  /** Points at global-scope agents so "No agents to recompile" doesn't read as a silent no-op. */
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/compile.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport os from \"os\";\nimport { unique } from \"remeda\";\nimport { BaseCommand } from \"../base-command\";\nimport { setVerbose, verbose } from \"../utils/logger\";\nimport {\n detectBothInstallations,\n type BothInstallations,\n loadAgentDefs,\n type AgentDefs,\n compileAgents,\n type CompilationResult,\n discoverInstalledSkills,\n type DiscoveredSkills,\n} from \"../lib/operations\";\nimport {\n ConfigLoadError,\n effectivelyExcludedSkillIds,\n isActiveAt,\n loadProjectConfig,\n loadInstalledConfig,\n resolveSource,\n} from \"../lib/configuration\";\nimport { getStackSkillIds, resolveAgentConfigToSkills } from \"../lib/stacks\";\nimport { loadSkillsMatrixFromSource, type UnusableSkillMetadata } from \"../lib/loading\";\nimport { STANDARD_FILES } from \"../consts\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { plural } from \"../utils/string\";\nimport {\n ERROR_MESSAGES,\n STATUS_MESSAGES,\n INFO_MESSAGES,\n configTypesRefreshFailed,\n globalScopedAgentsHint,\n recompileSummary,\n registeredProjectUpdateFailed,\n scopeBlockedStackAssignment,\n skillMetadataUnusableDetail,\n skillMetadataUnusableError,\n} from \"../utils/messages\";\nimport { reconcileTypesFromDisk, type GateReport } from \"../lib/config-gate/index.js\";\nimport { unofferablePlacementsFound } from \"../lib/hosts/configured-placements.js\";\nimport { providerInUse } from \"../lib/installation/install-layout.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { hostCompileNotices } from \"../lib/hosts/host-compile-notices.js\";\nimport type { Installation } from \"../lib/installation\";\nimport type { SkillScope } from \"../types/config\";\nimport type {\n AgentDefinition,\n AgentName,\n MergedSkillsMatrix,\n ProjectConfig,\n SkillDefinitionMap,\n SkillId,\n StackAgentConfig,\n} from \"../types\";\n\nexport default class Compile extends BaseCommand {\n static summary = \"Compile agents using local skills and agent definitions\";\n\n static description =\n \"Compile agents with resolved skill references. Compiles to the Claude plugin directory.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --verbose\",\n ];\n\n static flags = {\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n provider: providerFlag(),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Compile);\n setVerbose(flags.verbose);\n const cwd = process.cwd();\n\n // First: `providerInUse` below picks by roster order when a scope holds both providers.\n await refuseAnAmbiguousInstallation(\n cwd,\n \"compile\",\n providerNamedBy(flags.provider),\n (message) => this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n await this.ensureConfigReadable(cwd);\n const installations = await this.detectInstallations(cwd);\n await this.refuseUnofferablePlacements(cwd);\n await this.resolveAndLogSource(cwd);\n const agentDefs = await this.loadAgentDefsOrFail();\n await this.runCompilePasses(installations, agentDefs, cwd);\n await this.reportWhatThisHostCannotCarry(installations, cwd);\n }\n\n /** Runs after the passes, so the trust notice describes the tree this run wrote. */\n private async reportWhatThisHostCannotCarry(\n installations: BothInstallations,\n cwd: string,\n ): Promise<void> {\n const root = rootThisRunCompiled(installations, cwd);\n\n for (const notice of await hostCompileNotices(providerInUse(root), cwd)) {\n this.log(notice);\n }\n }\n\n private async detectInstallations(cwd: string): Promise<BothInstallations> {\n let installations: BothInstallations;\n try {\n installations = await detectBothInstallations(cwd);\n } catch (error) {\n // Compiling config-less would resurrect every deselected agent.\n if (error instanceof ConfigLoadError) {\n this.error(error.message, { exit: EXIT_CODES.ERROR });\n }\n throw error;\n }\n\n if (!installations.global && !installations.project) {\n this.error(ERROR_MESSAGES.NO_INSTALLATION, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n return installations;\n }\n\n /**\n * Re-checked here because config.ts names no provider, so a copied installation folder can hold\n * a configuration its host never vetted at install.\n */\n private async refuseUnofferablePlacements(cwd: string): Promise<void> {\n const [finding] = await unofferablePlacementsFound(cwd);\n if (finding !== undefined) this.error(finding, { exit: EXIT_CODES.ERROR });\n }\n\n /** No `--marketplace`: an installation recompiles against the marketplace config.ts recorded. */\n private async resolveAndLogSource(projectDir: string): Promise<void> {\n this.log(STATUS_MESSAGES.RESOLVING_SOURCE);\n try {\n // ABORT on an unreadable config (already refused earlier by `detectInstallations`).\n const sourceConfig = await resolveSource({ caller: \"stored\", projectDir });\n this.log(`Marketplace: ${sourceConfig.sourceOrigin}`);\n } catch (error) {\n this.log(ERROR_MESSAGES.FAILED_RESOLVE_SOURCE);\n this.handleError(error);\n }\n }\n\n private async loadAgentDefsOrFail(): Promise<AgentDefs> {\n this.log(STATUS_MESSAGES.LOADING_AGENT_PARTIALS);\n try {\n const defs = await loadAgentDefs();\n this.log(\"Agent partials loaded\");\n verbose(` Agents: ${defs.agentSourcePaths.agentsDir}`);\n return defs;\n } catch (error) {\n this.log(ERROR_MESSAGES.FAILED_LOAD_AGENT_PARTIALS);\n this.handleError(error);\n }\n }\n\n private async runCompilePasses(\n installations: BothInstallations,\n agentDefs: AgentDefs,\n cwd: string,\n ): Promise<void> {\n const passes = buildCompilePasses(installations, cwd, agentDefs);\n\n let passesCompiled = 0;\n for (const pass of passes) {\n const compiled = await this.runCompilePass(pass, cwd);\n if (compiled) passesCompiled++;\n }\n\n if (passesCompiled === 0) {\n this.error(ERROR_MESSAGES.NO_SKILLS_TO_COMPILE, { exit: EXIT_CODES.ERROR });\n }\n }\n\n /** Refuses the run, before anything is written, when an installed skill's metadata is unusable. */\n private async discoverAllSkills(projectDir: string): Promise<DiscoveredSkills> {\n this.log(STATUS_MESSAGES.DISCOVERING_SKILLS);\n const result = await discoverInstalledSkills(projectDir);\n if (result.unusableMetadata.length > 0) {\n this.refuseUnusableSkillMetadata(result.unusableMetadata);\n }\n if (result.totalSkillCount === 0) return result;\n this.log(formatDiscoveryMessage(result));\n return result;\n }\n\n /** Detail is logged, not raised: oclif hard-wraps error text, which breaks copyable paths. */\n private refuseUnusableSkillMetadata(entries: UnusableSkillMetadata[]): never {\n for (const entry of entries) {\n this.log(skillMetadataUnusableDetail(entry));\n }\n this.error(skillMetadataUnusableError(entries), { exit: EXIT_CODES.ERROR });\n }\n\n /** The resolver drops a missing stack skill silently except at verbose level. */\n private async warnUnresolvedStackSkills(\n projectDir: string,\n allSkills: SkillDefinitionMap,\n ): Promise<void> {\n const loaded = await loadProjectConfig(projectDir);\n if (!loaded?.config.stack) return;\n\n const excludedIds = effectivelyExcludedSkillIds(loaded.config.skills);\n const unresolved = getStackSkillIds(loaded.config.stack).filter(\n (id) => !excludedIds.has(id) && !(id in allSkills),\n );\n\n for (const id of unresolved) {\n this.warn(\n `Skill '${id}' is configured but was not found — agents will be compiled without it.`,\n );\n }\n }\n\n /**\n * A hand-edited config.ts can give a global sub-agent a project-scoped skill, which the compile\n * filter silently drops on every run.\n */\n private async warnScopeDroppedStackPairs(projectDir: string): Promise<void> {\n const loaded = await loadProjectConfig(projectDir);\n if (!loaded?.config.stack) return;\n\n for (const [skillId, agentNames] of findScopeDroppedStackPairs(loaded.config)) {\n this.warn(scopeBlockedStackAssignment(agentNames, skillId));\n }\n }\n\n /** Points at global-scope agents so \"No agents to recompile\" doesn't read as a silent no-op. */\n private async hintGlobalScopedAgents(projectDir: string): Promise<void> {\n const loaded = await loadInstalledConfig(projectDir);\n if (!loaded) return;\n\n const globalAgentCount = loaded.config.agents.filter((agent) =>\n isActiveAt(agent, \"global\"),\n ).length;\n if (globalAgentCount === 0) return;\n\n this.log(globalScopedAgentsHint(globalAgentCount));\n }\n\n /**\n * Seats the matrix singleton the render reads (else local skills lose their stated usage), and\n * returns it, `null` on failure: the render degrades, the type refresh skips. Extra sources only\n * annotate skills, so skipping them keeps output identical and the path offline.\n */\n private async seatMatrixForPass(projectDir: string): Promise<MergedSkillsMatrix | null> {\n try {\n const { matrix: seated } = await loadSkillsMatrixFromSource({\n projectDir,\n skipExtraSources: true,\n matrixOnly: true,\n });\n return seated;\n } catch (error) {\n this.warn(`Failed to load skills matrix for ${projectDir}: ${getErrorMessage(error)}`);\n return null;\n }\n }\n\n /**\n * Regenerates config-types.ts after a hand-edit; failure only warns, as the agents are written.\n * Skipped without a catalogue, since unions derived from none would be wrong, not just stale.\n */\n private async refreshConfigTypes(\n pass: CompilePass,\n cwd: string,\n seatedMatrix: MergedSkillsMatrix | null,\n ): Promise<void> {\n if (!seatedMatrix) {\n this.warn(\n configTypesRefreshFailed(`no skills catalogue could be loaded for ${pass.projectDir}`),\n );\n return;\n }\n\n let report: GateReport;\n try {\n const loaded = await loadInstalledConfig(pass.projectDir);\n if (!loaded) {\n verbose(\n `No config found at ${pass.projectDir} — skipping ${STANDARD_FILES.CONFIG_TYPES_TS} refresh`,\n );\n return;\n }\n\n // A global pass's fan-out must not reach back into the invoking directory.\n report = await reconcileTypesFromDisk(\n pass.projectDir,\n loaded.config,\n { matrix: seatedMatrix, agents: pass.agents },\n { currentProjectDir: cwd },\n );\n this.log(INFO_MESSAGES.CONFIG_TYPES_REFRESHED);\n } catch (error) {\n this.warn(configTypesRefreshFailed(getErrorMessage(error)));\n return;\n }\n\n this.reportPropagation(report);\n }\n\n /** Outside the refresh's catch: an unreachable project is not a failed refresh. */\n private reportPropagation(report: GateReport): void {\n this.reportProjectsOutOfReach(report.propagated);\n for (const projectPath of report.propagated.failed) {\n this.warn(registeredProjectUpdateFailed(projectPath));\n }\n this.reportFanOut(report);\n }\n\n private async runCompilePass(pass: CompilePass, cwd: string): Promise<boolean> {\n const { projectDir } = pass;\n this.announcePass(pass);\n\n const seatedMatrix = await this.seatMatrixForPass(projectDir);\n const { allSkills, totalSkillCount } = await this.discoverAllSkills(projectDir);\n const compiles = await this.announceWhetherPassCompiles(pass, totalSkillCount);\n // A skipped pass is a refused run, which writes nothing, config-types.ts included.\n if (!compiles) return false;\n\n await this.warnUnresolvedStackSkills(projectDir, allSkills);\n await this.warnScopeDroppedStackPairs(projectDir);\n await this.recompilePassAgents(pass, allSkills);\n await this.refreshConfigTypes(pass, cwd, seatedMatrix);\n\n this.log(\"\");\n this.logSuccess(`${pass.label} compile complete!`);\n this.log(\"\");\n return true;\n }\n\n private announcePass({ label, projectDir, installation }: CompilePass): void {\n this.log(\"\");\n this.log(`Compiling ${label.toLowerCase()} agents...`);\n this.log(\"\");\n\n verbose(` Project: ${projectDir}`);\n verbose(` Agents: ${installation.agentsDir}`);\n }\n\n /** A pass with no skills still compiles when its config declares base agents only. */\n private async announceWhetherPassCompiles(\n pass: CompilePass,\n totalSkillCount: number,\n ): Promise<boolean> {\n if (totalSkillCount > 0) return true;\n\n const passName = pass.label.toLowerCase();\n if (await declaresOnlyBaseAgents(pass)) {\n this.log(`No skills configured for ${passName} pass, compiling base agents`);\n return true;\n }\n\n this.log(`No skills found for ${passName} pass, skipping`);\n return false;\n }\n\n private async recompilePassAgents(pass: CompilePass, skills: SkillDefinitionMap): Promise<void> {\n const { projectDir, installation, sourcePath, scopeFilter } = pass;\n\n this.log(STATUS_MESSAGES.RECOMPILING_AGENTS);\n try {\n const recompileResult = await compileAgents({\n projectDir,\n sourcePath,\n skills,\n pluginDir: projectDir,\n outputDir: installation.agentsDir,\n ...(scopeFilter !== undefined && { scopeFilter }),\n });\n await this.reportRecompile(recompileResult, pass);\n } catch (error) {\n this.log(ERROR_MESSAGES.FAILED_COMPILE_AGENTS);\n this.handleError(error);\n }\n }\n\n private async reportRecompile(\n { compiled, rewritten, failed, warnings }: CompilationResult,\n { label, projectDir }: CompilePass,\n ): Promise<void> {\n const summary = recompileSummary(\n rewritten.length,\n compiled.length - rewritten.length,\n `${label.toLowerCase()} agent`,\n );\n\n if (failed.length > 0) {\n this.log(`${summary} (${failed.length} failed)`);\n for (const warning of warnings) {\n this.warn(warning);\n }\n } else if (compiled.length > 0) {\n this.log(summary);\n } else {\n this.log(INFO_MESSAGES.NO_AGENTS_TO_RECOMPILE);\n if (label === \"Project\") {\n await this.hintGlobalScopedAgents(projectDir);\n }\n }\n\n if (compiled.length > 0) {\n verbose(` Compiled: ${compiled.join(\", \")}`);\n }\n }\n}\n\ntype CompilePass = {\n label: \"Global\" | \"Project\";\n projectDir: string;\n installation: Installation;\n sourcePath: string;\n agents: Partial<Record<AgentName, AgentDefinition>>;\n scopeFilter?: SkillScope;\n};\n\n/**\n * One pass: the project's when there is one (writing nothing outside it), else the global's.\n * `scopeFilter` keeps inlined global agents out of the project's agents directory.\n */\nfunction buildCompilePasses(\n installations: BothInstallations,\n cwd: string,\n agentDefs: AgentDefs,\n): CompilePass[] {\n const { sourcePath, agents } = agentDefs;\n\n if (installations.project) {\n return [\n {\n label: \"Project\",\n projectDir: cwd,\n installation: installations.project,\n sourcePath,\n agents,\n ...(installations.hasBoth && { scopeFilter: \"project\" as const }),\n },\n ];\n }\n\n if (installations.global) {\n return [\n {\n label: \"Global\",\n projectDir: os.homedir(),\n installation: installations.global,\n sourcePath,\n agents,\n },\n ];\n }\n\n return [];\n}\n\n/** Mirrors the root {@link buildCompilePasses} picks. */\nfunction rootThisRunCompiled(installations: BothInstallations, cwd: string): string {\n return installations.project ? cwd : os.homedir();\n}\n\n/**\n * A skill-less pass still compiles a config of base agents only. One that declares skills none of\n * which are on disk lost them, and is skipped rather than recompiled without them.\n */\nasync function declaresOnlyBaseAgents(pass: CompilePass): Promise<boolean> {\n const loaded = await loadInstalledConfig(pass.projectDir);\n if (!loaded) return false;\n\n const { skills, agents } = loaded.config;\n const declaresASkill = skills.some((skill) => !skill.excluded);\n const compilesAnAgent = agents.some((agent) =>\n pass.scopeFilter === undefined ? !agent.excluded : isActiveAt(agent, pass.scopeFilter),\n );\n return !declaresASkill && compilesAnAgent;\n}\n\n/** Project-scoped skills a global sub-agent's stack names, grouped by skill. */\nfunction findScopeDroppedStackPairs(config: ProjectConfig): [SkillId, AgentName[]][] {\n const stack = config.stack ?? {};\n const globalAgentNames = config.agents\n .filter((agent) => isActiveAt(agent, \"global\"))\n .map((agent) => agent.name);\n const projectScopedIds = unique(\n config.skills.filter((skill) => isActiveAt(skill, \"project\")).map((skill) => skill.id),\n );\n\n return projectScopedIds\n .map((skillId): [SkillId, AgentName[]] => [\n skillId,\n globalAgentNames.filter((agentName) => stackAssignsSkill(stack[agentName], skillId)),\n ])\n .filter(([, agentNames]) => agentNames.length > 0);\n}\n\nfunction stackAssignsSkill(agentStack: StackAgentConfig | undefined, skillId: SkillId): boolean {\n if (!agentStack) return false;\n return resolveAgentConfigToSkills(agentStack).some((ref) => ref.id === skillId);\n}\n\nfunction formatDiscoveryMessage(result: DiscoveredSkills): string {\n const { totalSkillCount, pluginSkillCount } = result;\n const localCount = totalSkillCount - pluginSkillCount;\n\n if (pluginSkillCount > 0 && localCount > 0) {\n return `Discovered ${plural(totalSkillCount, \"skill\")} (${pluginSkillCount} from plugins, ${localCount} local)`;\n }\n\n return pluginSkillCount > 0\n ? `Discovered ${plural(pluginSkillCount, \"skill\")} from plugins`\n : `Discovered ${plural(totalSkillCount, \"local skill\")}`;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/compile.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport os from \"os\";\nimport { unique } from \"remeda\";\nimport { BaseCommand } from \"../base-command\";\nimport { setVerbose, verbose } from \"../utils/logger\";\nimport {\n detectBothInstallations,\n type BothInstallations,\n loadAgentDefs,\n type AgentDefs,\n compileAgents,\n type CompilationResult,\n discoverInstalledSkills,\n type DiscoveredSkills,\n} from \"../lib/operations\";\nimport {\n ConfigLoadError,\n effectivelyExcludedSkillIds,\n isActiveAt,\n loadProjectConfig,\n loadInstalledConfig,\n resolveSource,\n} from \"../lib/configuration\";\nimport { getStackSkillIds, resolveAgentConfigToSkills } from \"../lib/stacks\";\nimport { loadSkillsMatrixFromSource, type UnusableSkillMetadata } from \"../lib/loading\";\nimport { STANDARD_FILES } from \"../consts\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { plural } from \"../utils/string\";\nimport {\n ERROR_MESSAGES,\n STATUS_MESSAGES,\n INFO_MESSAGES,\n configTypesRefreshFailed,\n globalScopedAgentsHint,\n recompileSummary,\n registeredProjectUpdateFailed,\n scopeBlockedStackAssignment,\n skillMetadataUnusableDetail,\n skillMetadataUnusableError,\n} from \"../utils/messages\";\nimport { reconcileTypesFromDisk, type GateReport } from \"../lib/config-gate/index.js\";\nimport { namedByActiveEntries } from \"../lib/configuration/scope-diff.js\";\nimport { unofferablePlacementsFound } from \"../lib/hosts/configured-placements.js\";\nimport { providerInUse } from \"../lib/installation/install-layout.js\";\nimport {\n providerFlag,\n providerNamedBy,\n refuseAnAmbiguousInstallation,\n} from \"../lib/installation/provider-flag.js\";\nimport { hostCompileNotices } from \"../lib/hosts/host-compile-notices.js\";\nimport type { Installation } from \"../lib/installation\";\nimport type { SkillScope } from \"../types/config\";\nimport type {\n AgentDefinition,\n AgentName,\n MergedSkillsMatrix,\n ProjectConfig,\n SkillDefinitionMap,\n SkillId,\n StackAgentConfig,\n} from \"../types\";\n\nexport default class Compile extends BaseCommand {\n static summary = \"Compile agents using local skills and agent definitions\";\n\n static description =\n \"Compile agents with resolved skill references. Compiles to the Claude plugin directory.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --verbose\",\n ];\n\n static flags = {\n verbose: Flags.boolean({\n char: \"v\",\n description: \"Enable verbose logging\",\n default: false,\n }),\n provider: providerFlag(),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Compile);\n setVerbose(flags.verbose);\n const cwd = process.cwd();\n const namedProvider = providerNamedBy(flags.provider);\n\n await this.sayWhenTheGlobalInstallationStandsIn(namedProvider);\n // First: `providerInUse` below picks by roster order when a scope holds both providers.\n await refuseAnAmbiguousInstallation(cwd, \"compile\", namedProvider, (message) =>\n this.error(message, { exit: EXIT_CODES.INVALID_ARGS }),\n );\n await this.ensureConfigReadable(cwd);\n const installations = await this.detectInstallations(cwd);\n await this.refuseUnofferablePlacements(cwd);\n await this.resolveAndLogSource(cwd);\n const agentDefs = await this.loadAgentDefsOrFail();\n await this.runCompilePasses(installations, agentDefs, cwd);\n await this.reportWhatThisHostCannotCarry(installations, cwd);\n }\n\n /** Runs after the passes, so the trust notice describes the tree this run wrote. */\n private async reportWhatThisHostCannotCarry(\n installations: BothInstallations,\n cwd: string,\n ): Promise<void> {\n const root = rootThisRunCompiled(installations, cwd);\n\n for (const notice of await hostCompileNotices(providerInUse(root), cwd)) {\n this.log(notice);\n }\n }\n\n private async detectInstallations(cwd: string): Promise<BothInstallations> {\n let installations: BothInstallations;\n try {\n installations = await detectBothInstallations(cwd);\n } catch (error) {\n // Compiling config-less would resurrect every deselected agent.\n if (error instanceof ConfigLoadError) {\n this.error(error.message, { exit: EXIT_CODES.ERROR });\n }\n throw error;\n }\n\n if (!installations.global && !installations.project) {\n this.error(ERROR_MESSAGES.NO_INSTALLATION, {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n return installations;\n }\n\n /**\n * Re-checked here because config.ts names no provider, so a copied installation folder can hold\n * a configuration its host never vetted at install.\n */\n private async refuseUnofferablePlacements(cwd: string): Promise<void> {\n const [finding] = await unofferablePlacementsFound(cwd);\n if (finding !== undefined) this.error(finding, { exit: EXIT_CODES.ERROR });\n }\n\n /** No `--marketplace`: an installation recompiles against the marketplace config.ts recorded. */\n private async resolveAndLogSource(projectDir: string): Promise<void> {\n this.log(STATUS_MESSAGES.RESOLVING_SOURCE);\n try {\n // ABORT on an unreadable config (already refused earlier by `detectInstallations`).\n const sourceConfig = await resolveSource({ caller: \"stored\", projectDir });\n this.log(`Marketplace: ${sourceConfig.sourceOrigin}`);\n } catch (error) {\n this.log(ERROR_MESSAGES.FAILED_RESOLVE_SOURCE);\n this.handleError(error);\n }\n }\n\n private async loadAgentDefsOrFail(): Promise<AgentDefs> {\n this.log(STATUS_MESSAGES.LOADING_AGENT_PARTIALS);\n try {\n const defs = await loadAgentDefs();\n this.log(\"Agent partials loaded\");\n verbose(` Agents: ${defs.agentSourcePaths.agentsDir}`);\n return defs;\n } catch (error) {\n this.log(ERROR_MESSAGES.FAILED_LOAD_AGENT_PARTIALS);\n this.handleError(error);\n }\n }\n\n private async runCompilePasses(\n installations: BothInstallations,\n agentDefs: AgentDefs,\n cwd: string,\n ): Promise<void> {\n const passes = buildCompilePasses(installations, cwd, agentDefs);\n\n let passesCompiled = 0;\n for (const pass of passes) {\n const compiled = await this.runCompilePass(pass, cwd);\n if (compiled) passesCompiled++;\n }\n\n if (passesCompiled === 0) {\n this.error(ERROR_MESSAGES.NO_SKILLS_TO_COMPILE, { exit: EXIT_CODES.ERROR });\n }\n }\n\n /** Refuses the run, before anything is written, when an installed skill's metadata is unusable. */\n private async discoverAllSkills(projectDir: string): Promise<DiscoveredSkills> {\n this.log(STATUS_MESSAGES.DISCOVERING_SKILLS);\n const result = await discoverInstalledSkills(projectDir);\n if (result.unusableMetadata.length > 0) {\n this.refuseUnusableSkillMetadata(result.unusableMetadata);\n }\n if (result.totalSkillCount === 0) return result;\n this.log(formatDiscoveryMessage(result));\n return result;\n }\n\n /** Detail is logged, not raised: oclif hard-wraps error text, which breaks copyable paths. */\n private refuseUnusableSkillMetadata(entries: UnusableSkillMetadata[]): never {\n for (const entry of entries) {\n this.log(skillMetadataUnusableDetail(entry));\n }\n this.error(skillMetadataUnusableError(entries), { exit: EXIT_CODES.ERROR });\n }\n\n /** The resolver drops a missing stack skill silently except at verbose level. */\n private async warnUnresolvedStackSkills(\n projectDir: string,\n allSkills: SkillDefinitionMap,\n ): Promise<void> {\n const loaded = await loadProjectConfig(projectDir);\n if (!loaded?.config.stack) return;\n\n const excludedIds = effectivelyExcludedSkillIds(loaded.config.skills);\n const unresolved = getStackSkillIds(loaded.config.stack).filter(\n (id) => !excludedIds.has(id) && !(id in allSkills),\n );\n\n for (const id of unresolved) {\n this.warn(\n `Skill '${id}' is configured but was not found — agents will be compiled without it.`,\n );\n }\n }\n\n /**\n * A hand-edited config.ts can give a global sub-agent a project-scoped skill, which the compile\n * filter silently drops on every run.\n */\n private async warnScopeDroppedStackPairs(projectDir: string): Promise<void> {\n const loaded = await loadProjectConfig(projectDir);\n if (!loaded?.config.stack) return;\n\n const namedBy = namedByActiveEntries(loaded.config.skills);\n for (const [skillId, agentNames] of findScopeDroppedStackPairs(loaded.config)) {\n this.warn(scopeBlockedStackAssignment(agentNames, skillId, namedBy));\n }\n }\n\n /** Points at global-scope agents so \"No agents to recompile\" doesn't read as a silent no-op. */\n private async hintGlobalScopedAgents(projectDir: string): Promise<void> {\n const loaded = await loadInstalledConfig(projectDir);\n if (!loaded) return;\n\n const globalAgentCount = loaded.config.agents.filter((agent) =>\n isActiveAt(agent, \"global\"),\n ).length;\n if (globalAgentCount === 0) return;\n\n this.log(globalScopedAgentsHint(globalAgentCount));\n }\n\n /**\n * Seats the matrix singleton the render reads (else local skills lose their stated usage), and\n * returns it, `null` on failure: the render degrades, the type refresh skips. Extra sources only\n * annotate skills, so skipping them keeps output identical and the path offline.\n */\n private async seatMatrixForPass(projectDir: string): Promise<MergedSkillsMatrix | null> {\n try {\n const { matrix: seated } = await loadSkillsMatrixFromSource({\n projectDir,\n skipExtraSources: true,\n matrixOnly: true,\n });\n return seated;\n } catch (error) {\n this.warn(`Failed to load skills matrix for ${projectDir}: ${getErrorMessage(error)}`);\n return null;\n }\n }\n\n /**\n * Regenerates config-types.ts after a hand-edit; failure only warns, as the agents are written.\n * Skipped without a catalogue, since unions derived from none would be wrong, not just stale.\n */\n private async refreshConfigTypes(\n pass: CompilePass,\n cwd: string,\n seatedMatrix: MergedSkillsMatrix | null,\n ): Promise<void> {\n if (!seatedMatrix) {\n this.warn(\n configTypesRefreshFailed(`no skills catalogue could be loaded for ${pass.projectDir}`),\n );\n return;\n }\n\n let report: GateReport;\n try {\n const loaded = await loadInstalledConfig(pass.projectDir);\n if (!loaded) {\n verbose(\n `No config found at ${pass.projectDir} — skipping ${STANDARD_FILES.CONFIG_TYPES_TS} refresh`,\n );\n return;\n }\n\n // A global pass's fan-out must not reach back into the invoking directory.\n report = await reconcileTypesFromDisk(\n pass.projectDir,\n loaded.config,\n { matrix: seatedMatrix, agents: pass.agents },\n { currentProjectDir: cwd },\n );\n this.log(INFO_MESSAGES.CONFIG_TYPES_REFRESHED);\n } catch (error) {\n this.warn(configTypesRefreshFailed(getErrorMessage(error)));\n return;\n }\n\n this.reportPropagation(report);\n }\n\n /** Outside the refresh's catch: an unreachable project is not a failed refresh. */\n private reportPropagation(report: GateReport): void {\n this.reportProjectsOutOfReach(report.propagated);\n for (const projectPath of report.propagated.failed) {\n this.warn(registeredProjectUpdateFailed(projectPath));\n }\n this.reportFanOut(report);\n }\n\n private async runCompilePass(pass: CompilePass, cwd: string): Promise<boolean> {\n const { projectDir } = pass;\n this.announcePass(pass);\n\n const seatedMatrix = await this.seatMatrixForPass(projectDir);\n const { allSkills, totalSkillCount } = await this.discoverAllSkills(projectDir);\n const compiles = await this.announceWhetherPassCompiles(pass, totalSkillCount);\n // A skipped pass is a refused run, which writes nothing, config-types.ts included.\n if (!compiles) return false;\n\n await this.warnUnresolvedStackSkills(projectDir, allSkills);\n await this.warnScopeDroppedStackPairs(projectDir);\n await this.recompilePassAgents(pass, allSkills);\n await this.refreshConfigTypes(pass, cwd, seatedMatrix);\n\n this.log(\"\");\n this.logSuccess(`${pass.label} compile complete!`);\n this.log(\"\");\n return true;\n }\n\n private announcePass({ label, projectDir, installation }: CompilePass): void {\n this.log(\"\");\n this.log(`Compiling ${label.toLowerCase()} agents...`);\n this.log(\"\");\n\n verbose(` Project: ${projectDir}`);\n verbose(` Agents: ${installation.agentsDir}`);\n }\n\n /** A pass with no skills still compiles when its config declares base agents only. */\n private async announceWhetherPassCompiles(\n pass: CompilePass,\n totalSkillCount: number,\n ): Promise<boolean> {\n if (totalSkillCount > 0) return true;\n\n const passName = pass.label.toLowerCase();\n if (await declaresOnlyBaseAgents(pass)) {\n this.log(`No skills configured for ${passName} pass, compiling base agents`);\n return true;\n }\n\n this.log(`No skills found for ${passName} pass, skipping`);\n return false;\n }\n\n private async recompilePassAgents(pass: CompilePass, skills: SkillDefinitionMap): Promise<void> {\n const { projectDir, installation, sourcePath, scopeFilter } = pass;\n\n this.log(STATUS_MESSAGES.RECOMPILING_AGENTS);\n try {\n const recompileResult = await compileAgents({\n projectDir,\n sourcePath,\n skills,\n pluginDir: projectDir,\n outputDir: installation.agentsDir,\n ...(scopeFilter !== undefined && { scopeFilter }),\n });\n await this.reportRecompile(recompileResult, pass);\n } catch (error) {\n this.log(ERROR_MESSAGES.FAILED_COMPILE_AGENTS);\n this.handleError(error);\n }\n }\n\n private async reportRecompile(\n { compiled, rewritten, failed, warnings }: CompilationResult,\n { label, projectDir }: CompilePass,\n ): Promise<void> {\n const summary = recompileSummary(\n rewritten.length,\n compiled.length - rewritten.length,\n `${label.toLowerCase()} agent`,\n );\n\n if (failed.length > 0) {\n this.log(`${summary} (${failed.length} failed)`);\n for (const warning of warnings) {\n this.warn(warning);\n }\n } else if (compiled.length > 0) {\n this.log(summary);\n } else {\n this.log(INFO_MESSAGES.NO_AGENTS_TO_RECOMPILE);\n if (label === \"Project\") {\n await this.hintGlobalScopedAgents(projectDir);\n }\n }\n\n if (compiled.length > 0) {\n verbose(` Compiled: ${compiled.join(\", \")}`);\n }\n }\n}\n\ntype CompilePass = {\n label: \"Global\" | \"Project\";\n projectDir: string;\n installation: Installation;\n sourcePath: string;\n agents: Partial<Record<AgentName, AgentDefinition>>;\n scopeFilter?: SkillScope;\n};\n\n/**\n * One pass: the project's when there is one (writing nothing outside it), else the global's.\n * `scopeFilter` keeps inlined global agents out of the project's agents directory.\n */\nfunction buildCompilePasses(\n installations: BothInstallations,\n cwd: string,\n agentDefs: AgentDefs,\n): CompilePass[] {\n const { sourcePath, agents } = agentDefs;\n\n if (installations.project) {\n return [\n {\n label: \"Project\",\n projectDir: cwd,\n installation: installations.project,\n sourcePath,\n agents,\n ...(installations.hasBoth && { scopeFilter: \"project\" as const }),\n },\n ];\n }\n\n if (installations.global) {\n return [\n {\n label: \"Global\",\n projectDir: os.homedir(),\n installation: installations.global,\n sourcePath,\n agents,\n },\n ];\n }\n\n return [];\n}\n\n/** Mirrors the root {@link buildCompilePasses} picks. */\nfunction rootThisRunCompiled(installations: BothInstallations, cwd: string): string {\n return installations.project ? cwd : os.homedir();\n}\n\n/**\n * A skill-less pass still compiles a config of base agents only. One that declares skills none of\n * which are on disk lost them, and is skipped rather than recompiled without them.\n */\nasync function declaresOnlyBaseAgents(pass: CompilePass): Promise<boolean> {\n const loaded = await loadInstalledConfig(pass.projectDir);\n if (!loaded) return false;\n\n const { skills, agents } = loaded.config;\n const declaresASkill = skills.some((skill) => !skill.excluded);\n const compilesAnAgent = agents.some((agent) =>\n pass.scopeFilter === undefined ? !agent.excluded : isActiveAt(agent, pass.scopeFilter),\n );\n return !declaresASkill && compilesAnAgent;\n}\n\n/** Project-scoped skills a global sub-agent's stack names, grouped by skill. */\nfunction findScopeDroppedStackPairs(config: ProjectConfig): [SkillId, AgentName[]][] {\n const stack = config.stack ?? {};\n const globalAgentNames = config.agents\n .filter((agent) => isActiveAt(agent, \"global\"))\n .map((agent) => agent.name);\n const projectScopedIds = unique(\n config.skills.filter((skill) => isActiveAt(skill, \"project\")).map((skill) => skill.id),\n );\n\n return projectScopedIds\n .map((skillId): [SkillId, AgentName[]] => [\n skillId,\n globalAgentNames.filter((agentName) => stackAssignsSkill(stack[agentName], skillId)),\n ])\n .filter(([, agentNames]) => agentNames.length > 0);\n}\n\nfunction stackAssignsSkill(agentStack: StackAgentConfig | undefined, skillId: SkillId): boolean {\n if (!agentStack) return false;\n return resolveAgentConfigToSkills(agentStack).some((ref) => ref.id === skillId);\n}\n\nfunction formatDiscoveryMessage(result: DiscoveredSkills): string {\n const { totalSkillCount, pluginSkillCount } = result;\n const localCount = totalSkillCount - pluginSkillCount;\n\n if (pluginSkillCount > 0 && localCount > 0) {\n return `Discovered ${plural(totalSkillCount, \"skill\")} (${pluginSkillCount} from plugins, ${localCount} local)`;\n }\n\n return pluginSkillCount > 0\n ? `Discovered ${plural(pluginSkillCount, \"skill\")} from plugins`\n : `Discovered ${plural(totalSkillCount, \"local skill\")}`;\n}\n"],"mappings":"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","names":[]}
@@ -1,32 +1,36 @@
1
1
  #!/usr/bin/env node
2
- import "../chunk-IXVGBUWI.js";
2
+ import "../chunk-EC3JXT23.js";
3
3
  import {
4
4
  filterExcludedEntries,
5
5
  listAgentFilesOf,
6
6
  listAgentMdFiles,
7
7
  splitAgentsByProvenance
8
- } from "../chunk-EFXVYQGT.js";
9
- import {
10
- ambiguityFinding
11
- } from "../chunk-ORO2T4K2.js";
8
+ } from "../chunk-MQZNDK5F.js";
12
9
  import {
13
10
  BaseCommand,
14
- EXIT_CODES
15
- } from "../chunk-IAQFZFWD.js";
11
+ EXIT_CODES,
12
+ ambiguityFinding
13
+ } from "../chunk-JTMSFBCA.js";
14
+ import "../chunk-FACDJH6O.js";
16
15
  import {
17
16
  ConfigDefaultExportError,
17
+ ConfigEvaluationError,
18
18
  ConfigLoadError,
19
+ ConfigSchemaError,
19
20
  INFO_MESSAGES,
20
21
  MarketplaceManifestRequiredError,
21
22
  MarketplaceNameRefusedError,
22
23
  MarketplaceRefusedError,
23
24
  MarketplaceUnreachableError,
25
+ NoSkillRulesError,
24
26
  SOURCE_ENV_VAR,
27
+ StacksLoadError,
25
28
  agentCodec,
26
29
  agentYamlGenerationSchema,
27
30
  agentsDir,
28
31
  askingEachMarketplaceItself,
29
- configDirsInPlay,
32
+ configsDeclaringNothing,
33
+ configsInPlay,
30
34
  declaresNoContent,
31
35
  detectInstallations,
32
36
  directoryExists,
@@ -34,15 +38,16 @@ import {
34
38
  findConfigLoadFailures,
35
39
  formatZodErrors,
36
40
  getErrorMessage,
37
- getInstalledConfigPath,
38
41
  getInstalledPluginsRegistryPath,
39
- getPluginManifestPath,
42
+ getProjectConfigPath,
40
43
  getProjectPluginsDir,
41
44
  getStackSkillIds,
42
45
  getUserPluginsDir,
46
+ getVerifiedPluginInstallPaths,
43
47
  glob,
44
48
  hostCompilesAgent,
45
49
  hostFor,
50
+ inheritedGlobalProvider,
46
51
  installBaseDir,
47
52
  invalidResult,
48
53
  isHomeDirectory,
@@ -53,7 +58,6 @@ import {
53
58
  listPluginDirNames,
54
59
  listRegisteredPluginInstalls,
55
60
  loadConfig,
56
- loadInstalledConfig,
57
61
  loadProjectConfigFromDir,
58
62
  loadSkillsMatrixFromSource,
59
63
  loadSourceRepoConfig,
@@ -89,14 +93,13 @@ import {
89
93
  validatePlugin,
90
94
  validateProjectConfig,
91
95
  validateSkillFrontmatter,
92
- validateSkillMetadata,
93
- verbose
94
- } from "../chunk-E45IT3HC.js";
96
+ validateSkillMetadata
97
+ } from "../chunk-ENET4IF6.js";
95
98
  import {
96
99
  matrix,
97
100
  plural,
98
101
  typedValues
99
- } from "../chunk-AIBVAYHS.js";
102
+ } from "../chunk-UE4Z3YMB.js";
100
103
  import {
101
104
  CLI_INVOKE_COMMAND,
102
105
  DEFAULT_BRANDING,
@@ -111,7 +114,7 @@ import {
111
114
  STANDARD_FILES,
112
115
  UI_SYMBOLS,
113
116
  effectivelyExcludedSkillIds
114
- } from "../chunk-WUSEZFER.js";
117
+ } from "../chunk-U46LYYRA.js";
115
118
  import "../chunk-GHHJYNAN.js";
116
119
 
117
120
  // src/cli/commands/doctor.ts
@@ -123,18 +126,11 @@ import os from "os";
123
126
  async function hostsOnDisk(projectDir) {
124
127
  const found = await detectInstallations(projectDir);
125
128
  if (inheritsTheGlobalInstallation(found)) return hostsOf(providerInUse(os.homedir()));
126
- const project = providerInUse(projectDir);
127
- return { project, global: globalBeside(project, found) };
129
+ return { project: providerInUse(projectDir), global: inheritedGlobalProvider(projectDir) };
128
130
  }
129
131
  function inheritsTheGlobalInstallation(found) {
130
132
  return found.length > 0 && found.every((installation) => installation.scope === "global");
131
133
  }
132
- function globalBeside(project, found) {
133
- const inherited = found.some(
134
- (installation) => installation.scope === "global" && installation.provider === project
135
- );
136
- return inherited ? project : providerInUse(os.homedir());
137
- }
138
134
  function hostsOf(provider) {
139
135
  return { project: provider, global: provider };
140
136
  }
@@ -162,29 +158,23 @@ async function readConfigState(projectDir, hosts) {
162
158
  }
163
159
  const inherited = isHomeDirectory(projectDir) ? null : await loadProjectConfigFromDir(os.homedir(), hosts.global);
164
160
  if (inherited && !declaresNoContent(inherited.config)) {
165
- return { kind: "loaded", config: inherited.config, inherited: true };
161
+ return {
162
+ kind: "loaded",
163
+ config: inherited.config,
164
+ inherited: true,
165
+ declaringNothingIn: await providerDeclaringNothingIn(projectDir)
166
+ };
166
167
  }
167
168
  return own ? { kind: "declares-nothing", config: own.config } : { kind: "absent" };
168
169
  }
170
+ async function providerDeclaringNothingIn(projectDir) {
171
+ const [leftover] = await configsDeclaringNothing(projectDir);
172
+ return leftover === void 0 ? null : leftover.provider;
173
+ }
169
174
  async function installedPluginSkillIds(baseDir, provider) {
170
- const plugins = await verifiedPlugins(baseDir, provider);
175
+ const plugins = await getVerifiedPluginInstallPaths(baseDir, provider);
171
176
  return new Set(plugins.map((plugin) => parseMarketplacePluginRef(plugin.pluginKey)));
172
177
  }
173
- async function verifiedPlugins(baseDir, provider) {
174
- const enabled = (await pluginsListedBy(provider, baseDir)).filter((plugin) => plugin.enabled);
175
- const onDisk = await Promise.all(
176
- enabled.map((plugin) => fileExists(getPluginManifestPath(plugin.installPath)))
177
- );
178
- return enabled.filter((_, index) => onDisk[index] === true);
179
- }
180
- async function pluginsListedBy(provider, baseDir) {
181
- try {
182
- return await hostFor(provider).listPlugins(baseDir);
183
- } catch (error) {
184
- verbose(`Failed to list installed plugins: ${getErrorMessage(error)}`);
185
- return [];
186
- }
187
- }
188
178
  async function unofferablePlacements({
189
179
  projectDir,
190
180
  hosts
@@ -302,6 +292,7 @@ async function validateSource(sourcePath, reader = "author") {
302
292
  }
303
293
  const sourceProjectConfig = await loadSourceRepoConfig(resolvedPath);
304
294
  const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;
295
+ const stacksRelFile = sourceProjectConfig?.stacksFile ?? STACKS_FILE_PATH;
305
296
  const skillsDir2 = path.join(resolvedPath, skillsDirRelPath);
306
297
  if (!await directoryExists(skillsDir2)) {
307
298
  return buildResult(
@@ -311,11 +302,11 @@ async function validateSource(sourcePath, reader = "author") {
311
302
  }
312
303
  const { pairIssues, validMetadataFiles } = await pairSkillFiles(skillsDir2);
313
304
  const skillIssues = await validateSkillsInTurn(skillsDir2, skillsDirRelPath, validMetadataFiles);
314
- const crossReferenceIssues = await checkCrossReferences(resolvedPath, reader);
305
+ const crossReferenceIssues = await checkCrossReferences(resolvedPath, stacksRelFile, reader);
315
306
  const extraIssues = await Promise.all([
316
307
  validateStacks(resolvedPath),
317
308
  validateAgents(resolvedPath),
318
- validateConfigFiles(resolvedPath)
309
+ validateConfigFiles(resolvedPath, stacksRelFile)
319
310
  ]);
320
311
  return buildResult(
321
312
  [...pairIssues, ...skillIssues, ...crossReferenceIssues, ...extraIssues.flat()],
@@ -371,17 +362,31 @@ var MANIFEST_REQUIRED_SEVERITY = {
371
362
  author: "warning",
372
363
  consumer: "error"
373
364
  };
374
- async function checkCrossReferences(resolvedPath, reader) {
365
+ async function checkCrossReferences(resolvedPath, stacksRelFile, reader) {
375
366
  try {
376
367
  await loadSkillsMatrixFromSource({ sourceFlag: resolvedPath, skipExtraSources: true });
377
368
  return matrixHealthIssues(matrix).map(
378
369
  (healthIssue) => toSourceIssue(healthIssue, resolvedPath, reader)
379
370
  );
380
371
  } catch (error) {
381
- return [matrixLoadFailure(error, reader)];
372
+ const failedFile = fileThatFailedToLoad(error, resolvedPath, stacksRelFile);
373
+ return [matrixLoadFailure(error, reader, failedFile)];
374
+ }
375
+ }
376
+ function fileThatFailedToLoad(error, resolvedPath, stacksRelFile) {
377
+ if (error instanceof StacksLoadError) return stacksRelFile;
378
+ if (configThatFailedToLoad(error) === path.join(resolvedPath, SKILL_RULES_PATH)) {
379
+ return SKILL_RULES_PATH;
380
+ }
381
+ return void 0;
382
+ }
383
+ function configThatFailedToLoad(error) {
384
+ if (error instanceof ConfigEvaluationError || error instanceof ConfigDefaultExportError || error instanceof ConfigSchemaError || error instanceof NoSkillRulesError) {
385
+ return error.configPath;
382
386
  }
387
+ return void 0;
383
388
  }
384
- function matrixLoadFailure(error, reader) {
389
+ function matrixLoadFailure(error, reader, failedFile) {
385
390
  if (error instanceof MarketplaceManifestRequiredError) {
386
391
  return {
387
392
  severity: MANIFEST_REQUIRED_SEVERITY[reader],
@@ -396,10 +401,14 @@ function matrixLoadFailure(error, reader) {
396
401
  message: getErrorMessage(error)
397
402
  };
398
403
  }
404
+ if (failedFile !== void 0) return crossReferenceSkipped(failedFile, failedFile, error);
405
+ return crossReferenceSkipped(SKILL_CATEGORIES_PATH, "categories/rules", error);
406
+ }
407
+ function crossReferenceSkipped(file, whatFailed, error) {
399
408
  return {
400
409
  severity: "warning",
401
- file: SKILL_CATEGORIES_PATH,
402
- message: `Cross-reference validation skipped: failed to load categories/rules: ${getErrorMessage(error)}`
410
+ file,
411
+ message: `Cross-reference validation skipped: failed to load ${whatFailed}: ${getErrorMessage(error)}`
403
412
  };
404
413
  }
405
414
  var SKILL_AUDIT_PATH = "src/cli/lib/configuration/skill-audit.ts";
@@ -467,11 +476,11 @@ async function validateAgents(resolvedPath) {
467
476
  schema: agentYamlGenerationSchema
468
477
  });
469
478
  }
470
- async function validateConfigFiles(resolvedPath) {
479
+ async function validateConfigFiles(resolvedPath, stacksRelFile) {
471
480
  const results = await Promise.all([
472
481
  validateTsConfig(resolvedPath, SKILL_CATEGORIES_PATH, skillCategoriesFileSchema),
473
482
  validateTsConfig(resolvedPath, SKILL_RULES_PATH, skillRulesFileSchema),
474
- validateTsConfig(resolvedPath, STACKS_FILE_PATH, stacksConfigSchema)
483
+ validateTsConfig(resolvedPath, stacksRelFile, stacksConfigSchema)
475
484
  ]);
476
485
  return results.flat();
477
486
  }
@@ -572,7 +581,9 @@ function toUnreadableConfigIssue(failure) {
572
581
  }
573
582
  async function countExistingConfigs(projectDir) {
574
583
  const present = await Promise.all(
575
- configDirsInPlay(projectDir).map((dir) => fileExists(getInstalledConfigPath(dir)))
584
+ configsInPlay(projectDir).map(
585
+ ({ dir, provider }) => fileExists(getProjectConfigPath(dir, provider))
586
+ )
576
587
  );
577
588
  return present.filter(Boolean).length;
578
589
  }
@@ -676,7 +687,7 @@ async function validateInstalledSkills(projectDir) {
676
687
  }
677
688
  async function configuredSkillIds(projectDir) {
678
689
  const loaded = await Promise.all(
679
- configDirsInPlay(projectDir).map((dir) => loadInstalledConfig(dir))
690
+ configsInPlay(projectDir).map(({ dir, provider }) => loadProjectConfigFromDir(dir, provider))
680
691
  );
681
692
  return new Set(loaded.flatMap(configuredIdsOf));
682
693
  }
@@ -863,39 +874,45 @@ async function unclaimedAgentFiles({ dir, codec, claimed: claimed2 }) {
863
874
  import { countBy, unique as unique2 } from "remeda";
864
875
  function checkConfigValid(state, installation) {
865
876
  const theConfig = (verdict) => configRowMessage(state, installation, verdict);
866
- if (state.kind === "absent") {
867
- return {
868
- result: {
869
- kind: "config",
870
- status: "fail",
871
- message: theConfig("not found"),
872
- details: [`Run '${CLI_INVOKE_COMMAND} init' to create a configuration`]
873
- },
874
- config: null
875
- };
876
- }
877
- if (state.kind === "unreadable") {
878
- return {
879
- result: {
880
- kind: "config",
881
- status: "fail",
882
- message: theConfig("exists but could not be loaded"),
883
- details: [state.failure.reason]
884
- },
885
- config: null
886
- };
887
- }
888
- if (state.kind === "declares-nothing") {
889
- return {
890
- result: {
891
- kind: "config-empty",
892
- status: "warn",
893
- message: theConfig("is valid but declares no skills and no agents")
894
- },
895
- config: state.config
896
- };
877
+ switch (state.kind) {
878
+ case "absent":
879
+ return {
880
+ result: {
881
+ kind: "config",
882
+ status: "fail",
883
+ message: theConfig("not found"),
884
+ details: [`Run '${CLI_INVOKE_COMMAND} init' to create a configuration`]
885
+ },
886
+ config: null
887
+ };
888
+ case "unreadable":
889
+ return {
890
+ result: {
891
+ kind: "config",
892
+ status: "fail",
893
+ message: theConfig("exists but could not be loaded"),
894
+ details: [state.failure.reason]
895
+ },
896
+ config: null
897
+ };
898
+ case "declares-nothing":
899
+ return {
900
+ result: {
901
+ kind: "config-empty",
902
+ status: "warn",
903
+ message: theConfig("is valid but declares no skills and no agents")
904
+ },
905
+ config: state.config
906
+ };
907
+ case "loaded":
908
+ return checkLoadedConfig(state.config, theConfig);
909
+ default: {
910
+ const _exhaustive = state;
911
+ return _exhaustive;
912
+ }
897
913
  }
898
- const { config } = state;
914
+ }
915
+ function checkLoadedConfig(config, theConfig) {
899
916
  const validation = validateProjectConfig(config);
900
917
  if (!validation.valid) {
901
918
  return {
@@ -930,7 +947,7 @@ function checkConfigValid(state, installation) {
930
947
  }
931
948
  function configRowMessage(state, { projectDir, hosts }, verdict) {
932
949
  if (state.kind === "loaded" && state.inherited)
933
- return `${theInheritedConfig(hosts.global)}, which ${verdict}`;
950
+ return `${theInheritedConfig(projectDir, state.declaringNothingIn, hosts.global)}, which ${verdict}`;
934
951
  if (state.kind === "unreadable") {
935
952
  const { scopeRoot, scope } = state.failure;
936
953
  return `${theConfigAt(scopeRoot, hosts[scope])} ${verdict}`;
@@ -940,8 +957,9 @@ function configRowMessage(state, { projectDir, hosts }, verdict) {
940
957
  function theConfigAt(root, provider) {
941
958
  return `${scopeLabel(scopeOf(root))}: ${configNamedFrom(root, provider)}`;
942
959
  }
943
- function theInheritedConfig(provider) {
944
- return `${scopeLabel("project")}: no ${STANDARD_FILES.CONFIG_TS}, using ${scopeNoun("global")}'s (${configNamedFrom(os3.homedir(), provider)})`;
960
+ function theInheritedConfig(projectDir, declaringNothingIn, provider) {
961
+ const projectHolds = declaringNothingIn === null ? `no ${STANDARD_FILES.CONFIG_TS}` : `${relativeConfigPath(projectDir, declaringNothingIn)} declares nothing`;
962
+ return `${scopeLabel("project")}: ${projectHolds}, using ${scopeNoun("global")}'s (${configNamedFrom(os3.homedir(), provider)})`;
945
963
  }
946
964
  function scopeOf(dir) {
947
965
  return isHomeDirectory(dir) ? "global" : "project";
@@ -1466,6 +1484,7 @@ var Doctor = class _Doctor extends BaseCommand {
1466
1484
  async run() {
1467
1485
  await this.parse(_Doctor);
1468
1486
  const projectDir = process.cwd();
1487
+ await this.sayWhenTheGlobalInstallationStandsIn(void 0);
1469
1488
  this.printHeader(await this.resolveBrandingName(projectDir));
1470
1489
  const contentResults = await this.runContentChecks(projectDir);
1471
1490
  const operationalResults = await this.runOperationalChecks(projectDir, contentResults);