agents-inc 0.157.0 → 0.158.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 (97) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/{chunk-PXGDA2SY.js → chunk-2PN4QXON.js} +2 -2
  3. package/dist/{chunk-WENBESZO.js → chunk-3NBXQSW2.js} +5 -5
  4. package/dist/{chunk-RVXI5VQU.js → chunk-3PJLLBUS.js} +61 -257
  5. package/dist/{chunk-RVXI5VQU.js.map → chunk-3PJLLBUS.js.map} +1 -1
  6. package/dist/{chunk-YG5YPVTJ.js → chunk-3Q2N7CSY.js} +4 -4
  7. package/dist/{chunk-PVPNVK3W.js → chunk-4ABNXKAR.js} +2 -2
  8. package/dist/{chunk-DCIC35R7.js → chunk-54QLV3OH.js} +4 -4
  9. package/dist/{chunk-QXPMQBEI.js → chunk-6DBE562W.js} +3 -3
  10. package/dist/{chunk-IGOFZG3S.js → chunk-7Z4N4JWQ.js} +1 -241
  11. package/dist/{chunk-IGOFZG3S.js.map → chunk-7Z4N4JWQ.js.map} +1 -1
  12. package/dist/{chunk-3E52LCYC.js → chunk-DAUY2SB3.js} +10 -10
  13. package/dist/{chunk-CEGHC7L5.js → chunk-DP6YQFVO.js} +4 -4
  14. package/dist/{chunk-MU2TQ5KK.js → chunk-EEAX7E2X.js} +2 -2
  15. package/dist/{chunk-ZAQ6WMJV.js → chunk-H25VRR2T.js} +5 -5
  16. package/dist/{chunk-Z3H2K5PK.js → chunk-H2DHTJKW.js} +8 -8
  17. package/dist/{chunk-4KHUHPX4.js → chunk-H4CL23HG.js} +3 -3
  18. package/dist/{chunk-RLU2IXD3.js → chunk-IK6YOXZH.js} +3 -3
  19. package/dist/{chunk-V7PMQDDU.js → chunk-JG3B47P3.js} +4 -4
  20. package/dist/{chunk-QO4XD5V5.js → chunk-KVVXINCJ.js} +3 -3
  21. package/dist/{chunk-4EPJWN7C.js → chunk-L4FHSOL5.js} +3 -3
  22. package/dist/{chunk-24IGOJ7E.js → chunk-LKI3ENGQ.js} +3 -3
  23. package/dist/{chunk-K2VTGT45.js → chunk-OQB2CKBT.js} +5 -5
  24. package/dist/{chunk-XOZAKFTS.js → chunk-PNRLBPGS.js} +11 -11
  25. package/dist/{chunk-VI6U2PJG.js → chunk-PZNXBORZ.js} +3 -3
  26. package/dist/{chunk-YKFCUVHG.js → chunk-Q7CAE5NN.js} +3 -3
  27. package/dist/{chunk-ZBYVDXZG.js → chunk-SJ4T5YLG.js} +2 -2
  28. package/dist/{chunk-4CIAZOTD.js → chunk-TPQ5M3BW.js} +2 -2
  29. package/dist/{chunk-O4K42CJB.js → chunk-TUXXBEBB.js} +2 -2
  30. package/dist/{chunk-LDBVIPTP.js → chunk-WMVOJY6V.js} +3 -3
  31. package/dist/{chunk-KTXVQ7OM.js → chunk-X52QUV4U.js} +3 -3
  32. package/dist/{chunk-PGZSNNDA.js → chunk-XNYHMRVJ.js} +4 -4
  33. package/dist/commands/build/marketplace.js +5 -5
  34. package/dist/commands/build/plugins.js +5 -5
  35. package/dist/commands/compile.js +8 -8
  36. package/dist/commands/doctor.js +9 -9
  37. package/dist/commands/doctor.js.map +1 -1
  38. package/dist/commands/edit.js +27 -27
  39. package/dist/commands/eject.js +8 -8
  40. package/dist/commands/init.js +27 -27
  41. package/dist/commands/list.js +6 -6
  42. package/dist/commands/new/marketplace.js +5 -5
  43. package/dist/commands/search.js +8 -8
  44. package/dist/commands/share.js +6 -6
  45. package/dist/commands/uninstall.js +8 -8
  46. package/dist/commands/update.js +4 -4
  47. package/dist/components/wizard/category-grid.js +2 -2
  48. package/dist/components/wizard/domain-selection.js +5 -5
  49. package/dist/components/wizard/run-wizard-session.js +18 -18
  50. package/dist/components/wizard/skill-agent-summary.js +4 -4
  51. package/dist/components/wizard/source-grid.js +2 -2
  52. package/dist/components/wizard/stack-selection.js +4 -4
  53. package/dist/components/wizard/step-agents.js +5 -5
  54. package/dist/components/wizard/step-build.js +5 -5
  55. package/dist/components/wizard/step-confirm.js +7 -7
  56. package/dist/components/wizard/step-sources.js +5 -5
  57. package/dist/components/wizard/step-stack.js +5 -5
  58. package/dist/components/wizard/summary-panel.js +6 -6
  59. package/dist/components/wizard/wizard-layout.js +7 -7
  60. package/dist/components/wizard/wizard.js +17 -17
  61. package/dist/hooks/init.js +27 -27
  62. package/dist/load-agent-defs-2VYAV5GL.js +13 -0
  63. package/dist/{recompile-project-agents-G7ZM25PC.js → recompile-project-agents-NG5DCPHJ.js} +7 -7
  64. package/dist/{source-loader-BIAEDR5R.js → source-loader-CO2FZ3OO.js} +3 -3
  65. package/dist/stores/wizard-store.js +3 -3
  66. package/package.json +2 -4
  67. package/dist/load-agent-defs-M6LRVISN.js +0 -13
  68. /package/dist/{chunk-PXGDA2SY.js.map → chunk-2PN4QXON.js.map} +0 -0
  69. /package/dist/{chunk-WENBESZO.js.map → chunk-3NBXQSW2.js.map} +0 -0
  70. /package/dist/{chunk-YG5YPVTJ.js.map → chunk-3Q2N7CSY.js.map} +0 -0
  71. /package/dist/{chunk-PVPNVK3W.js.map → chunk-4ABNXKAR.js.map} +0 -0
  72. /package/dist/{chunk-DCIC35R7.js.map → chunk-54QLV3OH.js.map} +0 -0
  73. /package/dist/{chunk-QXPMQBEI.js.map → chunk-6DBE562W.js.map} +0 -0
  74. /package/dist/{chunk-3E52LCYC.js.map → chunk-DAUY2SB3.js.map} +0 -0
  75. /package/dist/{chunk-CEGHC7L5.js.map → chunk-DP6YQFVO.js.map} +0 -0
  76. /package/dist/{chunk-MU2TQ5KK.js.map → chunk-EEAX7E2X.js.map} +0 -0
  77. /package/dist/{chunk-ZAQ6WMJV.js.map → chunk-H25VRR2T.js.map} +0 -0
  78. /package/dist/{chunk-Z3H2K5PK.js.map → chunk-H2DHTJKW.js.map} +0 -0
  79. /package/dist/{chunk-4KHUHPX4.js.map → chunk-H4CL23HG.js.map} +0 -0
  80. /package/dist/{chunk-RLU2IXD3.js.map → chunk-IK6YOXZH.js.map} +0 -0
  81. /package/dist/{chunk-V7PMQDDU.js.map → chunk-JG3B47P3.js.map} +0 -0
  82. /package/dist/{chunk-QO4XD5V5.js.map → chunk-KVVXINCJ.js.map} +0 -0
  83. /package/dist/{chunk-4EPJWN7C.js.map → chunk-L4FHSOL5.js.map} +0 -0
  84. /package/dist/{chunk-24IGOJ7E.js.map → chunk-LKI3ENGQ.js.map} +0 -0
  85. /package/dist/{chunk-K2VTGT45.js.map → chunk-OQB2CKBT.js.map} +0 -0
  86. /package/dist/{chunk-XOZAKFTS.js.map → chunk-PNRLBPGS.js.map} +0 -0
  87. /package/dist/{chunk-VI6U2PJG.js.map → chunk-PZNXBORZ.js.map} +0 -0
  88. /package/dist/{chunk-YKFCUVHG.js.map → chunk-Q7CAE5NN.js.map} +0 -0
  89. /package/dist/{chunk-ZBYVDXZG.js.map → chunk-SJ4T5YLG.js.map} +0 -0
  90. /package/dist/{chunk-4CIAZOTD.js.map → chunk-TPQ5M3BW.js.map} +0 -0
  91. /package/dist/{chunk-O4K42CJB.js.map → chunk-TUXXBEBB.js.map} +0 -0
  92. /package/dist/{chunk-LDBVIPTP.js.map → chunk-WMVOJY6V.js.map} +0 -0
  93. /package/dist/{chunk-KTXVQ7OM.js.map → chunk-X52QUV4U.js.map} +0 -0
  94. /package/dist/{chunk-PGZSNNDA.js.map → chunk-XNYHMRVJ.js.map} +0 -0
  95. /package/dist/{load-agent-defs-M6LRVISN.js.map → load-agent-defs-2VYAV5GL.js.map} +0 -0
  96. /package/dist/{recompile-project-agents-G7ZM25PC.js.map → recompile-project-agents-NG5DCPHJ.js.map} +0 -0
  97. /package/dist/{source-loader-BIAEDR5R.js.map → source-loader-CO2FZ3OO.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/doctor.ts","../../src/cli/lib/source-validator.ts","../../src/cli/lib/content-validator.ts"],"sourcesContent":["import os from \"os\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\nimport {\n effectivelyExcludedSkillIds,\n loadProjectConfigFromDir,\n validateProjectConfig,\n SOURCE_ENV_VAR,\n type ResolvedConfig,\n} from \"../lib/configuration\";\nimport { loadSource, detectProject, type DetectedProject } from \"../lib/operations\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { discoverLocalSkills } from \"../lib/skills\";\nimport { getStackSkillIds } from \"../lib/stacks\";\nimport { filterExcludedEntries, listAgentMdFiles } from \"../lib/agents\";\nimport { getVerifiedPluginInstallPaths, parseMarketplacePluginRef } from \"../lib/plugins\";\nimport {\n declaresNoContent,\n isHomeDirectory,\n installBaseDir,\n resolveInstallPaths,\n} from \"../lib/installation\";\nimport { getProjectConfigPath } from \"../lib/configuration\";\nimport { isSourceRepo } from \"../lib/source-validator\";\nimport {\n listInstalledArtifacts,\n validateInstalledAgents,\n validateInstalledPlugins,\n validateInstalledSkills,\n validateProjectConfigFile,\n validateRegisteredSources,\n type ContentIssue,\n type ContentValidation,\n} from \"../lib/content-validator\";\nimport type { SourceLoadResult } from \"../lib/loading\";\nimport type { MergedSkillsMatrix, ProjectConfig, SkillConfig } from \"../types\";\nimport { fileExists, directoryExists } from \"../utils/fs\";\nimport {\n CLAUDE_SRC_DIR,\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n EJECT_SOURCE,\n LOCAL_SKILLS_PATH,\n STANDARD_FILES,\n UI_SYMBOLS,\n} from \"../consts\";\nimport { countBy, unique } from \"remeda\";\n\ntype CheckKind =\n | \"config\"\n | \"config-empty\"\n | \"skills\"\n | \"agents\"\n | \"orphans\"\n | \"orphans-unowned\"\n | \"installed\"\n | \"plugins\"\n | \"source\"\n | \"content-config\"\n | \"content-sources\"\n | \"content-plugins\"\n | \"content-skills\"\n | \"content-agents\";\n\ntype CheckResult = {\n kind: CheckKind;\n status: \"pass\" | \"fail\" | \"warn\" | \"skip\";\n message: string;\n details?: string[];\n};\n\ntype ConfigCheckOutput = {\n result: CheckResult;\n config: ProjectConfig | null;\n};\n\n/**\n * Which state the config these rows describe is in. `detectInstallation` answers \"is there an\n * installation here\", not \"is there a config here\", and hands back the same `null` for an absent\n * file and for one that loads while declaring neither skills nor agents — two states that need\n * different sentences. The state missing from this union is the one that cannot reach this layer:\n * a config that cannot be READ is the content layer's finding, and it skips the operational layer.\n */\ntype ConfigState =\n | { kind: \"absent\" }\n | { kind: \"declares-nothing\"; config: ProjectConfig }\n | { kind: \"loaded\"; config: ProjectConfig };\n\n/** Project-relative path to the config file, shown in doctor messages. */\nconst CONFIG_TS_REL = `${CLAUDE_SRC_DIR}/${STANDARD_FILES.CONFIG_TS}`;\n\n/**\n * The config in THIS directory, and what state it is in. Only this directory: the global fallback\n * is `detectInstallation`'s to make and it has already made it, so a project with no config of its\n * own is absent here whatever the home directory holds — `init` writes exactly the declares-nothing\n * shape as the blank global pair on every project setup, and it is not this project's config.\n *\n * The load cannot throw: `configDirsInPlay` is the same set the content layer just read, and any\n * failure in it skipped this layer entirely.\n */\nasync function resolveConfigState(\n detected: DetectedProject | null,\n projectDir: string,\n): Promise<ConfigState> {\n if (detected?.config) return { kind: \"loaded\", config: detected.config };\n\n const loaded = await loadProjectConfigFromDir(projectDir);\n if (!loaded) return { kind: \"absent\" };\n\n return declaresNoContent(loaded.config)\n ? { kind: \"declares-nothing\", config: loaded.config }\n : { kind: \"loaded\", config: loaded.config };\n}\n\nfunction checkConfigValid(state: ConfigState): ConfigCheckOutput {\n if (state.kind === \"absent\") {\n return {\n result: {\n kind: \"config\",\n status: \"fail\",\n message: `${CONFIG_TS_REL} not found`,\n details: [`Run '${CLI_INVOKE_COMMAND} init' to create a configuration`],\n },\n config: null,\n };\n }\n\n // Not a fault and nothing to repair — the file is valid, it just has nothing in it. The config\n // is still handed on: the rows below describe an empty install truthfully, where a `null` would\n // have them all report `Skipped (config invalid)` about a config that is valid.\n if (state.kind === \"declares-nothing\") {\n return {\n result: {\n kind: \"config-empty\",\n status: \"warn\",\n message: `${CONFIG_TS_REL} is valid but declares no skills and no agents`,\n },\n config: state.config,\n };\n }\n\n const { config } = state;\n const validation = validateProjectConfig(config);\n\n if (!validation.valid) {\n return {\n result: {\n kind: \"config\",\n status: \"fail\",\n message: `${CONFIG_TS_REL} has errors`,\n details: validation.errors,\n },\n config: null,\n };\n }\n\n if (validation.warnings.length > 0) {\n return {\n result: {\n kind: \"config\",\n status: \"warn\",\n message: `${CONFIG_TS_REL} has warnings`,\n details: validation.warnings,\n },\n config,\n };\n }\n\n return {\n result: {\n kind: \"config\",\n status: \"pass\",\n message: `${CONFIG_TS_REL} is valid`,\n },\n config,\n };\n}\n\nasync function checkSkillsResolved(\n config: ProjectConfig,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): Promise<CheckResult> {\n // config.ts declares skills both directly and through the stack. A global-only\n // install has a populated skills array and no stack at all, so keying this check\n // off the stack alone would report \"No skills configured\" for a real install.\n const excludedIds = effectivelyExcludedSkillIds(config.skills);\n const stackIds = config.stack ? getStackSkillIds(config.stack) : [];\n const uniqueSkills = unique([...stackIds, ...config.skills.map((s) => s.id)]).filter(\n (id) => !excludedIds.has(id),\n );\n\n if (uniqueSkills.length === 0) {\n return {\n kind: \"skills\",\n status: \"pass\",\n message: \"No skills configured\",\n };\n }\n\n const [localResult, globalResult] = await Promise.all([\n discoverLocalSkills(projectDir),\n !isHomeDirectory(projectDir) ? discoverLocalSkills(os.homedir()) : null,\n ]);\n const localSkillIds = new Set([\n ...(localResult?.skills.map((s) => s.id) ?? []),\n ...(globalResult?.skills.map((s) => s.id) ?? []),\n ]);\n\n const missingSkills = uniqueSkills.filter(\n (skillId) => !(skillId in matrix.skills) && !localSkillIds.has(skillId),\n );\n\n if (missingSkills.length > 0) {\n return {\n kind: \"skills\",\n status: \"fail\",\n message: `${uniqueSkills.length - missingSkills.length}/${uniqueSkills.length} skills found`,\n details: missingSkills.map((s) => `- ${s} (not found)`),\n };\n }\n\n return {\n kind: \"skills\",\n status: \"pass\",\n message: `${uniqueSkills.length}/${uniqueSkills.length} skills found`,\n };\n}\n\nasync function checkAgentsCompiled(\n config: ProjectConfig,\n projectDir: string,\n): Promise<CheckResult> {\n const agents = config.agents;\n\n if (agents.length === 0) {\n return {\n kind: \"agents\",\n status: \"pass\",\n message: \"No agents configured\",\n };\n }\n\n const projectAgentsDir = resolveInstallPaths(projectDir, \"project\").agentsDir;\n const globalAgentsDir = resolveInstallPaths(projectDir, \"global\").agentsDir;\n const agentChecks = await Promise.all(\n agents.map(async (agent) => {\n // Check scope-appropriate directory for the agent\n const agentsDir = agent.scope === \"global\" ? globalAgentsDir : projectAgentsDir;\n const agentPath = path.join(agentsDir, `${agent.name}.md`);\n return { name: agent.name, compiled: await fileExists(agentPath) };\n }),\n );\n const missingAgents = agentChecks.filter((c) => !c.compiled).map((c) => c.name);\n\n if (missingAgents.length > 0) {\n return {\n kind: \"agents\",\n status: \"warn\",\n message: `${missingAgents.length} agent${missingAgents.length === 1 ? \"\" : \"s\"} need${missingAgents.length === 1 ? \"s\" : \"\"} recompilation`,\n details: missingAgents.map((a) => `- ${a} (missing)`),\n };\n }\n\n return {\n kind: \"agents\",\n status: \"pass\",\n message: `${agents.length}/${agents.length} agents compiled`,\n };\n}\n\nasync function checkNoOrphans(config: ProjectConfig, projectDir: string): Promise<CheckResult> {\n const projectAgentsDir = resolveInstallPaths(projectDir, \"project\").agentsDir;\n const globalAgentsDir = resolveInstallPaths(projectDir, \"global\").agentsDir;\n\n // At home scope both scopes resolve to the same agents directory, so it is\n // listed once and its files are matched against both scopes' known names.\n const scopesShareAgentsDir = isHomeDirectory(projectDir);\n\n const [projectExists, globalExists] = await Promise.all([\n directoryExists(projectAgentsDir),\n !scopesShareAgentsDir ? directoryExists(globalAgentsDir) : false,\n ]);\n\n if (!projectExists && !globalExists) {\n return {\n kind: \"orphans\",\n status: \"pass\",\n message: \"No agents directory\",\n };\n }\n\n const projectMdFiles = projectExists ? await listAgentMdFiles(projectAgentsDir) : [];\n const globalMdFiles = globalExists ? await listAgentMdFiles(globalAgentsDir) : [];\n\n // Project files: only active project-scoped agents should have .md files here\n const activeProjectAgents: Set<string> = new Set(\n config.agents.filter((a) => a.scope === \"project\" && !a.excluded).map((a) => a.name),\n );\n // Global files: all global-scoped agents (including excluded) still serve other projects\n const knownGlobalAgents: Set<string> = new Set(\n config.agents.filter((a) => a.scope === \"global\").map((a) => a.name),\n );\n\n const knownProjectDirAgents = scopesShareAgentsDir\n ? new Set([...activeProjectAgents, ...knownGlobalAgents])\n : activeProjectAgents;\n\n const orphanedFiles = [\n ...orphanedAgentNames(projectMdFiles, knownProjectDirAgents),\n ...orphanedAgentNames(globalMdFiles, knownGlobalAgents),\n ];\n\n if (orphanedFiles.length > 0) {\n return {\n kind: \"orphans\",\n status: \"warn\",\n message: plural(orphanedFiles.length, \"orphaned agent file\"),\n details: orphanedFiles.map((f) => `- ${f}.md (not in config)`),\n };\n }\n\n return {\n kind: \"orphans\",\n status: \"pass\",\n message: \"No orphaned agent files\",\n };\n}\n\n/**\n * The agents whose compiled `.md` sits in a directory whose roster does not name them. The\n * roster differs per directory — a project directory knows only its own active agents, the\n * global one knows every global-scoped agent including the excluded — so it is a parameter.\n */\nfunction orphanedAgentNames(mdFiles: string[], knownAgents: ReadonlySet<string>): string[] {\n return mdFiles\n .map((fileName) => fileName.replace(/\\.md$/, \"\"))\n .filter((agentName) => !knownAgents.has(agentName));\n}\n\n/**\n * The same row when there is no configuration at all. Ownership is not unknown here, it is\n * settled: nothing declares any of it, so every artefact this CLI can prove it wrote is an\n * orphan and the row names it. What it CANNOT prove it wrote is left out — a skill directory\n * with no `forkedFrom` and an agent file with no provenance marker are somebody's own work,\n * and naming them here would offer `uninstall` files that command declines. See\n * {@link listInstalledArtifacts}, which asks exactly that question on both axes.\n *\n * A `fail`, where a stray file beside a config is a warning: that warning is earned by the next\n * `compile` pruning what it names, and nothing prunes these unattended. `compile` and `edit`\n * refuse without a config; `uninstall` does not need one, identifying skill directories by\n * their own `forkedFrom` and compiled agents by the marker each carries, which is why the tip\n * beneath this row can promise both halves.\n *\n * With nothing installed the row keeps the skip it has always printed. An empty directory with\n * no config is the state `init` exists for — there is nothing for a configuration to have owned.\n */\nasync function checkUnownedInstallation(projectDir: string): Promise<CheckResult> {\n const { skills, agents } = await listInstalledArtifacts(projectDir);\n if (skills.length === 0 && agents.length === 0) return skippedResult(\"orphans\");\n\n return {\n kind: \"orphans-unowned\",\n status: \"fail\",\n // The per-line \"(not in config)\" the other verdict repeats is said once here instead:\n // with no configuration it is true of every line, and there are as many lines as files.\n message: `${countedArtifacts(skills, agents)} installed here, and no configuration declares them`,\n details: [...skills, ...agents].map((artifact) => `- ${artifact}`),\n };\n}\n\n/** \"7 skills and 2 agents\", dropping a half with nothing in it rather than saying \"0 agents\". */\nfunction countedArtifacts(skills: string[], agents: string[]): string {\n return [\n ...(skills.length > 0 ? [plural(skills.length, \"skill\")] : []),\n ...(agents.length > 0 ? [plural(agents.length, \"agent\")] : []),\n ].join(\" and \");\n}\n\nasync function checkSkillsInstalled(\n config: ProjectConfig,\n projectDir: string,\n): Promise<CheckResult> {\n const skills: SkillConfig[] = config.skills;\n const ejectSkills = skills.filter((s) => s.origin === EJECT_SOURCE);\n\n if (ejectSkills.length === 0) {\n return {\n kind: \"installed\",\n status: \"pass\",\n message: \"No eject-mode skills configured\",\n };\n }\n\n const skillChecks = await Promise.all(\n ejectSkills.map(async (skill) => {\n const baseDir = installBaseDir(projectDir, skill.scope);\n const skillMdPath = path.join(baseDir, LOCAL_SKILLS_PATH, skill.id, STANDARD_FILES.SKILL_MD);\n return { id: skill.id, installed: await fileExists(skillMdPath) };\n }),\n );\n const missingSkills = skillChecks.filter((c) => !c.installed).map((c) => c.id);\n\n if (missingSkills.length > 0) {\n return {\n kind: \"installed\",\n status: \"warn\",\n message: `${plural(missingSkills.length, \"skill\")} missing from disk`,\n details: missingSkills.map((s) => `- ${s} (not found in ${LOCAL_SKILLS_PATH}/)`),\n };\n }\n\n return {\n kind: \"installed\",\n status: \"pass\",\n message: `${ejectSkills.length}/${ejectSkills.length} eject-mode skills installed`,\n };\n}\n\n/**\n * Plugin-mode skills have no files under `.claude/skills/` — they live in the\n * Claude plugin registry. Verifying them means asking the registry for the scope\n * each skill was installed at, not looking on disk.\n */\nasync function checkPluginSkillsInstalled(\n config: ProjectConfig,\n projectDir: string,\n): Promise<CheckResult> {\n const pluginSkills: SkillConfig[] = config.skills.filter((s) => s.origin !== EJECT_SOURCE);\n\n if (pluginSkills.length === 0) {\n return {\n kind: \"plugins\",\n status: \"pass\",\n message: \"No plugin-mode skills configured\",\n };\n }\n\n const baseDirs = unique(pluginSkills.map((s) => installBaseDir(projectDir, s.scope)));\n const missingPerBaseDir = await Promise.all(\n baseDirs.map(async (baseDir) => {\n const installedIds = new Set(\n (await getVerifiedPluginInstallPaths(baseDir)).map((plugin) =>\n parseMarketplacePluginRef(plugin.pluginKey),\n ),\n );\n return pluginSkills\n .filter((skill) => installBaseDir(projectDir, skill.scope) === baseDir)\n .filter((skill) => !installedIds.has(skill.id))\n .map((skill) => skill.id);\n }),\n );\n const missingSkills = missingPerBaseDir.flat();\n\n if (missingSkills.length > 0) {\n return {\n kind: \"plugins\",\n status: \"warn\",\n message: `${plural(missingSkills.length, \"skill\")} not installed as plugins`,\n details: missingSkills.map((s) => `- ${s} (no enabled plugin found)`),\n };\n }\n\n return {\n kind: \"plugins\",\n status: \"pass\",\n message: `${pluginSkills.length}/${pluginSkills.length} plugin-mode skills installed`,\n };\n}\n\n/**\n * How a marketplace came to be the one this run reads, in the words each rung earns.\n *\n * The `default` sentence is the one that had to exist. With no configuration anywhere the resolver\n * falls back to the public catalogue and this check FETCHES it, so the report a bare directory gets\n * describes a network round trip to a marketplace nobody named — which is the row doing its job,\n * since reachability is its whole subject, and it was doing it without saying so. The other four\n * rungs are here because the map is exhaustive against the union rather than a default with\n * exceptions; `doctor` takes no marketplace flag and reads no environment variable, so it reaches\n * the first two through nothing today.\n */\nconst MARKETPLACE_CHOSEN_BY = {\n flag: \"named by this run\",\n env: `named by ${SOURCE_ENV_VAR}`,\n project: \"named by this project's configuration\",\n global: \"named by the global configuration\",\n default: \"nothing here names one, so this is the default\",\n} as const satisfies Record<ResolvedConfig[\"sourceOrigin\"], string>;\n\n/** How this run got hold of that marketplace — off disk, or over the wire. */\nfunction howItWasReached(source: string, isLocal: boolean): string {\n return isLocal ? `Read ${source} from disk` : `Fetched ${source} over the network`;\n}\n\n/**\n * The row for a marketplace this run did reach.\n *\n * `message` names where the skills were read FROM, which for a remote marketplace is the cache\n * directory it was unpacked into; the provenance line beneath it names the marketplace itself.\n * Both, because neither answers the other's question: a cache path says nothing about whose\n * catalogue it holds, and a ref says nothing about what is on disk to inspect.\n */\nfunction reachedMarketplace(result: SourceLoadResult): CheckResult {\n const { source, sourceOrigin } = result.sourceConfig;\n const skillCount = Object.keys(matrix.skills).length;\n const sourceLabel = result.isLocal ? \"local\" : \"remote\";\n\n return {\n kind: \"source\",\n status: \"pass\",\n message: `Connected to ${sourceLabel}: ${result.sourcePath}`,\n details: [\n `${skillCount} skills available`,\n `${howItWasReached(source, result.isLocal)} — ${MARKETPLACE_CHOSEN_BY[sourceOrigin]}`,\n ],\n };\n}\n\nasync function checkSourceReachable(projectDir: string): Promise<CheckResult> {\n try {\n const { sourceResult } = await loadSource({ projectDir });\n return reachedMarketplace(sourceResult);\n } catch (error) {\n const message = getErrorMessage(error);\n return {\n kind: \"source\",\n status: \"fail\",\n message: \"Failed to load marketplace\",\n details: [message],\n };\n }\n}\n\ntype ContentCheck = {\n kind: CheckKind;\n name: string;\n noun: string;\n run: (projectDir: string) => Promise<ContentValidation>;\n};\n\n/**\n * A content check plus the two gates it owns: whether it reads config.ts to know WHAT to validate\n * (see {@link CONFIG_CHECK}), and which operational rows its errors stand down.\n *\n * `blocks` names only the rows that READ what this pass validates, so their own verdict would be\n * this pass's finding in the row's words. A row absent from every `blocks` list reads none of the\n * content on disk and answers as truthfully as ever — an error here is not its business.\n */\ntype GatedContentCheck = ContentCheck & {\n readsConfig: boolean;\n blocks: readonly CheckKind[];\n};\n\n/**\n * The config file every other check is read against, so it is validated before any of them and\n * on its own: a file that exists and cannot be parsed is a finding about that file, and every\n * row underneath would be a cascade of it. It carries no gate of its own — it IS the gate.\n */\nconst CONFIG_CHECK: ContentCheck = {\n kind: \"content-config\",\n name: \"Config\",\n noun: \"config\",\n run: validateProjectConfigFile,\n};\n\n/**\n * The content layer: schema and file-level validation of what is on disk. It runs before the\n * operational layer so that a row whose inputs this layer has already reported broken can stand\n * down rather than re-report the same fault as a finding of its own.\n */\nconst CONTENT_CHECKS: GatedContentCheck[] = [\n {\n kind: \"content-sources\",\n name: \"Marketplaces\",\n noun: \"marketplace\",\n // The registered marketplaces are the ones config.ts names.\n readsConfig: true,\n // A marketplace whose content is broken is missing skills from the matrix every configured\n // id is resolved against, so the skills row would call ids \"not found\" that this row has\n // already accounted for.\n blocks: [\"skills\"],\n run: validateRegisteredSources,\n },\n {\n kind: \"content-plugins\",\n name: \"Plugins\",\n noun: \"plugin\",\n readsConfig: false,\n // `resolvePluginInstallPaths` swallows a registry it cannot parse and returns none, so every\n // plugin-mode skill would read \"no enabled plugin found\" — the registry's finding, once per\n // configured skill, wearing the row's words.\n blocks: [\"plugins\"],\n run: validateInstalledPlugins,\n },\n {\n kind: \"content-skills\",\n name: \"Skills\",\n noun: \"skill\",\n // `~/.claude/skills/` is shared with everything else that installs a skill there, so which of\n // its directories are this installation's is a question only the config can answer for the\n // ones carrying no provenance marker. A config nobody can read leaves that unanswerable.\n readsConfig: true,\n // `extractLocalSkill` DROPS a skill whose metadata.yaml is missing or unusable, so a \"not\n // found\" from the skills row would be this finding re-worded.\n blocks: [\"skills\"],\n run: validateInstalledSkills,\n },\n {\n kind: \"content-agents\",\n name: \"Agents\",\n noun: \"agent\",\n readsConfig: false,\n // Nothing downstream opens an agent .md. `Agents Compiled` asks whether the file is there and\n // `No Orphans` reads the names of the files that are — broken frontmatter changes neither.\n blocks: [],\n run: validateInstalledAgents,\n },\n];\n\nfunction contentStatus(errors: number, warnings: number): CheckResult[\"status\"] {\n if (errors > 0) return \"fail\";\n if (warnings > 0) return \"warn\";\n return \"pass\";\n}\n\nfunction contentMessage(noun: string, count: number, errors: number, warnings: number): string {\n // A pass that walked nothing can still report an issue — an unreadable plugin\n // registry is a finding about the directory, not about a plugin inside it.\n if (errors === 0 && warnings === 0) {\n return count === 0 ? `No ${noun}s to validate` : `${plural(count, noun)} validated`;\n }\n return `${plural(count, noun)}: ${plural(errors, \"error\")}, ${plural(warnings, \"warning\")}`;\n}\n\nfunction formatContentIssue(issue: ContentIssue): string {\n const marker = issue.severity === \"error\" ? \"ERROR\" : \"WARN\";\n return `- [${marker}] ${issue.file}: ${issue.message}`;\n}\n\nfunction toContentResult(check: ContentCheck, validation: ContentValidation): CheckResult {\n const errors = validation.issues.filter((issue) => issue.severity === \"error\").length;\n const warnings = validation.issues.length - errors;\n\n return {\n kind: check.kind,\n status: contentStatus(errors, warnings),\n message: contentMessage(check.noun, validation.count, errors, warnings),\n details: [\n ...validation.notes.map((note) => `- ${note}`),\n ...validation.issues.map(formatContentIssue),\n ],\n };\n}\n\n/**\n * The column every row's status symbol starts at. It has to clear the longest row name\n * the report prints — \"Marketplace Reachable\", 21 characters — or that row's name runs\n * straight into its own tick with no gap.\n */\nconst CHECK_WIDTH = 24;\n\n/** Section headings and the rows underneath them are indented one step apart. */\nconst SECTION_INDENT = \" \";\nconst ROW_INDENT = \" \";\n\nconst SECTION_CONTENT = \"Content checks\";\nconst SECTION_OPERATIONAL = \"Operational checks\";\nconst SKIP_NO_INSTALLATION = \"Skipped — no installation here (marketplace repository)\";\nconst SKIP_CONFIG_UNREADABLE = \"Skipped — the configuration that names them cannot be read\";\n\n/**\n * The whole operational layer standing down, for the one content finding that leaves every row\n * with nothing to say: a config nobody can read. It still says \"errors\" rather than naming that\n * file, because the config row is one of them and whatever else failed is above it too.\n */\nconst SKIP_AFTER_CONFIG_ERROR = \"Skipped — fix the content errors above first\";\n\n/**\n * The sentence a single row stands down with. Unlike its neighbours it names the finding rather\n * than the layer: which pass blocked it is the one thing separating a row that cannot answer from\n * the ones printing verdicts beside it.\n */\nfunction skipRestatingContent(nouns: string[]): string {\n return `Skipped — this row would only restate the ${nouns.join(\" and \")} errors above`;\n}\n\nfunction plural(count: number, word: string): string {\n return `${count} ${word}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction formatCheckName(name: string): string {\n return name.padEnd(CHECK_WIDTH);\n}\n\nfunction formatStatus(status: CheckResult[\"status\"]): string {\n switch (status) {\n case \"pass\":\n return UI_SYMBOLS.CHECK;\n case \"fail\":\n return UI_SYMBOLS.CROSS;\n case \"warn\":\n return \"!\";\n case \"skip\":\n return \"-\";\n default: {\n const _exhaustive: never = status;\n return _exhaustive;\n }\n }\n}\n\nfunction formatCheckLine(name: string, result: CheckResult): string[] {\n const headerLine = `${ROW_INDENT}${formatCheckName(name)}${formatStatus(result.status)} ${result.message}`;\n const detailLines = (result.details ?? []).map(\n (detail) => `${ROW_INDENT}${\" \".repeat(CHECK_WIDTH)} ${detail}`,\n );\n return [headerLine, ...detailLines];\n}\n\nfunction formatSummary(results: CheckResult[]): string {\n const counts = countBy(results, (r) => r.status);\n\n const parts = [\n `${counts.pass ?? 0} passed`,\n plural(counts.warn ?? 0, \"warning\"),\n plural(counts.fail ?? 0, \"error\"),\n ];\n\n return `${SECTION_INDENT}Summary: ${parts.join(\", \")}`;\n}\n\nconst TIPS: Array<{ kind: CheckKind; status: CheckResult[\"status\"]; tip: string }> = [\n {\n kind: \"agents\",\n status: \"warn\",\n tip: ` Tip: Run '${CLI_INVOKE_COMMAND} compile' to generate missing agent files`,\n },\n {\n kind: \"config\",\n status: \"fail\",\n tip: ` Tip: Run '${CLI_INVOKE_COMMAND} init' to create or fix configuration`,\n },\n {\n // The remedy for a valid config with nothing in it. Not the tip above: there is nothing to\n // create and nothing to fix. `init` on this config opens the wizard rather than the dashboard\n // — that is what the detection returning null is FOR — so it is the way to fill it in.\n kind: \"config-empty\",\n status: \"warn\",\n tip: ` Tip: Nothing is configured yet — run '${CLI_INVOKE_COMMAND} init' to choose skills and sub-agents`,\n },\n {\n // The one remedy that applies to a config that cannot be read. `init` does not clear such a\n // file — it refuses it — so the tip above would send the reader in a circle; this is the same\n // way out `edit` and `init` themselves name, worded the same way.\n kind: \"content-config\",\n status: \"fail\",\n tip: ` Tip: There is no automatic repair — recreate the configuration: '${CLI_INVOKE_COMMAND} uninstall' still works on a config it cannot read, then '${CLI_INVOKE_COMMAND} init'`,\n },\n {\n // Printed beside the config tip above, which says how to get a configuration back and\n // nothing about the files that outlived the old one. Both halves are named with what they\n // actually do: `uninstall` matches skill directories by their own `forked-from` metadata and\n // compiled agents by the marker each one carries, so neither needs the configuration that is\n // gone — which is why the row can name both and this tip can promise both.\n kind: \"orphans-unowned\",\n status: \"fail\",\n tip: ` Tip: Nothing declares the files above — '${CLI_INVOKE_COMMAND} init' writes a configuration that can own them again, or '${CLI_INVOKE_COMMAND} uninstall' removes them, the compiled agents included: each file listed carries this CLI's own provenance, which is what that command reads when there is no configuration left`,\n },\n {\n kind: \"skills\",\n status: \"fail\",\n tip: \" Tip: Check skill IDs in config match available skills\",\n },\n {\n kind: \"installed\",\n status: \"warn\",\n // No command is named on purpose: 'eject skills --force' re-copies every skill in the\n // marketplace and always targets project scope, so it cannot repair a global-scoped\n // skill and it litters a plugin-mode project with local skill directories.\n tip: \" Tip: Re-eject the missing skills from the marketplace to restore their files\",\n },\n];\n\nfunction formatTips(results: CheckResult[]): string[] {\n return TIPS.filter((t) => results.some((r) => r.kind === t.kind && r.status === t.status)).map(\n (t) => t.tip,\n );\n}\n\nfunction skippedResult(kind: CheckKind): CheckResult {\n return { kind, status: \"skip\", message: \"Skipped (config invalid)\" };\n}\n\n/**\n * The skills row when the marketplace never loaded. Distinct from {@link skippedResult}: the\n * config is fine, and what is missing is the matrix to resolve its skills against.\n */\nfunction sourceUnreachableSkillsResult(): CheckResult {\n return { kind: \"skills\", status: \"skip\", message: \"Skipped (marketplace unreachable)\" };\n}\n\nfunction skippedContentResult(kind: CheckKind): CheckResult {\n return { kind, status: \"skip\", message: SKIP_CONFIG_UNREADABLE };\n}\n\n/** The content passes that failed this run — the set every operational row is gated against. */\nfunction failedContentKinds(contentResults: CheckResult[]): ReadonlySet<CheckKind> {\n return new Set(contentResults.filter((r) => r.status === \"fail\").map((r) => r.kind));\n}\n\n/**\n * An operational row standing down because a content pass it reads through failed, naming what\n * blocked it. `null` — the answer for most rows on most runs — means nothing it reads is broken\n * and it can speak for itself.\n */\nfunction contentBlockedResult(\n row: CheckKind,\n failedContent: ReadonlySet<CheckKind>,\n): CheckResult | null {\n const blockingNouns = CONTENT_CHECKS.filter((check) => failedContent.has(check.kind))\n .filter((check) => check.blocks.includes(row))\n .map((check) => check.noun);\n\n if (blockingNouns.length === 0) return null;\n\n return { kind: row, status: \"skip\", message: skipRestatingContent(blockingNouns) };\n}\n\nfunction runContentCheck(check: ContentCheck, projectDir: string): Promise<CheckResult> {\n return safeCheck(check.kind, async () => toContentResult(check, await check.run(projectDir)));\n}\n\n/**\n * Wrap a check so a thrown exception becomes a `fail` result instead of crashing the\n * whole doctor run. Per-check isolation ensures one broken check does not mask others.\n */\nasync function safeCheck(kind: CheckKind, fn: () => Promise<CheckResult>): Promise<CheckResult> {\n try {\n return await fn();\n } catch (error) {\n return { kind, status: \"fail\", message: \"Check threw\", details: [getErrorMessage(error)] };\n }\n}\n\nexport default class Doctor extends BaseCommand {\n static summary = \"Diagnose common configuration issues\";\n\n static description = `Run diagnostic checks on your ${DEFAULT_BRANDING.NAME} configuration to identify issues with config validity, skill resolution, agent compilation, and marketplace connectivity.`;\n\n static examples = [\"<%= config.bin %> <%= command.id %>\"];\n\n static flags = {};\n\n async run(): Promise<void> {\n await this.parse(Doctor);\n const projectDir = process.cwd();\n\n // The shared `verbose()` logger stays OFF, and nothing here switches it on. `doctor` used to,\n // for the whole run — the mechanical residue of a `--verbose` flag whose removal was meant to\n // make each row's own DETAILS unconditional, which `formatCheckLine` does on its own. What the\n // logger added on top of that was the loaders' trace, spliced between the section headings and\n // the rows they head: for a directory holding nothing, 27 lines of it, every one restating a\n // row printed underneath it.\n this.printHeader(await this.resolveBrandingName(projectDir));\n const contentResults = await this.runContentChecks(projectDir);\n const operationalResults = await this.runOperationalChecks(projectDir, contentResults);\n const results = [...contentResults, ...operationalResults];\n\n this.printResults(results);\n\n if (results.some((r) => r.status === \"fail\")) {\n this.exit(EXIT_CODES.ERROR);\n }\n }\n\n private printHeader(brandingName: string): void {\n this.log(\"\");\n this.log(`${brandingName} Doctor`);\n this.log(\"\");\n this.log(`${SECTION_INDENT}Checking configuration health...`);\n this.log(\"\");\n }\n\n /**\n * The config is checked first and alone. A check that reads it to know what to validate would\n * otherwise ask a file already reported as unreadable — and asking is what emitted the loader's\n * own failure line once per read, spliced between these rows. Everything that walks installed\n * content on disk still runs: it says something true whatever the config is in.\n */\n private async runContentChecks(projectDir: string): Promise<CheckResult[]> {\n this.log(`${SECTION_INDENT}${SECTION_CONTENT}`);\n\n const configResult = await runContentCheck(CONFIG_CHECK, projectDir);\n const configUnreadable = configResult.status === \"fail\";\n\n const rows = await Promise.all(\n CONTENT_CHECKS.map(async (check) => ({\n name: check.name,\n result:\n check.readsConfig && configUnreadable\n ? skippedContentResult(check.kind)\n : await runContentCheck(check, projectDir),\n })),\n );\n\n const allRows = [{ name: CONFIG_CHECK.name, result: configResult }, ...rows];\n\n for (const row of allRows) {\n this.logCheck(row.name, row.result);\n }\n\n return allRows.map((row) => row.result);\n }\n\n /**\n * The whole layer stands down for the two findings that leave every row with nothing to say: a\n * config nobody can read — every row is read out of it, so all of them would be cascades of that\n * one file — and a marketplace repository with nothing installed, where a marketplace author has\n * no install for the layer to describe. Every other content error is scoped to the rows that\n * read what it is about; {@link GatedContentCheck} says which those are, per pass.\n */\n private async runOperationalChecks(\n projectDir: string,\n contentResults: CheckResult[],\n ): Promise<CheckResult[]> {\n this.log(\"\");\n this.log(`${SECTION_INDENT}${SECTION_OPERATIONAL}`);\n\n const failedContent = failedContentKinds(contentResults);\n if (failedContent.has(CONFIG_CHECK.kind)) {\n this.log(`${ROW_INDENT}${SKIP_AFTER_CONFIG_ERROR}`);\n return [];\n }\n\n const detected = await detectProject(projectDir);\n if (!detected && (await this.isUninstalledSourceRepo(projectDir))) {\n this.log(`${ROW_INDENT}${SKIP_NO_INSTALLATION}`);\n return [];\n }\n\n const configState = await resolveConfigState(detected, projectDir);\n return this.runAllChecks(projectDir, configState, failedContent);\n }\n\n /**\n * A config file that exists but failed to load also detects as \"no project\", and\n * that is a finding rather than an absence — so the skip requires no config file\n * at all, not merely no usable one.\n */\n private async isUninstalledSourceRepo(projectDir: string): Promise<boolean> {\n if (await fileExists(getProjectConfigPath(projectDir))) return false;\n return isSourceRepo(projectDir);\n }\n\n private async runAllChecks(\n projectDir: string,\n configState: ConfigState,\n failedContent: ReadonlySet<CheckKind>,\n ): Promise<CheckResult[]> {\n const { result: configResult, config } = checkConfigValid(configState);\n this.logCheck(\"Config Valid\", configResult);\n\n // loadSource (called by checkSourceReachable) populates the matrix. Run it\n // before checkSkillsResolved so skills lookups see a populated matrix; if\n // source fails, skip skills rather than reporting false \"not found\" errors.\n const sourceResult = await safeCheck(\"source\", () => checkSourceReachable(projectDir));\n\n const filteredConfig = config ? filterExcludedEntries(config) : null;\n\n const skillsResult = await this.resolveSkillsCheck(\n config,\n sourceResult,\n projectDir,\n failedContent,\n );\n this.logCheck(\"Skills Resolved\", skillsResult);\n\n const agentsResult = filteredConfig\n ? await safeCheck(\"agents\", () => checkAgentsCompiled(filteredConfig, projectDir))\n : skippedResult(\"agents\");\n this.logCheck(\"Agents Compiled\", agentsResult);\n\n const orphansResult = await this.resolveOrphansCheck(config, configState, projectDir);\n this.logCheck(\"No Orphans\", orphansResult);\n\n const installedResult = filteredConfig\n ? await safeCheck(\"installed\", () => checkSkillsInstalled(filteredConfig, projectDir))\n : skippedResult(\"installed\");\n this.logCheck(\"Skills Installed\", installedResult);\n\n const pluginsResult = await this.resolvePluginsCheck(filteredConfig, projectDir, failedContent);\n this.logCheck(\"Plugins Installed\", pluginsResult);\n\n this.logCheck(\"Marketplace Reachable\", sourceResult);\n\n return [\n configResult,\n skillsResult,\n agentsResult,\n orphansResult,\n installedResult,\n pluginsResult,\n sourceResult,\n ];\n }\n\n /**\n * The orphan row, and which question it can answer. With a config it names the compiled\n * agents that config does not; with no config at all every installed file is unowned and it\n * names all of them. It skips for the one state left — a config that loads and fails\n * validation — because there the file that says who owns what has already been rejected, and\n * an installation must not be called stranded on the strength of one nobody can trust.\n */\n private async resolveOrphansCheck(\n config: ProjectConfig | null,\n configState: ConfigState,\n projectDir: string,\n ): Promise<CheckResult> {\n if (config) return safeCheck(\"orphans\", () => checkNoOrphans(config, projectDir));\n if (configState.kind === \"absent\") {\n return safeCheck(\"orphans\", () => checkUnownedInstallation(projectDir));\n }\n return skippedResult(\"orphans\");\n }\n\n /**\n * The skills row, and the three states in which it cannot be computed: no config to read the\n * skills out of, content it resolves against that the layer above has already reported broken,\n * and a marketplace that never loaded — so there is no populated matrix to resolve them\n * against, and every configured skill would be reported \"not found\".\n */\n private async resolveSkillsCheck(\n config: ProjectConfig | null,\n sourceResult: CheckResult,\n projectDir: string,\n failedContent: ReadonlySet<CheckKind>,\n ): Promise<CheckResult> {\n if (!config) return skippedResult(\"skills\");\n\n const blocked = contentBlockedResult(\"skills\", failedContent);\n if (blocked) return blocked;\n if (sourceResult.status === \"fail\") return sourceUnreachableSkillsResult();\n\n return safeCheck(\"skills\", () => checkSkillsResolved(config, matrix, projectDir));\n }\n\n /**\n * The plugin row, and the two states in which it cannot be computed: no config to read the\n * plugin-mode skills out of, and a plugin registry the layer above could not parse — which\n * resolves as no installs at all, so every configured skill would be reported missing.\n */\n private async resolvePluginsCheck(\n config: ProjectConfig | null,\n projectDir: string,\n failedContent: ReadonlySet<CheckKind>,\n ): Promise<CheckResult> {\n if (!config) return skippedResult(\"plugins\");\n\n const blocked = contentBlockedResult(\"plugins\", failedContent);\n if (blocked) return blocked;\n\n return safeCheck(\"plugins\", () => checkPluginSkillsInstalled(config, projectDir));\n }\n\n private logCheck(name: string, result: CheckResult): void {\n for (const line of formatCheckLine(name, result)) {\n this.log(line);\n }\n }\n\n private printResults(results: CheckResult[]): void {\n this.log(\"\");\n this.log(formatSummary(results));\n\n const tips = formatTips(results);\n if (tips.length > 0) {\n this.log(\"\");\n for (const tip of tips) {\n this.log(tip);\n }\n }\n\n this.log(\"\");\n }\n}\n","import path from \"path\";\nimport { isRecord } from \"../utils/type-guards.js\";\nimport { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\nimport { glob, readFile, fileExists, directoryExists } from \"../utils/fs\";\nimport {\n DIRS,\n MARKETPLACE_JSON,\n PLUGIN_MANIFEST_DIR,\n SKILL_CATEGORIES_PATH,\n SKILL_RULES_PATH,\n SKILLS_DIR_PATH,\n STACKS_FILE_PATH,\n STANDARD_FILES,\n} from \"../consts\";\nimport {\n agentYamlGenerationSchema,\n metadataValidationSchema,\n splitMetadataValidationIssues,\n validateSkillMetadata,\n skillCategoriesFileSchema,\n skillRulesFileSchema,\n stackConfigValidationSchema,\n stacksConfigSchema,\n} from \"./schemas\";\nimport { parseFrontmatter } from \"./loading/loader\";\nimport { ConfigDefaultExportError, loadConfig, loadProjectSourceConfig } from \"./configuration\";\nimport { checkMatrixHealth, type MatrixHealthIssue } from \"./matrix\";\nimport { loadSkillsMatrixFromSource } from \"./loading/source-loader\";\nimport { MarketplaceNameRefusedError } from \"./loading/source-fetcher\";\nimport { matrix } from \"./matrix/matrix-provider\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { formatZodErrors } from \"./schema-validator\";\n\nexport type SourceValidationIssue = {\n severity: \"error\" | \"warning\";\n file: string;\n message: string;\n};\n\nexport type SourceValidationResult = {\n issues: SourceValidationIssue[];\n skillCount: number;\n errorCount: number;\n warningCount: number;\n};\n\n/**\n * Who this report is for, relative to the marketplace it is about.\n *\n * You are the `\"author\"` of the marketplace being validated when it IS the directory the command\n * ran in; a marketplace anywhere else — fetched, or on disk at another path — is one you are only\n * a `\"consumer\"` of. Not \"is there a marketplace under the cwd\": that says nothing about the OTHER\n * marketplace a config may point at, and the severity turns on the per-marketplace question.\n *\n * It changes one finding. A slug a marketplace's rules dangle is a typo its author can fix and\n * wants the run to fail on, and it is a defect a consumer cannot touch in a file they cannot open\n * — while every skill still installs and still resolves. Whether the reader holds push rights is\n * not knowable here and is not the test: a checkout under your cursor is a file you can edit.\n */\nexport type MarketplaceReader = \"author\" | \"consumer\";\n\n/**\n * True when `dir` is itself a skills source repository — it carries the skills tree\n * `validateSource` walks, at `src/skills/` or wherever its own source config points.\n * A marketplace author's checkout answers yes; a consumer project answers no.\n */\nexport async function isSourceRepo(dir: string): Promise<boolean> {\n // ABORT on an unreadable config, and it is caught rather than fatal at both callers: `doctor`\n // reaches this through `safeCheck`, so the throw becomes a failed row instead of an aborted\n // command, and its other caller asks only where no config file exists at all.\n const sourceConfig = await loadProjectSourceConfig(dir);\n return directoryExists(path.join(dir, sourceConfig?.skillsDir ?? SKILLS_DIR_PATH));\n}\n\n/** Checks if a key uses snake_case (has underscore between lowercase letters) */\nexport function isSnakeCase(key: string): boolean {\n return /[a-z]_[a-z]/.test(key);\n}\n\n/**\n * Checks top-level keys for snake_case usage (camelCase is the convention).\n * Non-object input yields no issues.\n */\nexport function checkSnakeCaseKeys(rawMetadata: unknown, relPath: string): SourceValidationIssue[] {\n if (!isRecord(rawMetadata)) return [];\n\n return Object.keys(rawMetadata)\n .filter(isSnakeCase)\n .map((key) => ({\n severity: \"error\" as const,\n file: relPath,\n message: `Key '${key}' uses snake_case — use camelCase instead`,\n }));\n}\n\n/**\n * Warns when a skill directory's name does not equal the skill's machine id\n * (SKILL.md frontmatter `name`) — the key the loader registers the skill under.\n * Warning, not error: the loader still loads the skill by its id, but the\n * directory no longer signals which skill it contains.\n */\nexport function checkDirNameMatchesSkillId(\n skillId: string,\n relPath: string,\n dirName: string,\n): SourceValidationIssue[] {\n if (skillId === dirName) return [];\n return [\n {\n severity: \"warning\",\n file: relPath,\n message: `Directory name '${dirName}' does not match skill id '${skillId}'`,\n },\n ];\n}\n\n/**\n * Reads a skill directory's SKILL.md frontmatter and checks the directory name\n * against the skill's machine id. When the id cannot be read (unreadable file or\n * missing/invalid frontmatter), reports that the check could not run.\n */\nasync function checkSkillDirName(\n skillsDir: string,\n skillsDirRelPath: string,\n skillDir: string,\n): Promise<SourceValidationIssue[]> {\n const dirName = path.basename(skillDir);\n const skillMdRelPath = path.join(skillsDirRelPath, skillDir, STANDARD_FILES.SKILL_MD);\n\n try {\n const content = await readFile(path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD));\n const frontmatter = parseFrontmatter(content, skillMdRelPath);\n\n if (frontmatter === null) {\n return [\n {\n severity: \"warning\",\n file: skillMdRelPath,\n message: `Cannot verify directory name '${dirName}': missing or invalid ${STANDARD_FILES.SKILL_MD} frontmatter`,\n },\n ];\n }\n\n return checkDirNameMatchesSkillId(frontmatter.name, skillMdRelPath, dirName);\n } catch (error) {\n return [\n {\n severity: \"warning\",\n file: skillMdRelPath,\n message: `Cannot verify directory name '${dirName}': ${getErrorMessage(error)}`,\n },\n ];\n }\n}\n\n/**\n * Finds missing SKILL.md / metadata.yaml pairs (pure function, no I/O).\n *\n * Returns issues for:\n * - Directories with SKILL.md but no metadata.yaml\n * - Directories with metadata.yaml but no SKILL.md\n */\nexport function validateSkillFilePairs(\n skillMdDirs: Set<string>,\n metadataDirs: Set<string>,\n skillsDir: string,\n): SourceValidationIssue[] {\n const missingMetadata = [...skillMdDirs]\n .filter((dir) => !metadataDirs.has(dir))\n .map((dir) => ({\n severity: \"error\" as const,\n file: path.join(skillsDir, dir),\n message: `Missing ${STANDARD_FILES.METADATA_YAML} — skill directory has ${STANDARD_FILES.SKILL_MD} but no metadata`,\n }));\n\n const missingSkillMd = [...metadataDirs]\n .filter((dir) => !skillMdDirs.has(dir))\n .map((dir) => ({\n severity: \"error\" as const,\n file: path.join(skillsDir, dir),\n message: `Missing ${STANDARD_FILES.SKILL_MD} — skill directory has ${STANDARD_FILES.METADATA_YAML} but no SKILL.md`,\n }));\n\n return [...missingMetadata, ...missingSkillMd];\n}\n\n/**\n * Validates a skills source repository for metadata correctness.\n *\n * Checks:\n * 1. Every metadata.yaml against the strict validation schema\n * (over-length cliDescription is downgraded to a warning)\n * 2. Directory name equals the skill's machine id (SKILL.md frontmatter name)\n * 3. Cross-references resolve to existing skill IDs (via checkMatrixHealth)\n * 4. camelCase key convention (no snake_case)\n * 5. Every skill directory has both SKILL.md and metadata.yaml\n *\n * `reader` decides how loudly one of those findings is stated — see {@link MarketplaceReader}.\n * It defaults to `\"author\"`, the louder verdict: a caller that names nobody has said nothing\n * about who is reading, and under-reporting to the one person who can fix the file is the worse\n * of the two ways to be wrong.\n */\nexport async function validateSource(\n sourcePath: string,\n reader: MarketplaceReader = \"author\",\n): Promise<SourceValidationResult> {\n const issues: SourceValidationIssue[] = [];\n\n const resolvedPath = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(sourcePath);\n\n if (!(await directoryExists(resolvedPath))) {\n issues.push({\n severity: \"error\",\n file: resolvedPath,\n message: \"Marketplace directory does not exist\",\n });\n return buildResult(issues, 0);\n }\n\n // ABORT on an unreadable config, caught by `validateOneSource`, which turns it into an issue\n // against this marketplace. Defaulting past it would validate whatever sits at `src/skills/` and\n // call a marketplace whose skills live elsewhere empty.\n const sourceProjectConfig = await loadProjectSourceConfig(resolvedPath);\n const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;\n const skillsDir = path.join(resolvedPath, skillsDirRelPath);\n\n if (!(await directoryExists(skillsDir))) {\n issues.push({\n severity: \"error\",\n file: skillsDir,\n message: \"Skills directory does not exist\",\n });\n return buildResult(issues, 0);\n }\n\n // Phase 1: Check every skill directory has both SKILL.md and metadata.yaml\n const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);\n const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);\n\n const skillMdDirs = new Set(skillMdFiles.map((f) => path.dirname(f)));\n const metadataDirs = new Set(metadataFiles.map((f) => path.dirname(f)));\n\n issues.push(...validateSkillFilePairs(skillMdDirs, metadataDirs, skillsDir));\n\n // Phase 2: Validate each metadata.yaml against strict schema and conventions.\n // Pair violations were already reported by phase 1 — validate only complete pairs.\n const validMetadataFiles = metadataFiles.filter((f) => skillMdDirs.has(path.dirname(f)));\n for (const metadataFile of validMetadataFiles) {\n issues.push(...(await validateOneSkill(skillsDir, skillsDirRelPath, metadataFile)));\n }\n\n // Phase 3: Cross-reference validation via matrix health check\n issues.push(...(await checkCrossReferences(resolvedPath, reader)));\n\n // Phases 4–6: optional source-repo targets — run in parallel\n // Phase 4: stack skill metadata + stack configs\n // Phase 5: agent metadata\n // Phase 6: config/*.ts runtime exports\n const extraIssues = await Promise.all([\n validateStacks(resolvedPath),\n validateAgents(resolvedPath),\n validateConfigFiles(resolvedPath),\n ]);\n issues.push(...extraIssues.flat());\n\n return buildResult(issues, validMetadataFiles.length);\n}\n\n/**\n * Why a YAML file could not be read, in the parser's own words. Two phases refuse the same\n * way — the skill-pair scan and the stack/agent scan — and they printed different sentences\n * for a while, one carrying the cause and one dropping it; naming the message once is what\n * stops them diverging again.\n */\nfunction yamlParseFailure(error: unknown): string {\n return `Failed to parse YAML: ${getErrorMessage(error)}`;\n}\n\n/**\n * One complete skill pair, judged four ways: its metadata.yaml parses, its keys are camelCase,\n * it satisfies the strict published-skill schema, and its directory is named after the id its\n * SKILL.md declares. A file nothing can be parsed out of reports that and stops — every check\n * after it reads the parsed value, so each would only restate the same fault.\n */\nasync function validateOneSkill(\n skillsDir: string,\n skillsDirRelPath: string,\n metadataFile: string,\n): Promise<SourceValidationIssue[]> {\n const relPath = path.join(skillsDirRelPath, metadataFile);\n\n let rawMetadata: unknown;\n try {\n rawMetadata = parseYaml(await readFile(path.join(skillsDir, metadataFile)));\n } catch (error) {\n return [{ severity: \"error\", file: relPath, message: yamlParseFailure(error) }];\n }\n\n return [\n ...checkSnakeCaseKeys(rawMetadata, relPath),\n ...checkMetadataSchema(rawMetadata, relPath),\n // Independent of metadata validity — the id lives in SKILL.md frontmatter\n ...(await checkSkillDirName(skillsDir, skillsDirRelPath, path.dirname(metadataFile))),\n ];\n}\n\n/**\n * The strict published-skill schema's verdict, as its hard errors plus the one advisory\n * (over-length cliDescription) `splitMetadataValidationIssues` separates out.\n */\nfunction checkMetadataSchema(rawMetadata: unknown, relPath: string): SourceValidationIssue[] {\n const result = validateSkillMetadata(rawMetadata);\n if (result.success) return [];\n\n const { errors, warnings } = splitMetadataValidationIssues(result.error, rawMetadata);\n return [\n ...errors.map((message) => ({ severity: \"error\" as const, file: relPath, message })),\n ...warnings.map((message) => ({ severity: \"warning\" as const, file: relPath, message })),\n ];\n}\n\n/**\n * The manifest as a reader of the report has to type it — the location half of the row\n * `doctor` prints, and therefore the file they open.\n */\nconst MARKETPLACE_MANIFEST_PATH = path.join(PLUGIN_MANIFEST_DIR, MARKETPLACE_JSON);\n\n/**\n * Whether every relationship the source declares resolves to a skill it actually holds.\n * A load that did not complete is reported by {@link matrixLoadFailure}, which decides\n * whether the failure is this marketplace's fault or merely this pass's.\n */\nasync function checkCrossReferences(\n resolvedPath: string,\n reader: MarketplaceReader,\n): Promise<SourceValidationIssue[]> {\n try {\n await loadSkillsMatrixFromSource({ sourceFlag: resolvedPath, skipExtraSources: true });\n return checkMatrixHealth(matrix).map((healthIssue) =>\n toSourceIssue(healthIssue, resolvedPath, reader),\n );\n } catch (error) {\n return [matrixLoadFailure(error)];\n }\n}\n\n/**\n * A load this pass could not complete, as the finding a reader can act on.\n *\n * Two answers, because the two failures are not one event. A manifest naming the\n * marketplace something Claude Code registers no plugin under leaves nothing here\n * installable, so it is this marketplace's own ERROR, against the file that holds the\n * name — without it the Marketplaces row counted such a marketplace as validated and\n * printed a tick beneath `doctor`'s own warning about that same file, and a warning above\n * a tick is what a reader stops believing. Everything else leaves the marketplace\n * installable and only leaves this pass unable to run, so it stays a warning against the\n * file it was reading. Read off the throw's TYPE, so nothing here matches on a sentence.\n */\nfunction matrixLoadFailure(error: unknown): SourceValidationIssue {\n if (error instanceof MarketplaceNameRefusedError) {\n return {\n severity: \"error\",\n file: MARKETPLACE_MANIFEST_PATH,\n message: getErrorMessage(error),\n };\n }\n\n return {\n severity: \"warning\",\n file: SKILL_CATEGORIES_PATH,\n message: `Cross-reference validation skipped: failed to load categories/rules: ${getErrorMessage(error)}`,\n };\n}\n\n/**\n * The audit manifest, as a path a reader can open. It is this CLI's own file rather than anything\n * in the marketplace being validated, and it has to be: the verdict a matrix contradicts is\n * recorded there and the marketplace holds no copy of it.\n */\nconst SKILL_AUDIT_PATH = \"src/cli/lib/configuration/skill-audit.ts\";\n\n/**\n * The file a finding's defect is written in — the one `doctor` renders as the location half of the\n * line, and therefore the one the reader opens.\n *\n * Each answer is the file the check actually reads, which is not always the file its name suggests:\n *\n * - a category and the `domain` it omits are both declared in the categories file, and a skill\n * naming a category nothing defines is the same file short an entry (its own metadata.yaml is\n * the other half of that fix, and the message already names the skill);\n * - every relation a resolved skill carries comes from the rules file — no metadata.yaml declares\n * one — so an unresolved reference and the dangling slug behind it are both written there;\n * - a verdict, recorded or missing, is the audit manifest's.\n *\n * Exhaustive on purpose: a seventh finding kind will not compile until someone decides where its\n * defect lives, which is the property one path shared by all six had already lost.\n */\nfunction fileHoldingDefect(finding: MatrixHealthIssue[\"finding\"]): string {\n switch (finding) {\n case \"category-missing-domain\":\n case \"skill-unknown-category\":\n return SKILL_CATEGORIES_PATH;\n case \"skill-unresolved-relation-ref\":\n case \"rule-unresolved-slug\":\n return SKILL_RULES_PATH;\n case \"audit-verdict-contradiction\":\n case \"skill-unaudited\":\n return SKILL_AUDIT_PATH;\n default: {\n const exhaustive: never = finding;\n return exhaustive;\n }\n }\n}\n\n/**\n * One health finding as this reader should hear it. Every kind but one is reported at the\n * severity the health check gave it — that severity is a property of the defect. The exception\n * is the slug a marketplace's own rules dangle, which is a property of the defect AND of who is\n * looking: a typo the author can fix, and a file the consumer cannot open.\n *\n * The reader moves the severity and the wording; it never moves the file, because which file holds\n * the defect is not a fact about who is reading.\n */\nfunction toSourceIssue(\n healthIssue: MatrixHealthIssue,\n marketplacePath: string,\n reader: MarketplaceReader,\n): SourceValidationIssue {\n const file = fileHoldingDefect(healthIssue.finding);\n\n if (reader === \"consumer\" && healthIssue.finding === \"rule-unresolved-slug\") {\n return {\n severity: \"warning\",\n file,\n message: consumedMarketplaceMessage(marketplacePath, healthIssue.details),\n };\n }\n\n return {\n severity: healthIssue.severity,\n file,\n message: healthIssue.details,\n };\n}\n\n/**\n * The same finding, addressed to someone who did not write the rule. It leads with the\n * marketplace because that is the part the slug alone does not tell them, and it says outright\n * that there is nothing here to fix — a warning that sends a reader hunting through their own\n * project for a typo in a file they do not own is worse than no warning at all.\n */\nfunction consumedMarketplaceMessage(marketplacePath: string, details: string): string {\n return `Marketplace '${marketplacePath}': ${details}. Nothing to fix here — the rule is that marketplace's, not this project's`;\n}\n\n/**\n * Validates stack-embedded skill metadata.yaml files and stack config.yaml files.\n * Skips silently when src/stacks/ does not exist.\n */\nasync function validateStacks(resolvedPath: string): Promise<SourceValidationIssue[]> {\n const stacksDir = path.join(resolvedPath, DIRS.stacks);\n if (!(await directoryExists(stacksDir))) return [];\n\n const [skillMetaIssues, configIssues] = await Promise.all([\n validateYamlFiles({\n baseDir: stacksDir,\n relBaseDir: DIRS.stacks,\n pattern: `**/skills/**/${STANDARD_FILES.METADATA_YAML}`,\n schema: metadataValidationSchema,\n }),\n validateYamlFiles({\n baseDir: stacksDir,\n relBaseDir: DIRS.stacks,\n pattern: `*/${STANDARD_FILES.CONFIG_YAML}`,\n schema: stackConfigValidationSchema,\n }),\n ]);\n return [...skillMetaIssues, ...configIssues];\n}\n\n/**\n * Validates agent metadata.yaml files against the compiled agent output schema.\n * Skips silently when src/agents/ does not exist.\n */\nasync function validateAgents(resolvedPath: string): Promise<SourceValidationIssue[]> {\n const agentsDir = path.join(resolvedPath, DIRS.agents);\n if (!(await directoryExists(agentsDir))) return [];\n\n return validateYamlFiles({\n baseDir: agentsDir,\n relBaseDir: DIRS.agents,\n pattern: `**/${STANDARD_FILES.AGENT_METADATA_YAML}`,\n schema: agentYamlGenerationSchema,\n });\n}\n\n/**\n * Validates TypeScript config files (skill-categories.ts, skill-rules.ts, stacks.ts)\n * by runtime-loading them via loadConfig and validating the default export.\n * Skips silently when a file does not exist.\n */\nasync function validateConfigFiles(resolvedPath: string): Promise<SourceValidationIssue[]> {\n const results = await Promise.all([\n validateTsConfig(resolvedPath, SKILL_CATEGORIES_PATH, skillCategoriesFileSchema),\n validateTsConfig(resolvedPath, SKILL_RULES_PATH, skillRulesFileSchema),\n validateTsConfig(resolvedPath, STACKS_FILE_PATH, stacksConfigSchema),\n ]);\n return results.flat();\n}\n\n/**\n * Globs YAML files under baseDir and validates each against the given schema.\n * Reports parse errors, schema errors (as field-path messages), and uses relBaseDir\n * for display paths so issue locations match the project-relative form used elsewhere.\n */\nasync function validateYamlFiles(opts: {\n baseDir: string;\n relBaseDir: string;\n pattern: string;\n schema: z.ZodType<unknown>;\n}): Promise<SourceValidationIssue[]> {\n const issues: SourceValidationIssue[] = [];\n const files = await glob(opts.pattern, opts.baseDir);\n\n for (const relFile of files) {\n const absPath = path.join(opts.baseDir, relFile);\n const displayPath = path.join(opts.relBaseDir, relFile);\n\n let parsed: unknown;\n try {\n parsed = parseYaml(await readFile(absPath));\n } catch (error) {\n issues.push({ severity: \"error\", file: displayPath, message: yamlParseFailure(error) });\n continue;\n }\n\n const result = opts.schema.safeParse(parsed);\n if (result.success) continue;\n\n issues.push(\n ...formatZodErrors(result.error).map((message) => ({\n severity: \"error\" as const,\n file: displayPath,\n message,\n })),\n );\n }\n return issues;\n}\n\n/**\n * Runtime-loads a TypeScript config file via loadConfig and reports validation failures.\n * Absent files are not errors — only report when the file exists but fails to load or validate.\n *\n * The two ways a file can say nothing are reported apart, because the author's next move differs\n * and they used to arrive wearing each other's words. A `null` is a file that exported nothing at\n * all; a module that exported only named bindings raises {@link ConfigDefaultExportError}, which\n * is the one this file's own config files get wrong — `export const skillRules = {...}` reads to\n * `loadConfig` as a namespace, and validating THAT against the schema reports whichever field the\n * schema names first as missing from a file the author can see it in.\n */\nasync function validateTsConfig(\n resolvedPath: string,\n relConfigPath: string,\n schema: z.ZodType<unknown>,\n): Promise<SourceValidationIssue[]> {\n const absPath = path.join(resolvedPath, relConfigPath);\n if (!(await fileExists(absPath))) return [];\n\n try {\n const loaded = await loadConfig(absPath, schema);\n if (loaded === null) {\n return [{ severity: \"error\", file: relConfigPath, message: \"Config is empty\" }];\n }\n return [];\n } catch (error) {\n if (error instanceof ConfigDefaultExportError) {\n return [{ severity: \"error\", file: relConfigPath, message: \"Config has no default export\" }];\n }\n return [\n { severity: \"error\", file: relConfigPath, message: formatLoadError(relConfigPath, error) },\n ];\n }\n}\n\n/**\n * Normalizes a loadConfig error so the message references the relative config path,\n * not the absolute path embedded by loadConfig's own template string.\n */\nfunction formatLoadError(relConfigPath: string, error: unknown): string {\n const raw = getErrorMessage(error);\n const stripped = raw.replace(/Failed to load config from '[^']+':\\s*/, \"\");\n return `Failed to load ${relConfigPath}: ${stripped}`;\n}\n\nfunction buildResult(issues: SourceValidationIssue[], skillCount: number): SourceValidationResult {\n const errorCount = issues.filter((i) => i.severity === \"error\").length;\n const warningCount = issues.filter((i) => i.severity === \"warning\").length;\n return { issues, skillCount, errorCount, warningCount };\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { partition } from \"remeda\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { PLUGIN_MANIFEST_DIR, STANDARD_FILES } from \"../consts.js\";\nimport { directoryExists, fileExists, listDirectories } from \"../utils/fs.js\";\nimport { listAgentMdFiles, splitAgentsByProvenance } from \"./agents/index.js\";\nimport { readSkillMetadata } from \"./loading/index.js\";\nimport {\n configDirsInPlay,\n findConfigLoadFailures,\n getProjectConfigPath,\n isLocalSource,\n loadProjectConfigFromDir,\n resolvePrimarySourceEntry,\n type ConfigLoadError,\n type LoadedProjectConfig,\n type SourceEntry,\n} from \"./configuration/index.js\";\nimport { isHomeDirectory, resolveInstallPaths } from \"./installation/index.js\";\nimport {\n getInstalledPluginsRegistryPath,\n getProjectPluginsDir,\n getUserPluginsDir,\n listRegisteredPluginInstalls,\n validateAgentFrontmatter,\n validateAllPlugins,\n validatePlugin,\n validateSkillFrontmatter,\n type ResolvedPlugin,\n} from \"./plugins/index.js\";\nimport { splitMetadataValidationIssues, validateSkillMetadata } from \"./schemas.js\";\nimport { readForkedFromMetadata } from \"./skills/index.js\";\nimport { isSourceRepo, validateSource, type MarketplaceReader } from \"./source-validator.js\";\nimport type { ValidationResult } from \"../types/index.js\";\n\n/** How a source repository under the cwd is labelled when it is not a registered source. */\nconst CWD_SOURCE_NAME = \"current directory\";\n\n/** What a compiled agent is called on disk; `splitAgentsByProvenance` answers in bare names. */\nconst AGENT_FILE_EXTENSION = \".md\";\n\nexport type ContentIssue = {\n severity: \"error\" | \"warning\";\n /** The file or directory a reader has to open to fix the issue. */\n file: string;\n message: string;\n};\n\n/**\n * One content pass: what it walked, what it found, and what it deliberately did\n * not check. `notes` carries neither errors nor warnings — it is the record of\n * which sources were reached and which were skipped.\n */\nexport type ContentValidation = {\n count: number;\n issues: ContentIssue[];\n notes: string[];\n};\n\nconst NOTHING_VALIDATED: ContentValidation = { count: 0, issues: [], notes: [] };\n\nfunction mergeValidations(parts: ContentValidation[]): ContentValidation {\n return parts.reduce(\n (acc, part) => ({\n count: acc.count + part.count,\n issues: [...acc.issues, ...part.issues],\n notes: [...acc.notes, ...part.notes],\n }),\n NOTHING_VALIDATED,\n );\n}\n\n/** Render an absolute path with a `~/` prefix when it's under the user's home directory. */\nfunction displayDir(absolutePath: string): string {\n const home = os.homedir();\n if (absolutePath === home) return \"~\";\n if (absolutePath.startsWith(home + path.sep)) {\n return `~${path.sep}${path.relative(home, absolutePath)}`;\n }\n return absolutePath;\n}\n\nfunction toIssues(file: string, result: ValidationResult): ContentIssue[] {\n return [\n ...result.errors.map((message) => ({ severity: \"error\" as const, file, message })),\n ...result.warnings.map((message) => ({ severity: \"warning\" as const, file, message })),\n ];\n}\n\n/** Says which of the three load outcomes a config file is in, without restating the loader. */\nconst CONFIG_UNREADABLE = \"exists but could not be loaded\";\n\n/**\n * Validates the config files this run reads: the project's own and the global one it inlines.\n *\n * A config that exists and cannot be parsed is reported here rather than left to the operational\n * layer, for the reason that layer exists to be gated on — every operational row is read OUT of\n * this file, so each would be a cascade of the same fault. It is also the only report that can\n * carry the loader's reason: the layers below re-read the file per check, and their own\n * diagnostics for it are what used to arrive spliced between the rows.\n *\n * An ABSENT config is not a finding here. It is the legitimate state `init` exists for, and the\n * operational layer already names it and offers the remedy that fits it.\n */\nexport async function validateProjectConfigFile(projectDir: string): Promise<ContentValidation> {\n const [present, failures] = await Promise.all([\n countExistingConfigs(projectDir),\n findConfigLoadFailures(projectDir),\n ]);\n\n return { count: present, issues: failures.map(toUnreadableConfigIssue), notes: [] };\n}\n\nfunction toUnreadableConfigIssue(failure: ConfigLoadError): ContentIssue {\n return {\n severity: \"error\",\n file: displayDir(failure.configPath),\n message: `${CONFIG_UNREADABLE}: ${failure.reason}`,\n };\n}\n\nasync function countExistingConfigs(projectDir: string): Promise<number> {\n const present = await Promise.all(\n configDirsInPlay(projectDir).map((dir) => fileExists(getProjectConfigPath(dir))),\n );\n return present.filter(Boolean).length;\n}\n\n/**\n * Validates the marketplace this installation reads from when it is local, plus the current\n * directory when that is itself a skills source repository — that repository is the content a\n * marketplace author runs this against, and it is not the source they read skills from.\n * A remote marketplace is recorded as skipped rather than fetched.\n *\n * Each one is validated as the reader's own or as someone else's — see {@link readerFor}.\n */\nexport async function validateRegisteredSources(projectDir: string): Promise<ContentValidation> {\n // DEGRADE on an unreadable config. This pass declares `readsConfig: true`, so `doctor` stands it\n // down before it runs whenever the config check has already reported the file — and if it is\n // reached anyway, `safeCheck` turns the throw into a failed row rather than an aborted run. A\n // command whose job is naming what is wrong here must survive the thing it is naming.\n const primary = await resolvePrimarySourceEntry(projectDir);\n const registered = [primary];\n const remote = registered.filter((source) => !isLocalSource(source.url));\n const local = await localSourcesToValidate(projectDir, registered);\n\n const outcomes = await Promise.all(\n local.map((source) => validateOneSource(source, readerFor(projectDir, source))),\n );\n\n return {\n count: local.length,\n issues: outcomes.flatMap((outcome) => outcome.issues),\n notes: [\n ...outcomes.map((outcome) => outcome.note),\n ...remote.map((source) => `${source.name} (${source.url}) — skipped (remote)`),\n ],\n };\n}\n\nasync function localSourcesToValidate(\n projectDir: string,\n registered: SourceEntry[],\n): Promise<SourceEntry[]> {\n const local = registered.filter((source) => isLocalSource(source.url));\n const alreadyCovered = local.some((source) => isCwdMarketplace(projectDir, source));\n\n if (alreadyCovered || !(await isSourceRepo(projectDir))) return local;\n\n return [...local, { name: CWD_SOURCE_NAME, url: projectDir }];\n}\n\n/** Whether this marketplace IS the directory the command ran in, however the config spells it. */\nfunction isCwdMarketplace(projectDir: string, source: SourceEntry): boolean {\n return path.resolve(projectDir, source.url) === projectDir;\n}\n\n/**\n * Where this layer decides what the reader's relationship to a marketplace is — the one place\n * that holds both the directory the command ran in and the path of each marketplace it validates.\n * The appended `CWD_SOURCE_NAME` entry answers `\"author\"` by construction, which is the whole of\n * why a marketplace author's own repository is judged the way they need it to be.\n */\nfunction readerFor(projectDir: string, source: SourceEntry): MarketplaceReader {\n return isCwdMarketplace(projectDir, source) ? \"author\" : \"consumer\";\n}\n\ntype SourceOutcome = { note: string; issues: ContentIssue[] };\n\nasync function validateOneSource(\n source: SourceEntry,\n reader: MarketplaceReader,\n): Promise<SourceOutcome> {\n const label = `${source.name} (${source.url})`;\n try {\n const result = await validateSource(source.url, reader);\n return { note: `${label} — ${result.skillCount} skills`, issues: result.issues };\n } catch (error) {\n return {\n note: `${label} — failed`,\n issues: [{ severity: \"error\", file: source.url, message: getErrorMessage(error) }],\n };\n }\n}\n\n/** Validates every installed plugin bundle in the global and project plugin directories. */\nexport async function validateInstalledPlugins(projectDir: string): Promise<ContentValidation> {\n const dirs = [\n getUserPluginsDir(),\n ...(isHomeDirectory(projectDir) ? [] : [getProjectPluginsDir(projectDir)]),\n ];\n return mergeValidations(await Promise.all(dirs.map(validatePluginsDirectory)));\n}\n\nasync function validatePluginsDirectory(pluginsDir: string): Promise<ContentValidation> {\n if (!(await directoryExists(pluginsDir))) return NOTHING_VALIDATED;\n\n if (await fileExists(getInstalledPluginsRegistryPath(pluginsDir))) {\n const registryValidation = await validateRegistryPlugins(pluginsDir);\n if (registryValidation !== undefined) return registryValidation;\n }\n\n const pluginDirs = await findPluginDirectories(pluginsDir);\n if (pluginDirs.length === 0) return NOTHING_VALIDATED;\n\n const { results } = await validateAllPlugins(pluginsDir);\n\n return {\n count: results.length,\n issues: results.flatMap(({ name, result }) => toIssues(name, result)),\n notes: [],\n };\n}\n\n/**\n * Validates the installs recorded in the plugins directory's `installed_plugins.json`\n * (claude CLI >=2.1.220 cache layout). Returns undefined when the registry records no\n * installs so the caller can fall back to the direct-children scan (older/manual layouts).\n */\nasync function validateRegistryPlugins(pluginsDir: string): Promise<ContentValidation | undefined> {\n let installs: ResolvedPlugin[];\n try {\n installs = await listRegisteredPluginInstalls(pluginsDir);\n } catch (error) {\n return {\n count: 0,\n issues: [\n {\n severity: \"error\",\n file: displayDir(getInstalledPluginsRegistryPath(pluginsDir)),\n message: getErrorMessage(error),\n },\n ],\n notes: [],\n };\n }\n\n if (installs.length === 0) return undefined;\n\n // A recorded installPath that no longer exists surfaces as an invalid plugin\n // via validatePlugin's structure check, not a crash.\n const results = await Promise.all(\n installs.map(async ({ pluginKey, installPath }) =>\n toIssues(pluginKey, await validatePlugin(installPath)),\n ),\n );\n\n return { count: installs.length, issues: results.flat(), notes: [] };\n}\n\nasync function findPluginDirectories(pluginsDir: string): Promise<string[]> {\n const entries = await listDirectories(pluginsDir);\n const checks = await Promise.all(\n entries.map(async (name) => ({\n name,\n isPlugin: await directoryExists(path.join(pluginsDir, name, PLUGIN_MANIFEST_DIR)),\n })),\n );\n return checks.filter((check) => check.isPlugin).map((check) => check.name);\n}\n\n/**\n * Validates the SKILL.md and metadata.yaml of every installed skill this installation owns, both\n * scopes.\n *\n * Ownership has to be asked because `~/.claude/skills/` is CLAUDE CODE's directory, shared with\n * everything else that installs a skill there — not this CLI's private space. Judging every\n * directory in it against this CLI's schema reported a skill some other tool put there as a fault\n * in the user's install, in a file they never wrote and cannot fix from here.\n *\n * Two claims make a directory this installation's, and either is enough:\n *\n * - **The configuration in play names its id.** Both configs a run reads, because both scopes are\n * walked. This is the claim that keeps `doctor` loud where it matters most: the provenance\n * marker lives INSIDE metadata.yaml, so a skill whose metadata is missing or unparseable — the\n * plainest breakage there is — can carry no marker to be recognised by.\n * - **The directory carries `forkedFrom`.** The marker this CLI stamps into every skill directory\n * it writes, and the same question `uninstall` asks before removing anything. It answers for the\n * skills a configuration has stopped naming, or never got the chance to.\n *\n * A directory neither claim reaches is not judged and not counted. It IS named — see\n * {@link foreignSkillNote}: a check that quietly walks past a directory is indistinguishable from\n * one that missed it.\n */\nexport async function validateInstalledSkills(projectDir: string): Promise<ContentValidation> {\n const configuredIds = await configuredSkillIds(projectDir);\n return mergeValidations(\n await Promise.all(\n installedDirs(projectDir, \"skillsDir\").map((dir) =>\n validateSkillsDirectory(dir, configuredIds),\n ),\n ),\n );\n}\n\n/** Every skill id the configs this run reads name, across both scopes and both install modes. */\nasync function configuredSkillIds(projectDir: string): Promise<ReadonlySet<string>> {\n const loaded = await Promise.all(configDirsInPlay(projectDir).map(loadProjectConfigFromDir));\n return new Set(loaded.flatMap(configuredIdsOf));\n}\n\nfunction configuredIdsOf(loaded: LoadedProjectConfig | null): string[] {\n if (!loaded) return [];\n return loaded.config.skills.map((skill) => skill.id);\n}\n\n/** Validates the frontmatter of every compiled agent file, both scopes. */\nexport async function validateInstalledAgents(projectDir: string): Promise<ContentValidation> {\n return mergeValidations(\n await Promise.all(installedDirs(projectDir, \"agentsDir\").map(validateAgentsDirectory)),\n );\n}\n\n/**\n * The directories to walk for an installed-content pass. At the home directory both\n * scopes resolve to the same place, so it is walked once instead of twice.\n */\nfunction installedDirs(projectDir: string, key: \"skillsDir\" | \"agentsDir\"): string[] {\n const global = resolveInstallPaths(projectDir, \"global\")[key];\n if (isHomeDirectory(projectDir)) return [global];\n return [global, resolveInstallPaths(projectDir, \"project\")[key]];\n}\n\n/** What an installed-content pass walked, named rather than validated. */\nexport type InstalledArtifacts = {\n /** Every skill directory this CLI can prove it wrote, both scopes, as display paths. */\n skills: string[];\n /** Every compiled agent file this CLI can prove it wrote, both scopes, as display paths. */\n agents: string[];\n};\n\n/**\n * The same two walks {@link validateInstalledSkills} and {@link validateInstalledAgents} count,\n * naming what belongs to this installation instead of judging it. `doctor` reports this when no\n * configuration exists to compare the installation against: there is nothing to validate the\n * files AGAINST, and naming them is the whole finding.\n *\n * Each walk applies the same ownership question its own pass asks, minus the half that needs a\n * config to answer — see {@link listSkillDirsWithOurProvenance} and\n * {@link listAgentFilesWithOurProvenance}. Both are the question the command this row sends the\n * reader to asks before it removes anything, so what is named here is what `uninstall` takes.\n */\nexport async function listInstalledArtifacts(projectDir: string): Promise<InstalledArtifacts> {\n const [skills, agents] = await Promise.all([\n listAcrossScopes(installedDirs(projectDir, \"skillsDir\"), listSkillDirsWithOurProvenance),\n listAcrossScopes(installedDirs(projectDir, \"agentsDir\"), listAgentFilesWithOurProvenance),\n ]);\n return { skills, agents };\n}\n\n/**\n * The compiled agent files in one tree that this CLI can prove it wrote.\n *\n * The agent axis's counterpart to {@link listSkillDirsWithOurProvenance}, and deliberately\n * `splitAgentsByProvenance` rather than a second reading of the same marker: `uninstall` decides\n * what to remove with no configuration by asking that function, so a listing built any other way\n * could offer a file it then refused. It did — every `*.md` in the directory was named here while\n * the remover took only the marked ones, so a hand-authored agent was offered by one screen and\n * declined by the next.\n *\n * A file that cannot be read carries no marker and is not listed, which is that function's own\n * rule: \"cannot prove it is ours\" and \"is not ours\" call for the same answer. Nothing goes\n * unmentioned either way — {@link validateInstalledAgents} walks every agent file whatever state\n * the config is in.\n */\nasync function listAgentFilesWithOurProvenance(agentsDir: string): Promise<string[]> {\n const { marked } = await splitAgentsByProvenance(agentsDir);\n return marked.map((name) => `${name}${AGENT_FILE_EXTENSION}`);\n}\n\n/**\n * The skill directories in one tree that this CLI can prove it wrote.\n *\n * With no configuration left to name an id, the provenance marker is the only claim a directory\n * can carry — and it is the claim `uninstall` reads before removing anything, so every directory\n * listed here is one that command would actually remove. Listing a directory it would refuse is\n * the CLI recommending what it then declines to do.\n *\n * The marker lives INSIDE `metadata.yaml`, so a directory whose metadata is missing or unreadable\n * can carry no marker and is not listed. That is deliberate rather than a gap: \"cannot prove it is\n * ours\" and \"is not ours\" call for the same answer — leave it alone — which is the rule\n * `splitAgentsByProvenance` already applies to compiled agents. Nothing goes unmentioned either\n * way: {@link validateInstalledSkills} runs whatever state the config is in, and names every\n * directory it stepped over.\n */\nasync function listSkillDirsWithOurProvenance(skillsDir: string): Promise<string[]> {\n const names = await listDirectories(skillsDir);\n const judged = await Promise.all(\n names.map(async (name) => ({ name, ours: await carriesOurProvenance(skillsDir, name) })),\n );\n return judged.filter((entry) => entry.ours).map((entry) => entry.name);\n}\n\nasync function listAcrossScopes(\n dirs: string[],\n listEntries: (dir: string) => Promise<string[]>,\n): Promise<string[]> {\n const perDir = await Promise.all(dirs.map((dir) => listDisplayPaths(dir, listEntries)));\n return perDir.flat();\n}\n\n/** One directory's entries as display paths, or nothing when the directory is absent. */\nasync function listDisplayPaths(\n dir: string,\n listEntries: (dir: string) => Promise<string[]>,\n): Promise<string[]> {\n if (!(await directoryExists(dir))) return [];\n const entries = await listEntries(dir);\n return entries.map((entry) => displayDir(path.join(dir, entry)));\n}\n\nasync function validateSkillsDirectory(\n skillsDir: string,\n configuredIds: ReadonlySet<string>,\n): Promise<ContentValidation> {\n if (!(await directoryExists(skillsDir))) return NOTHING_VALIDATED;\n\n const skillDirs = await listDirectories(skillsDir);\n if (skillDirs.length === 0) return NOTHING_VALIDATED;\n\n const judged = await Promise.all(\n skillDirs.map(async (name) => ({\n name,\n ours: await isOurSkillDirectory(skillsDir, name, configuredIds),\n })),\n );\n const [ours, foreign] = partition(judged, (entry) => entry.ours);\n\n const results = await Promise.all(\n ours.map(async ({ name }) => {\n const skillDir = path.join(skillsDir, name);\n return toIssues(displayDir(skillDir), await validateInstalledSkill(skillDir));\n }),\n );\n\n return {\n count: ours.length,\n issues: results.flat(),\n notes: foreign.map(({ name }) => foreignSkillNote(skillsDir, name)),\n };\n}\n\n/** Either claim this installation has on a skill directory — see {@link validateInstalledSkills}. */\nasync function isOurSkillDirectory(\n skillsDir: string,\n name: string,\n configuredIds: ReadonlySet<string>,\n): Promise<boolean> {\n if (configuredIds.has(name)) return true;\n return carriesOurProvenance(skillsDir, name);\n}\n\n/**\n * The claim a skill directory carries on its own, independent of any configuration: the\n * `forkedFrom` block the copier stamps into every directory this CLI writes. One definition,\n * because the union above and the no-config listing are the same judgement with and without its\n * other half — and `uninstall` decides what to remove by asking exactly this.\n */\nasync function carriesOurProvenance(skillsDir: string, name: string): Promise<boolean> {\n return (await readForkedFromMetadata(path.join(skillsDir, name))) !== null;\n}\n\n/**\n * A directory this pass declined to judge, named so the count and the directory listing do not\n * silently disagree. Not a warning: nothing here is wrong, and a reader sent to fix a skill they\n * did not install is worse off than one told plainly that it is not this CLI's to police.\n */\nfunction foreignSkillNote(skillsDir: string, name: string): string {\n return `${displayDir(path.join(skillsDir, name))} — not installed by this CLI and named by no configuration here: not validated`;\n}\n\nasync function validateAgentsDirectory(agentsDir: string): Promise<ContentValidation> {\n if (!(await directoryExists(agentsDir))) return NOTHING_VALIDATED;\n\n const agentFiles = await listAgentMdFiles(agentsDir);\n if (agentFiles.length === 0) return NOTHING_VALIDATED;\n\n const results = await Promise.all(\n agentFiles.map(async (fileName) => {\n const agentPath = path.join(agentsDir, fileName);\n return toIssues(displayDir(agentPath), await validateAgentFrontmatter(agentPath));\n }),\n );\n\n return { count: agentFiles.length, issues: results.flat(), notes: [] };\n}\n\nasync function validateInstalledSkill(skillDir: string): Promise<ValidationResult> {\n const skillMdPath = path.join(skillDir, STANDARD_FILES.SKILL_MD);\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(skillMdPath))) {\n errors.push(`Missing ${STANDARD_FILES.SKILL_MD}`);\n } else {\n const frontmatterResult = await validateSkillFrontmatter(skillMdPath);\n errors.push(...frontmatterResult.errors);\n warnings.push(...frontmatterResult.warnings);\n }\n\n if (!(await fileExists(metadataPath))) {\n errors.push(`Missing ${STANDARD_FILES.METADATA_YAML}`);\n } else {\n const metadataResult = await validateInstalledSkillMetadata(metadataPath);\n errors.push(...metadataResult.errors);\n warnings.push(...metadataResult.warnings);\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\nasync function validateInstalledSkillMetadata(metadataPath: string): Promise<ValidationResult> {\n // Same judgment `compile` refuses on and local-skill discovery skips on: a file\n // that describes no skill is reported here as the error it is. The strict\n // published-skill checks below are layered on top of that verdict, never against\n // it — doctor reports what the other two passes refuse, and then some.\n const read = await readSkillMetadata(metadataPath);\n if (!read.usable) {\n return {\n valid: false,\n errors: [`${STANDARD_FILES.METADATA_YAML}: ${read.reason}`],\n warnings: [],\n };\n }\n\n const metadata = read.metadata;\n const result = validateSkillMetadata(metadata);\n if (result.success) {\n return { valid: true, errors: [], warnings: [] };\n }\n\n // Over-length cliDescription is advisory — only hard schema violations invalidate the skill\n const { errors, warnings } = splitMetadataValidationIssues(result.error, metadata);\n return {\n valid: errors.length === 0,\n errors: errors.map((e) => `${STANDARD_FILES.METADATA_YAML}: ${e}`),\n warnings: warnings.map((w) => `${STANDARD_FILES.METADATA_YAML}: ${w}`),\n };\n}\n"],"mappings":"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","names":["os","path","path","path","matrix","os","path"]}
1
+ {"version":3,"sources":["../../src/cli/commands/doctor.ts","../../src/cli/lib/source-validator.ts","../../src/cli/lib/content-validator.ts"],"sourcesContent":["import os from \"os\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\nimport {\n effectivelyExcludedSkillIds,\n loadProjectConfigFromDir,\n validateProjectConfig,\n SOURCE_ENV_VAR,\n type ResolvedConfig,\n} from \"../lib/configuration\";\nimport { loadSource, detectProject, type DetectedProject } from \"../lib/operations\";\nimport { matrix } from \"../lib/matrix/matrix-provider\";\nimport { discoverLocalSkills } from \"../lib/skills\";\nimport { getStackSkillIds } from \"../lib/stacks\";\nimport { filterExcludedEntries, listAgentMdFiles } from \"../lib/agents\";\nimport { getVerifiedPluginInstallPaths, parseMarketplacePluginRef } from \"../lib/plugins\";\nimport {\n declaresNoContent,\n isHomeDirectory,\n installBaseDir,\n resolveInstallPaths,\n} from \"../lib/installation\";\nimport { getProjectConfigPath } from \"../lib/configuration\";\nimport { isSourceRepo } from \"../lib/source-validator\";\nimport {\n listInstalledArtifacts,\n validateInstalledAgents,\n validateInstalledPlugins,\n validateInstalledSkills,\n validateProjectConfigFile,\n validateRegisteredSources,\n type ContentIssue,\n type ContentValidation,\n} from \"../lib/content-validator\";\nimport type { SourceLoadResult } from \"../lib/loading\";\nimport type { MergedSkillsMatrix, ProjectConfig, SkillConfig } from \"../types\";\nimport { fileExists, directoryExists } from \"../utils/fs\";\nimport {\n CLAUDE_SRC_DIR,\n CLI_INVOKE_COMMAND,\n DEFAULT_BRANDING,\n EJECT_SOURCE,\n LOCAL_SKILLS_PATH,\n STANDARD_FILES,\n UI_SYMBOLS,\n} from \"../consts\";\nimport { countBy, unique } from \"remeda\";\n\ntype CheckKind =\n | \"config\"\n | \"config-empty\"\n | \"skills\"\n | \"agents\"\n | \"orphans\"\n | \"orphans-unowned\"\n | \"installed\"\n | \"plugins\"\n | \"source\"\n | \"content-config\"\n | \"content-sources\"\n | \"content-plugins\"\n | \"content-skills\"\n | \"content-agents\";\n\ntype CheckResult = {\n kind: CheckKind;\n status: \"pass\" | \"fail\" | \"warn\" | \"skip\";\n message: string;\n details?: string[];\n};\n\ntype ConfigCheckOutput = {\n result: CheckResult;\n config: ProjectConfig | null;\n};\n\n/**\n * Which state the config these rows describe is in. `detectInstallation` answers \"is there an\n * installation here\", not \"is there a config here\", and hands back the same `null` for an absent\n * file and for one that loads while declaring neither skills nor agents — two states that need\n * different sentences. The state missing from this union is the one that cannot reach this layer:\n * a config that cannot be READ is the content layer's finding, and it skips the operational layer.\n */\ntype ConfigState =\n | { kind: \"absent\" }\n | { kind: \"declares-nothing\"; config: ProjectConfig }\n | { kind: \"loaded\"; config: ProjectConfig };\n\n/** Project-relative path to the config file, shown in doctor messages. */\nconst CONFIG_TS_REL = `${CLAUDE_SRC_DIR}/${STANDARD_FILES.CONFIG_TS}`;\n\n/**\n * The config in THIS directory, and what state it is in. Only this directory: the global fallback\n * is `detectInstallation`'s to make and it has already made it, so a project with no config of its\n * own is absent here whatever the home directory holds — `init` writes exactly the declares-nothing\n * shape as the blank global pair on every project setup, and it is not this project's config.\n *\n * The load cannot throw: `configDirsInPlay` is the same set the content layer just read, and any\n * failure in it skipped this layer entirely.\n */\nasync function resolveConfigState(\n detected: DetectedProject | null,\n projectDir: string,\n): Promise<ConfigState> {\n if (detected?.config) return { kind: \"loaded\", config: detected.config };\n\n const loaded = await loadProjectConfigFromDir(projectDir);\n if (!loaded) return { kind: \"absent\" };\n\n return declaresNoContent(loaded.config)\n ? { kind: \"declares-nothing\", config: loaded.config }\n : { kind: \"loaded\", config: loaded.config };\n}\n\nfunction checkConfigValid(state: ConfigState): ConfigCheckOutput {\n if (state.kind === \"absent\") {\n return {\n result: {\n kind: \"config\",\n status: \"fail\",\n message: `${CONFIG_TS_REL} not found`,\n details: [`Run '${CLI_INVOKE_COMMAND} init' to create a configuration`],\n },\n config: null,\n };\n }\n\n // Not a fault and nothing to repair — the file is valid, it just has nothing in it. The config\n // is still handed on: the rows below describe an empty install truthfully, where a `null` would\n // have them all report `Skipped (config invalid)` about a config that is valid.\n if (state.kind === \"declares-nothing\") {\n return {\n result: {\n kind: \"config-empty\",\n status: \"warn\",\n message: `${CONFIG_TS_REL} is valid but declares no skills and no agents`,\n },\n config: state.config,\n };\n }\n\n const { config } = state;\n const validation = validateProjectConfig(config);\n\n if (!validation.valid) {\n return {\n result: {\n kind: \"config\",\n status: \"fail\",\n message: `${CONFIG_TS_REL} has errors`,\n details: validation.errors,\n },\n config: null,\n };\n }\n\n if (validation.warnings.length > 0) {\n return {\n result: {\n kind: \"config\",\n status: \"warn\",\n message: `${CONFIG_TS_REL} has warnings`,\n details: validation.warnings,\n },\n config,\n };\n }\n\n return {\n result: {\n kind: \"config\",\n status: \"pass\",\n message: `${CONFIG_TS_REL} is valid`,\n },\n config,\n };\n}\n\nasync function checkSkillsResolved(\n config: ProjectConfig,\n matrix: MergedSkillsMatrix,\n projectDir: string,\n): Promise<CheckResult> {\n // config.ts declares skills both directly and through the stack. A global-only\n // install has a populated skills array and no stack at all, so keying this check\n // off the stack alone would report \"No skills configured\" for a real install.\n const excludedIds = effectivelyExcludedSkillIds(config.skills);\n const stackIds = config.stack ? getStackSkillIds(config.stack) : [];\n const uniqueSkills = unique([...stackIds, ...config.skills.map((s) => s.id)]).filter(\n (id) => !excludedIds.has(id),\n );\n\n if (uniqueSkills.length === 0) {\n return {\n kind: \"skills\",\n status: \"pass\",\n message: \"No skills configured\",\n };\n }\n\n const [localResult, globalResult] = await Promise.all([\n discoverLocalSkills(projectDir),\n !isHomeDirectory(projectDir) ? discoverLocalSkills(os.homedir()) : null,\n ]);\n const localSkillIds = new Set([\n ...(localResult?.skills.map((s) => s.id) ?? []),\n ...(globalResult?.skills.map((s) => s.id) ?? []),\n ]);\n\n const missingSkills = uniqueSkills.filter(\n (skillId) => !(skillId in matrix.skills) && !localSkillIds.has(skillId),\n );\n\n if (missingSkills.length > 0) {\n return {\n kind: \"skills\",\n status: \"fail\",\n message: `${uniqueSkills.length - missingSkills.length}/${uniqueSkills.length} skills found`,\n details: missingSkills.map((s) => `- ${s} (not found)`),\n };\n }\n\n return {\n kind: \"skills\",\n status: \"pass\",\n message: `${uniqueSkills.length}/${uniqueSkills.length} skills found`,\n };\n}\n\nasync function checkAgentsCompiled(\n config: ProjectConfig,\n projectDir: string,\n): Promise<CheckResult> {\n const agents = config.agents;\n\n if (agents.length === 0) {\n return {\n kind: \"agents\",\n status: \"pass\",\n message: \"No agents configured\",\n };\n }\n\n const projectAgentsDir = resolveInstallPaths(projectDir, \"project\").agentsDir;\n const globalAgentsDir = resolveInstallPaths(projectDir, \"global\").agentsDir;\n const agentChecks = await Promise.all(\n agents.map(async (agent) => {\n // Check scope-appropriate directory for the agent\n const agentsDir = agent.scope === \"global\" ? globalAgentsDir : projectAgentsDir;\n const agentPath = path.join(agentsDir, `${agent.name}.md`);\n return { name: agent.name, compiled: await fileExists(agentPath) };\n }),\n );\n const missingAgents = agentChecks.filter((c) => !c.compiled).map((c) => c.name);\n\n if (missingAgents.length > 0) {\n return {\n kind: \"agents\",\n status: \"warn\",\n message: `${missingAgents.length} agent${missingAgents.length === 1 ? \"\" : \"s\"} need${missingAgents.length === 1 ? \"s\" : \"\"} recompilation`,\n details: missingAgents.map((a) => `- ${a} (missing)`),\n };\n }\n\n return {\n kind: \"agents\",\n status: \"pass\",\n message: `${agents.length}/${agents.length} agents compiled`,\n };\n}\n\nasync function checkNoOrphans(config: ProjectConfig, projectDir: string): Promise<CheckResult> {\n const projectAgentsDir = resolveInstallPaths(projectDir, \"project\").agentsDir;\n const globalAgentsDir = resolveInstallPaths(projectDir, \"global\").agentsDir;\n\n // At home scope both scopes resolve to the same agents directory, so it is\n // listed once and its files are matched against both scopes' known names.\n const scopesShareAgentsDir = isHomeDirectory(projectDir);\n\n const [projectExists, globalExists] = await Promise.all([\n directoryExists(projectAgentsDir),\n !scopesShareAgentsDir ? directoryExists(globalAgentsDir) : false,\n ]);\n\n if (!projectExists && !globalExists) {\n return {\n kind: \"orphans\",\n status: \"pass\",\n message: \"No agents directory\",\n };\n }\n\n const projectMdFiles = projectExists ? await listAgentMdFiles(projectAgentsDir) : [];\n const globalMdFiles = globalExists ? await listAgentMdFiles(globalAgentsDir) : [];\n\n // Project files: only active project-scoped agents should have .md files here\n const activeProjectAgents: Set<string> = new Set(\n config.agents.filter((a) => a.scope === \"project\" && !a.excluded).map((a) => a.name),\n );\n // Global files: all global-scoped agents (including excluded) still serve other projects\n const knownGlobalAgents: Set<string> = new Set(\n config.agents.filter((a) => a.scope === \"global\").map((a) => a.name),\n );\n\n const knownProjectDirAgents = scopesShareAgentsDir\n ? new Set([...activeProjectAgents, ...knownGlobalAgents])\n : activeProjectAgents;\n\n const orphanedFiles = [\n ...orphanedAgentNames(projectMdFiles, knownProjectDirAgents),\n ...orphanedAgentNames(globalMdFiles, knownGlobalAgents),\n ];\n\n if (orphanedFiles.length > 0) {\n return {\n kind: \"orphans\",\n status: \"warn\",\n message: plural(orphanedFiles.length, \"orphaned agent file\"),\n details: orphanedFiles.map((f) => `- ${f}.md (not in config)`),\n };\n }\n\n return {\n kind: \"orphans\",\n status: \"pass\",\n message: \"No orphaned agent files\",\n };\n}\n\n/**\n * The agents whose compiled `.md` sits in a directory whose roster does not name them. The\n * roster differs per directory — a project directory knows only its own active agents, the\n * global one knows every global-scoped agent including the excluded — so it is a parameter.\n */\nfunction orphanedAgentNames(mdFiles: string[], knownAgents: ReadonlySet<string>): string[] {\n return mdFiles\n .map((fileName) => fileName.replace(/\\.md$/, \"\"))\n .filter((agentName) => !knownAgents.has(agentName));\n}\n\n/**\n * The same row when there is no configuration at all. Ownership is not unknown here, it is\n * settled: nothing declares any of it, so every artefact this CLI can prove it wrote is an\n * orphan and the row names it. What it CANNOT prove it wrote is left out — a skill directory\n * with no `forkedFrom` and an agent file with no provenance marker are somebody's own work,\n * and naming them here would offer `uninstall` files that command declines. See\n * {@link listInstalledArtifacts}, which asks exactly that question on both axes.\n *\n * A `fail`, where a stray file beside a config is a warning: that warning is earned by the next\n * `compile` pruning what it names, and nothing prunes these unattended. `compile` and `edit`\n * refuse without a config; `uninstall` does not need one, identifying skill directories by\n * their own `forkedFrom` and compiled agents by the marker each carries, which is why the tip\n * beneath this row can promise both halves.\n *\n * With nothing installed the row keeps the skip it has always printed. An empty directory with\n * no config is the state `init` exists for — there is nothing for a configuration to have owned.\n */\nasync function checkUnownedInstallation(projectDir: string): Promise<CheckResult> {\n const { skills, agents } = await listInstalledArtifacts(projectDir);\n if (skills.length === 0 && agents.length === 0) return skippedResult(\"orphans\");\n\n return {\n kind: \"orphans-unowned\",\n status: \"fail\",\n // The per-line \"(not in config)\" the other verdict repeats is said once here instead:\n // with no configuration it is true of every line, and there are as many lines as files.\n message: `${countedArtifacts(skills, agents)} installed here, and no configuration declares them`,\n details: [...skills, ...agents].map((artifact) => `- ${artifact}`),\n };\n}\n\n/** \"7 skills and 2 agents\", dropping a half with nothing in it rather than saying \"0 agents\". */\nfunction countedArtifacts(skills: string[], agents: string[]): string {\n return [\n ...(skills.length > 0 ? [plural(skills.length, \"skill\")] : []),\n ...(agents.length > 0 ? [plural(agents.length, \"agent\")] : []),\n ].join(\" and \");\n}\n\nasync function checkSkillsInstalled(\n config: ProjectConfig,\n projectDir: string,\n): Promise<CheckResult> {\n const skills: SkillConfig[] = config.skills;\n const ejectSkills = skills.filter((s) => s.origin === EJECT_SOURCE);\n\n if (ejectSkills.length === 0) {\n return {\n kind: \"installed\",\n status: \"pass\",\n message: \"No eject-mode skills configured\",\n };\n }\n\n const skillChecks = await Promise.all(\n ejectSkills.map(async (skill) => {\n const baseDir = installBaseDir(projectDir, skill.scope);\n const skillMdPath = path.join(baseDir, LOCAL_SKILLS_PATH, skill.id, STANDARD_FILES.SKILL_MD);\n return { id: skill.id, installed: await fileExists(skillMdPath) };\n }),\n );\n const missingSkills = skillChecks.filter((c) => !c.installed).map((c) => c.id);\n\n if (missingSkills.length > 0) {\n return {\n kind: \"installed\",\n status: \"warn\",\n message: `${plural(missingSkills.length, \"skill\")} missing from disk`,\n details: missingSkills.map((s) => `- ${s} (not found in ${LOCAL_SKILLS_PATH}/)`),\n };\n }\n\n return {\n kind: \"installed\",\n status: \"pass\",\n message: `${ejectSkills.length}/${ejectSkills.length} eject-mode skills installed`,\n };\n}\n\n/**\n * Plugin-mode skills have no files under `.claude/skills/` — they live in the\n * Claude plugin registry. Verifying them means asking the registry for the scope\n * each skill was installed at, not looking on disk.\n */\nasync function checkPluginSkillsInstalled(\n config: ProjectConfig,\n projectDir: string,\n): Promise<CheckResult> {\n const pluginSkills: SkillConfig[] = config.skills.filter((s) => s.origin !== EJECT_SOURCE);\n\n if (pluginSkills.length === 0) {\n return {\n kind: \"plugins\",\n status: \"pass\",\n message: \"No plugin-mode skills configured\",\n };\n }\n\n const baseDirs = unique(pluginSkills.map((s) => installBaseDir(projectDir, s.scope)));\n const missingPerBaseDir = await Promise.all(\n baseDirs.map(async (baseDir) => {\n const installedIds = new Set(\n (await getVerifiedPluginInstallPaths(baseDir)).map((plugin) =>\n parseMarketplacePluginRef(plugin.pluginKey),\n ),\n );\n return pluginSkills\n .filter((skill) => installBaseDir(projectDir, skill.scope) === baseDir)\n .filter((skill) => !installedIds.has(skill.id))\n .map((skill) => skill.id);\n }),\n );\n const missingSkills = missingPerBaseDir.flat();\n\n if (missingSkills.length > 0) {\n return {\n kind: \"plugins\",\n status: \"warn\",\n message: `${plural(missingSkills.length, \"skill\")} not installed as plugins`,\n details: missingSkills.map((s) => `- ${s} (no enabled plugin found)`),\n };\n }\n\n return {\n kind: \"plugins\",\n status: \"pass\",\n message: `${pluginSkills.length}/${pluginSkills.length} plugin-mode skills installed`,\n };\n}\n\n/**\n * How a marketplace came to be the one this run reads, in the words each rung earns.\n *\n * The `default` sentence is the one that had to exist. With no configuration anywhere the resolver\n * falls back to the public catalogue and this check FETCHES it, so the report a bare directory gets\n * describes a network round trip to a marketplace nobody named — which is the row doing its job,\n * since reachability is its whole subject, and it was doing it without saying so. The other four\n * rungs are here because the map is exhaustive against the union rather than a default with\n * exceptions; `doctor` takes no marketplace flag and reads no environment variable, so it reaches\n * the first two through nothing today.\n */\nconst MARKETPLACE_CHOSEN_BY = {\n flag: \"named by this run\",\n env: `named by ${SOURCE_ENV_VAR}`,\n project: \"named by this project's configuration\",\n global: \"named by the global configuration\",\n default: \"nothing here names one, so this is the default\",\n} as const satisfies Record<ResolvedConfig[\"sourceOrigin\"], string>;\n\n/** How this run got hold of that marketplace — off disk, or over the wire. */\nfunction howItWasReached(source: string, isLocal: boolean): string {\n return isLocal ? `Read ${source} from disk` : `Fetched ${source} over the network`;\n}\n\n/**\n * The row for a marketplace this run did reach.\n *\n * `message` names where the skills were read FROM, which for a remote marketplace is the cache\n * directory it was unpacked into; the provenance line beneath it names the marketplace itself.\n * Both, because neither answers the other's question: a cache path says nothing about whose\n * catalogue it holds, and a ref says nothing about what is on disk to inspect.\n */\nfunction reachedMarketplace(result: SourceLoadResult): CheckResult {\n const { source, sourceOrigin } = result.sourceConfig;\n const skillCount = Object.keys(matrix.skills).length;\n const sourceLabel = result.isLocal ? \"local\" : \"remote\";\n\n return {\n kind: \"source\",\n status: \"pass\",\n message: `Connected to ${sourceLabel}: ${result.sourcePath}`,\n details: [\n `${plural(skillCount, \"skill\")} available`,\n `${howItWasReached(source, result.isLocal)} — ${MARKETPLACE_CHOSEN_BY[sourceOrigin]}`,\n ],\n };\n}\n\nasync function checkSourceReachable(projectDir: string): Promise<CheckResult> {\n try {\n const { sourceResult } = await loadSource({ projectDir });\n return reachedMarketplace(sourceResult);\n } catch (error) {\n const message = getErrorMessage(error);\n return {\n kind: \"source\",\n status: \"fail\",\n message: \"Failed to load marketplace\",\n details: [message],\n };\n }\n}\n\ntype ContentCheck = {\n kind: CheckKind;\n name: string;\n noun: string;\n run: (projectDir: string) => Promise<ContentValidation>;\n};\n\n/**\n * A content check plus the two gates it owns: whether it reads config.ts to know WHAT to validate\n * (see {@link CONFIG_CHECK}), and which operational rows its errors stand down.\n *\n * `blocks` names only the rows that READ what this pass validates, so their own verdict would be\n * this pass's finding in the row's words. A row absent from every `blocks` list reads none of the\n * content on disk and answers as truthfully as ever — an error here is not its business.\n */\ntype GatedContentCheck = ContentCheck & {\n readsConfig: boolean;\n blocks: readonly CheckKind[];\n};\n\n/**\n * The config file every other check is read against, so it is validated before any of them and\n * on its own: a file that exists and cannot be parsed is a finding about that file, and every\n * row underneath would be a cascade of it. It carries no gate of its own — it IS the gate.\n */\nconst CONFIG_CHECK: ContentCheck = {\n kind: \"content-config\",\n name: \"Config\",\n noun: \"config\",\n run: validateProjectConfigFile,\n};\n\n/**\n * The content layer: schema and file-level validation of what is on disk. It runs before the\n * operational layer so that a row whose inputs this layer has already reported broken can stand\n * down rather than re-report the same fault as a finding of its own.\n */\nconst CONTENT_CHECKS: GatedContentCheck[] = [\n {\n kind: \"content-sources\",\n name: \"Marketplaces\",\n noun: \"marketplace\",\n // The registered marketplaces are the ones config.ts names.\n readsConfig: true,\n // A marketplace whose content is broken is missing skills from the matrix every configured\n // id is resolved against, so the skills row would call ids \"not found\" that this row has\n // already accounted for.\n blocks: [\"skills\"],\n run: validateRegisteredSources,\n },\n {\n kind: \"content-plugins\",\n name: \"Plugins\",\n noun: \"plugin\",\n readsConfig: false,\n // `resolvePluginInstallPaths` swallows a registry it cannot parse and returns none, so every\n // plugin-mode skill would read \"no enabled plugin found\" — the registry's finding, once per\n // configured skill, wearing the row's words.\n blocks: [\"plugins\"],\n run: validateInstalledPlugins,\n },\n {\n kind: \"content-skills\",\n name: \"Skills\",\n noun: \"skill\",\n // `~/.claude/skills/` is shared with everything else that installs a skill there, so which of\n // its directories are this installation's is a question only the config can answer for the\n // ones carrying no provenance marker. A config nobody can read leaves that unanswerable.\n readsConfig: true,\n // `extractLocalSkill` DROPS a skill whose metadata.yaml is missing or unusable, so a \"not\n // found\" from the skills row would be this finding re-worded.\n blocks: [\"skills\"],\n run: validateInstalledSkills,\n },\n {\n kind: \"content-agents\",\n name: \"Agents\",\n noun: \"agent\",\n readsConfig: false,\n // Nothing downstream opens an agent .md. `Agents Compiled` asks whether the file is there and\n // `No Orphans` reads the names of the files that are — broken frontmatter changes neither.\n blocks: [],\n run: validateInstalledAgents,\n },\n];\n\nfunction contentStatus(errors: number, warnings: number): CheckResult[\"status\"] {\n if (errors > 0) return \"fail\";\n if (warnings > 0) return \"warn\";\n return \"pass\";\n}\n\nfunction contentMessage(noun: string, count: number, errors: number, warnings: number): string {\n // A pass that walked nothing can still report an issue — an unreadable plugin\n // registry is a finding about the directory, not about a plugin inside it.\n if (errors === 0 && warnings === 0) {\n return count === 0 ? `No ${noun}s to validate` : `${plural(count, noun)} validated`;\n }\n return `${plural(count, noun)}: ${plural(errors, \"error\")}, ${plural(warnings, \"warning\")}`;\n}\n\nfunction formatContentIssue(issue: ContentIssue): string {\n const marker = issue.severity === \"error\" ? \"ERROR\" : \"WARN\";\n return `- [${marker}] ${issue.file}: ${issue.message}`;\n}\n\nfunction toContentResult(check: ContentCheck, validation: ContentValidation): CheckResult {\n const errors = validation.issues.filter((issue) => issue.severity === \"error\").length;\n const warnings = validation.issues.length - errors;\n\n return {\n kind: check.kind,\n status: contentStatus(errors, warnings),\n message: contentMessage(check.noun, validation.count, errors, warnings),\n details: [\n ...validation.notes.map((note) => `- ${note}`),\n ...validation.issues.map(formatContentIssue),\n ],\n };\n}\n\n/**\n * The column every row's status symbol starts at. It has to clear the longest row name\n * the report prints — \"Marketplace Reachable\", 21 characters — or that row's name runs\n * straight into its own tick with no gap.\n */\nconst CHECK_WIDTH = 24;\n\n/** Section headings and the rows underneath them are indented one step apart. */\nconst SECTION_INDENT = \" \";\nconst ROW_INDENT = \" \";\n\nconst SECTION_CONTENT = \"Content checks\";\nconst SECTION_OPERATIONAL = \"Operational checks\";\nconst SKIP_NO_INSTALLATION = \"Skipped — no installation here (marketplace repository)\";\nconst SKIP_CONFIG_UNREADABLE = \"Skipped — the configuration that names them cannot be read\";\n\n/**\n * The whole operational layer standing down, for the one content finding that leaves every row\n * with nothing to say: a config nobody can read. It still says \"errors\" rather than naming that\n * file, because the config row is one of them and whatever else failed is above it too.\n */\nconst SKIP_AFTER_CONFIG_ERROR = \"Skipped — fix the content errors above first\";\n\n/**\n * The sentence a single row stands down with. Unlike its neighbours it names the finding rather\n * than the layer: which pass blocked it is the one thing separating a row that cannot answer from\n * the ones printing verdicts beside it.\n */\nfunction skipRestatingContent(nouns: string[]): string {\n return `Skipped — this row would only restate the ${nouns.join(\" and \")} errors above`;\n}\n\nfunction plural(count: number, word: string): string {\n return `${count} ${word}${count === 1 ? \"\" : \"s\"}`;\n}\n\nfunction formatCheckName(name: string): string {\n return name.padEnd(CHECK_WIDTH);\n}\n\nfunction formatStatus(status: CheckResult[\"status\"]): string {\n switch (status) {\n case \"pass\":\n return UI_SYMBOLS.CHECK;\n case \"fail\":\n return UI_SYMBOLS.CROSS;\n case \"warn\":\n return \"!\";\n case \"skip\":\n return \"-\";\n default: {\n const _exhaustive: never = status;\n return _exhaustive;\n }\n }\n}\n\nfunction formatCheckLine(name: string, result: CheckResult): string[] {\n const headerLine = `${ROW_INDENT}${formatCheckName(name)}${formatStatus(result.status)} ${result.message}`;\n const detailLines = (result.details ?? []).map(\n (detail) => `${ROW_INDENT}${\" \".repeat(CHECK_WIDTH)} ${detail}`,\n );\n return [headerLine, ...detailLines];\n}\n\nfunction formatSummary(results: CheckResult[]): string {\n const counts = countBy(results, (r) => r.status);\n\n const parts = [\n `${counts.pass ?? 0} passed`,\n plural(counts.warn ?? 0, \"warning\"),\n plural(counts.fail ?? 0, \"error\"),\n ];\n\n return `${SECTION_INDENT}Summary: ${parts.join(\", \")}`;\n}\n\nconst TIPS: Array<{ kind: CheckKind; status: CheckResult[\"status\"]; tip: string }> = [\n {\n kind: \"agents\",\n status: \"warn\",\n tip: ` Tip: Run '${CLI_INVOKE_COMMAND} compile' to generate missing agent files`,\n },\n {\n kind: \"config\",\n status: \"fail\",\n tip: ` Tip: Run '${CLI_INVOKE_COMMAND} init' to create or fix configuration`,\n },\n {\n // The remedy for a valid config with nothing in it. Not the tip above: there is nothing to\n // create and nothing to fix. `init` on this config opens the wizard rather than the dashboard\n // — that is what the detection returning null is FOR — so it is the way to fill it in.\n kind: \"config-empty\",\n status: \"warn\",\n tip: ` Tip: Nothing is configured yet — run '${CLI_INVOKE_COMMAND} init' to choose skills and sub-agents`,\n },\n {\n // The one remedy that applies to a config that cannot be read. `init` does not clear such a\n // file — it refuses it — so the tip above would send the reader in a circle; this is the same\n // way out `edit` and `init` themselves name, worded the same way.\n kind: \"content-config\",\n status: \"fail\",\n tip: ` Tip: There is no automatic repair — recreate the configuration: '${CLI_INVOKE_COMMAND} uninstall' still works on a config it cannot read, then '${CLI_INVOKE_COMMAND} init'`,\n },\n {\n // Printed beside the config tip above, which says how to get a configuration back and\n // nothing about the files that outlived the old one. Both halves are named with what they\n // actually do: `uninstall` matches skill directories by their own `forked-from` metadata and\n // compiled agents by the marker each one carries, so neither needs the configuration that is\n // gone — which is why the row can name both and this tip can promise both.\n kind: \"orphans-unowned\",\n status: \"fail\",\n tip: ` Tip: Nothing declares the files above — '${CLI_INVOKE_COMMAND} init' writes a configuration that can own them again, or '${CLI_INVOKE_COMMAND} uninstall' removes them, the compiled agents included: each file listed carries this CLI's own provenance, which is what that command reads when there is no configuration left`,\n },\n {\n kind: \"skills\",\n status: \"fail\",\n tip: \" Tip: Check skill IDs in config match available skills\",\n },\n {\n kind: \"installed\",\n status: \"warn\",\n // No command is named on purpose: 'eject skills --force' re-copies every skill in the\n // marketplace and always targets project scope, so it cannot repair a global-scoped\n // skill and it litters a plugin-mode project with local skill directories.\n tip: \" Tip: Re-eject the missing skills from the marketplace to restore their files\",\n },\n];\n\nfunction formatTips(results: CheckResult[]): string[] {\n return TIPS.filter((t) => results.some((r) => r.kind === t.kind && r.status === t.status)).map(\n (t) => t.tip,\n );\n}\n\nfunction skippedResult(kind: CheckKind): CheckResult {\n return { kind, status: \"skip\", message: \"Skipped (config invalid)\" };\n}\n\n/**\n * The skills row when the marketplace never loaded. Distinct from {@link skippedResult}: the\n * config is fine, and what is missing is the matrix to resolve its skills against.\n */\nfunction sourceUnreachableSkillsResult(): CheckResult {\n return { kind: \"skills\", status: \"skip\", message: \"Skipped (marketplace unreachable)\" };\n}\n\nfunction skippedContentResult(kind: CheckKind): CheckResult {\n return { kind, status: \"skip\", message: SKIP_CONFIG_UNREADABLE };\n}\n\n/** The content passes that failed this run — the set every operational row is gated against. */\nfunction failedContentKinds(contentResults: CheckResult[]): ReadonlySet<CheckKind> {\n return new Set(contentResults.filter((r) => r.status === \"fail\").map((r) => r.kind));\n}\n\n/**\n * An operational row standing down because a content pass it reads through failed, naming what\n * blocked it. `null` — the answer for most rows on most runs — means nothing it reads is broken\n * and it can speak for itself.\n */\nfunction contentBlockedResult(\n row: CheckKind,\n failedContent: ReadonlySet<CheckKind>,\n): CheckResult | null {\n const blockingNouns = CONTENT_CHECKS.filter((check) => failedContent.has(check.kind))\n .filter((check) => check.blocks.includes(row))\n .map((check) => check.noun);\n\n if (blockingNouns.length === 0) return null;\n\n return { kind: row, status: \"skip\", message: skipRestatingContent(blockingNouns) };\n}\n\nfunction runContentCheck(check: ContentCheck, projectDir: string): Promise<CheckResult> {\n return safeCheck(check.kind, async () => toContentResult(check, await check.run(projectDir)));\n}\n\n/**\n * Wrap a check so a thrown exception becomes a `fail` result instead of crashing the\n * whole doctor run. Per-check isolation ensures one broken check does not mask others.\n */\nasync function safeCheck(kind: CheckKind, fn: () => Promise<CheckResult>): Promise<CheckResult> {\n try {\n return await fn();\n } catch (error) {\n return { kind, status: \"fail\", message: \"Check threw\", details: [getErrorMessage(error)] };\n }\n}\n\nexport default class Doctor extends BaseCommand {\n static summary = \"Diagnose common configuration issues\";\n\n static description = `Run diagnostic checks on your ${DEFAULT_BRANDING.NAME} configuration to identify issues with config validity, skill resolution, agent compilation, and marketplace connectivity.`;\n\n static examples = [\"<%= config.bin %> <%= command.id %>\"];\n\n static flags = {};\n\n async run(): Promise<void> {\n await this.parse(Doctor);\n const projectDir = process.cwd();\n\n // The shared `verbose()` logger stays OFF, and nothing here switches it on. `doctor` used to,\n // for the whole run — the mechanical residue of a `--verbose` flag whose removal was meant to\n // make each row's own DETAILS unconditional, which `formatCheckLine` does on its own. What the\n // logger added on top of that was the loaders' trace, spliced between the section headings and\n // the rows they head: for a directory holding nothing, 27 lines of it, every one restating a\n // row printed underneath it.\n this.printHeader(await this.resolveBrandingName(projectDir));\n const contentResults = await this.runContentChecks(projectDir);\n const operationalResults = await this.runOperationalChecks(projectDir, contentResults);\n const results = [...contentResults, ...operationalResults];\n\n this.printResults(results);\n\n if (results.some((r) => r.status === \"fail\")) {\n this.exit(EXIT_CODES.ERROR);\n }\n }\n\n private printHeader(brandingName: string): void {\n this.log(\"\");\n this.log(`${brandingName} Doctor`);\n this.log(\"\");\n this.log(`${SECTION_INDENT}Checking configuration health...`);\n this.log(\"\");\n }\n\n /**\n * The config is checked first and alone. A check that reads it to know what to validate would\n * otherwise ask a file already reported as unreadable — and asking is what emitted the loader's\n * own failure line once per read, spliced between these rows. Everything that walks installed\n * content on disk still runs: it says something true whatever the config is in.\n */\n private async runContentChecks(projectDir: string): Promise<CheckResult[]> {\n this.log(`${SECTION_INDENT}${SECTION_CONTENT}`);\n\n const configResult = await runContentCheck(CONFIG_CHECK, projectDir);\n const configUnreadable = configResult.status === \"fail\";\n\n const rows = await Promise.all(\n CONTENT_CHECKS.map(async (check) => ({\n name: check.name,\n result:\n check.readsConfig && configUnreadable\n ? skippedContentResult(check.kind)\n : await runContentCheck(check, projectDir),\n })),\n );\n\n const allRows = [{ name: CONFIG_CHECK.name, result: configResult }, ...rows];\n\n for (const row of allRows) {\n this.logCheck(row.name, row.result);\n }\n\n return allRows.map((row) => row.result);\n }\n\n /**\n * The whole layer stands down for the two findings that leave every row with nothing to say: a\n * config nobody can read — every row is read out of it, so all of them would be cascades of that\n * one file — and a marketplace repository with nothing installed, where a marketplace author has\n * no install for the layer to describe. Every other content error is scoped to the rows that\n * read what it is about; {@link GatedContentCheck} says which those are, per pass.\n */\n private async runOperationalChecks(\n projectDir: string,\n contentResults: CheckResult[],\n ): Promise<CheckResult[]> {\n this.log(\"\");\n this.log(`${SECTION_INDENT}${SECTION_OPERATIONAL}`);\n\n const failedContent = failedContentKinds(contentResults);\n if (failedContent.has(CONFIG_CHECK.kind)) {\n this.log(`${ROW_INDENT}${SKIP_AFTER_CONFIG_ERROR}`);\n return [];\n }\n\n const detected = await detectProject(projectDir);\n if (!detected && (await this.isUninstalledSourceRepo(projectDir))) {\n this.log(`${ROW_INDENT}${SKIP_NO_INSTALLATION}`);\n return [];\n }\n\n const configState = await resolveConfigState(detected, projectDir);\n return this.runAllChecks(projectDir, configState, failedContent);\n }\n\n /**\n * A config file that exists but failed to load also detects as \"no project\", and\n * that is a finding rather than an absence — so the skip requires no config file\n * at all, not merely no usable one.\n */\n private async isUninstalledSourceRepo(projectDir: string): Promise<boolean> {\n if (await fileExists(getProjectConfigPath(projectDir))) return false;\n return isSourceRepo(projectDir);\n }\n\n private async runAllChecks(\n projectDir: string,\n configState: ConfigState,\n failedContent: ReadonlySet<CheckKind>,\n ): Promise<CheckResult[]> {\n const { result: configResult, config } = checkConfigValid(configState);\n this.logCheck(\"Config Valid\", configResult);\n\n // loadSource (called by checkSourceReachable) populates the matrix. Run it\n // before checkSkillsResolved so skills lookups see a populated matrix; if\n // source fails, skip skills rather than reporting false \"not found\" errors.\n const sourceResult = await safeCheck(\"source\", () => checkSourceReachable(projectDir));\n\n const filteredConfig = config ? filterExcludedEntries(config) : null;\n\n const skillsResult = await this.resolveSkillsCheck(\n config,\n sourceResult,\n projectDir,\n failedContent,\n );\n this.logCheck(\"Skills Resolved\", skillsResult);\n\n const agentsResult = filteredConfig\n ? await safeCheck(\"agents\", () => checkAgentsCompiled(filteredConfig, projectDir))\n : skippedResult(\"agents\");\n this.logCheck(\"Agents Compiled\", agentsResult);\n\n const orphansResult = await this.resolveOrphansCheck(config, configState, projectDir);\n this.logCheck(\"No Orphans\", orphansResult);\n\n const installedResult = filteredConfig\n ? await safeCheck(\"installed\", () => checkSkillsInstalled(filteredConfig, projectDir))\n : skippedResult(\"installed\");\n this.logCheck(\"Skills Installed\", installedResult);\n\n const pluginsResult = await this.resolvePluginsCheck(filteredConfig, projectDir, failedContent);\n this.logCheck(\"Plugins Installed\", pluginsResult);\n\n this.logCheck(\"Marketplace Reachable\", sourceResult);\n\n return [\n configResult,\n skillsResult,\n agentsResult,\n orphansResult,\n installedResult,\n pluginsResult,\n sourceResult,\n ];\n }\n\n /**\n * The orphan row, and which question it can answer. With a config it names the compiled\n * agents that config does not; with no config at all every installed file is unowned and it\n * names all of them. It skips for the one state left — a config that loads and fails\n * validation — because there the file that says who owns what has already been rejected, and\n * an installation must not be called stranded on the strength of one nobody can trust.\n */\n private async resolveOrphansCheck(\n config: ProjectConfig | null,\n configState: ConfigState,\n projectDir: string,\n ): Promise<CheckResult> {\n if (config) return safeCheck(\"orphans\", () => checkNoOrphans(config, projectDir));\n if (configState.kind === \"absent\") {\n return safeCheck(\"orphans\", () => checkUnownedInstallation(projectDir));\n }\n return skippedResult(\"orphans\");\n }\n\n /**\n * The skills row, and the three states in which it cannot be computed: no config to read the\n * skills out of, content it resolves against that the layer above has already reported broken,\n * and a marketplace that never loaded — so there is no populated matrix to resolve them\n * against, and every configured skill would be reported \"not found\".\n */\n private async resolveSkillsCheck(\n config: ProjectConfig | null,\n sourceResult: CheckResult,\n projectDir: string,\n failedContent: ReadonlySet<CheckKind>,\n ): Promise<CheckResult> {\n if (!config) return skippedResult(\"skills\");\n\n const blocked = contentBlockedResult(\"skills\", failedContent);\n if (blocked) return blocked;\n if (sourceResult.status === \"fail\") return sourceUnreachableSkillsResult();\n\n return safeCheck(\"skills\", () => checkSkillsResolved(config, matrix, projectDir));\n }\n\n /**\n * The plugin row, and the two states in which it cannot be computed: no config to read the\n * plugin-mode skills out of, and a plugin registry the layer above could not parse — which\n * resolves as no installs at all, so every configured skill would be reported missing.\n */\n private async resolvePluginsCheck(\n config: ProjectConfig | null,\n projectDir: string,\n failedContent: ReadonlySet<CheckKind>,\n ): Promise<CheckResult> {\n if (!config) return skippedResult(\"plugins\");\n\n const blocked = contentBlockedResult(\"plugins\", failedContent);\n if (blocked) return blocked;\n\n return safeCheck(\"plugins\", () => checkPluginSkillsInstalled(config, projectDir));\n }\n\n private logCheck(name: string, result: CheckResult): void {\n for (const line of formatCheckLine(name, result)) {\n this.log(line);\n }\n }\n\n private printResults(results: CheckResult[]): void {\n this.log(\"\");\n this.log(formatSummary(results));\n\n const tips = formatTips(results);\n if (tips.length > 0) {\n this.log(\"\");\n for (const tip of tips) {\n this.log(tip);\n }\n }\n\n this.log(\"\");\n }\n}\n","import path from \"path\";\nimport { isRecord } from \"../utils/type-guards.js\";\nimport { parse as parseYaml } from \"yaml\";\nimport { z } from \"zod\";\nimport { glob, readFile, fileExists, directoryExists } from \"../utils/fs\";\nimport {\n DIRS,\n MARKETPLACE_JSON,\n PLUGIN_MANIFEST_DIR,\n SKILL_CATEGORIES_PATH,\n SKILL_RULES_PATH,\n SKILLS_DIR_PATH,\n STACKS_FILE_PATH,\n STANDARD_FILES,\n} from \"../consts\";\nimport {\n agentYamlGenerationSchema,\n metadataValidationSchema,\n splitMetadataValidationIssues,\n validateSkillMetadata,\n skillCategoriesFileSchema,\n skillRulesFileSchema,\n stackConfigValidationSchema,\n stacksConfigSchema,\n} from \"./schemas\";\nimport { parseFrontmatter } from \"./loading/loader\";\nimport { ConfigDefaultExportError, loadConfig, loadProjectSourceConfig } from \"./configuration\";\nimport { checkMatrixHealth, type MatrixHealthIssue } from \"./matrix\";\nimport { loadSkillsMatrixFromSource } from \"./loading/source-loader\";\nimport { MarketplaceNameRefusedError } from \"./loading/source-fetcher\";\nimport { matrix } from \"./matrix/matrix-provider\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { formatZodErrors } from \"./schema-validator\";\n\nexport type SourceValidationIssue = {\n severity: \"error\" | \"warning\";\n file: string;\n message: string;\n};\n\nexport type SourceValidationResult = {\n issues: SourceValidationIssue[];\n skillCount: number;\n errorCount: number;\n warningCount: number;\n};\n\n/**\n * Who this report is for, relative to the marketplace it is about.\n *\n * You are the `\"author\"` of the marketplace being validated when it IS the directory the command\n * ran in; a marketplace anywhere else — fetched, or on disk at another path — is one you are only\n * a `\"consumer\"` of. Not \"is there a marketplace under the cwd\": that says nothing about the OTHER\n * marketplace a config may point at, and the severity turns on the per-marketplace question.\n *\n * It changes one finding. A slug a marketplace's rules dangle is a typo its author can fix and\n * wants the run to fail on, and it is a defect a consumer cannot touch in a file they cannot open\n * — while every skill still installs and still resolves. Whether the reader holds push rights is\n * not knowable here and is not the test: a checkout under your cursor is a file you can edit.\n */\nexport type MarketplaceReader = \"author\" | \"consumer\";\n\n/**\n * True when `dir` is itself a skills source repository — it carries the skills tree\n * `validateSource` walks, at `src/skills/` or wherever its own source config points.\n * A marketplace author's checkout answers yes; a consumer project answers no.\n */\nexport async function isSourceRepo(dir: string): Promise<boolean> {\n // ABORT on an unreadable config, and it is caught rather than fatal at both callers: `doctor`\n // reaches this through `safeCheck`, so the throw becomes a failed row instead of an aborted\n // command, and its other caller asks only where no config file exists at all.\n const sourceConfig = await loadProjectSourceConfig(dir);\n return directoryExists(path.join(dir, sourceConfig?.skillsDir ?? SKILLS_DIR_PATH));\n}\n\n/** Checks if a key uses snake_case (has underscore between lowercase letters) */\nexport function isSnakeCase(key: string): boolean {\n return /[a-z]_[a-z]/.test(key);\n}\n\n/**\n * Checks top-level keys for snake_case usage (camelCase is the convention).\n * Non-object input yields no issues.\n */\nexport function checkSnakeCaseKeys(rawMetadata: unknown, relPath: string): SourceValidationIssue[] {\n if (!isRecord(rawMetadata)) return [];\n\n return Object.keys(rawMetadata)\n .filter(isSnakeCase)\n .map((key) => ({\n severity: \"error\" as const,\n file: relPath,\n message: `Key '${key}' uses snake_case — use camelCase instead`,\n }));\n}\n\n/**\n * Warns when a skill directory's name does not equal the skill's machine id\n * (SKILL.md frontmatter `name`) — the key the loader registers the skill under.\n * Warning, not error: the loader still loads the skill by its id, but the\n * directory no longer signals which skill it contains.\n */\nexport function checkDirNameMatchesSkillId(\n skillId: string,\n relPath: string,\n dirName: string,\n): SourceValidationIssue[] {\n if (skillId === dirName) return [];\n return [\n {\n severity: \"warning\",\n file: relPath,\n message: `Directory name '${dirName}' does not match skill id '${skillId}'`,\n },\n ];\n}\n\n/**\n * Reads a skill directory's SKILL.md frontmatter and checks the directory name\n * against the skill's machine id. When the id cannot be read (unreadable file or\n * missing/invalid frontmatter), reports that the check could not run.\n */\nasync function checkSkillDirName(\n skillsDir: string,\n skillsDirRelPath: string,\n skillDir: string,\n): Promise<SourceValidationIssue[]> {\n const dirName = path.basename(skillDir);\n const skillMdRelPath = path.join(skillsDirRelPath, skillDir, STANDARD_FILES.SKILL_MD);\n\n try {\n const content = await readFile(path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD));\n const frontmatter = parseFrontmatter(content, skillMdRelPath);\n\n if (frontmatter === null) {\n return [\n {\n severity: \"warning\",\n file: skillMdRelPath,\n message: `Cannot verify directory name '${dirName}': missing or invalid ${STANDARD_FILES.SKILL_MD} frontmatter`,\n },\n ];\n }\n\n return checkDirNameMatchesSkillId(frontmatter.name, skillMdRelPath, dirName);\n } catch (error) {\n return [\n {\n severity: \"warning\",\n file: skillMdRelPath,\n message: `Cannot verify directory name '${dirName}': ${getErrorMessage(error)}`,\n },\n ];\n }\n}\n\n/**\n * Finds missing SKILL.md / metadata.yaml pairs (pure function, no I/O).\n *\n * Returns issues for:\n * - Directories with SKILL.md but no metadata.yaml\n * - Directories with metadata.yaml but no SKILL.md\n */\nexport function validateSkillFilePairs(\n skillMdDirs: Set<string>,\n metadataDirs: Set<string>,\n skillsDir: string,\n): SourceValidationIssue[] {\n const missingMetadata = [...skillMdDirs]\n .filter((dir) => !metadataDirs.has(dir))\n .map((dir) => ({\n severity: \"error\" as const,\n file: path.join(skillsDir, dir),\n message: `Missing ${STANDARD_FILES.METADATA_YAML} — skill directory has ${STANDARD_FILES.SKILL_MD} but no metadata`,\n }));\n\n const missingSkillMd = [...metadataDirs]\n .filter((dir) => !skillMdDirs.has(dir))\n .map((dir) => ({\n severity: \"error\" as const,\n file: path.join(skillsDir, dir),\n message: `Missing ${STANDARD_FILES.SKILL_MD} — skill directory has ${STANDARD_FILES.METADATA_YAML} but no SKILL.md`,\n }));\n\n return [...missingMetadata, ...missingSkillMd];\n}\n\n/**\n * Validates a skills source repository for metadata correctness.\n *\n * Checks:\n * 1. Every metadata.yaml against the strict validation schema\n * (over-length cliDescription is downgraded to a warning)\n * 2. Directory name equals the skill's machine id (SKILL.md frontmatter name)\n * 3. Cross-references resolve to existing skill IDs (via checkMatrixHealth)\n * 4. camelCase key convention (no snake_case)\n * 5. Every skill directory has both SKILL.md and metadata.yaml\n *\n * `reader` decides how loudly one of those findings is stated — see {@link MarketplaceReader}.\n * It defaults to `\"author\"`, the louder verdict: a caller that names nobody has said nothing\n * about who is reading, and under-reporting to the one person who can fix the file is the worse\n * of the two ways to be wrong.\n */\nexport async function validateSource(\n sourcePath: string,\n reader: MarketplaceReader = \"author\",\n): Promise<SourceValidationResult> {\n const issues: SourceValidationIssue[] = [];\n\n const resolvedPath = path.isAbsolute(sourcePath) ? sourcePath : path.resolve(sourcePath);\n\n if (!(await directoryExists(resolvedPath))) {\n issues.push({\n severity: \"error\",\n file: resolvedPath,\n message: \"Marketplace directory does not exist\",\n });\n return buildResult(issues, 0);\n }\n\n // ABORT on an unreadable config, caught by `validateOneSource`, which turns it into an issue\n // against this marketplace. Defaulting past it would validate whatever sits at `src/skills/` and\n // call a marketplace whose skills live elsewhere empty.\n const sourceProjectConfig = await loadProjectSourceConfig(resolvedPath);\n const skillsDirRelPath = sourceProjectConfig?.skillsDir ?? SKILLS_DIR_PATH;\n const skillsDir = path.join(resolvedPath, skillsDirRelPath);\n\n if (!(await directoryExists(skillsDir))) {\n issues.push({\n severity: \"error\",\n file: skillsDir,\n message: \"Skills directory does not exist\",\n });\n return buildResult(issues, 0);\n }\n\n // Phase 1: Check every skill directory has both SKILL.md and metadata.yaml\n const skillMdFiles = await glob(`**/${STANDARD_FILES.SKILL_MD}`, skillsDir);\n const metadataFiles = await glob(`**/${STANDARD_FILES.METADATA_YAML}`, skillsDir);\n\n const skillMdDirs = new Set(skillMdFiles.map((f) => path.dirname(f)));\n const metadataDirs = new Set(metadataFiles.map((f) => path.dirname(f)));\n\n issues.push(...validateSkillFilePairs(skillMdDirs, metadataDirs, skillsDir));\n\n // Phase 2: Validate each metadata.yaml against strict schema and conventions.\n // Pair violations were already reported by phase 1 — validate only complete pairs.\n const validMetadataFiles = metadataFiles.filter((f) => skillMdDirs.has(path.dirname(f)));\n for (const metadataFile of validMetadataFiles) {\n issues.push(...(await validateOneSkill(skillsDir, skillsDirRelPath, metadataFile)));\n }\n\n // Phase 3: Cross-reference validation via matrix health check\n issues.push(...(await checkCrossReferences(resolvedPath, reader)));\n\n // Phases 4–6: optional source-repo targets — run in parallel\n // Phase 4: stack skill metadata + stack configs\n // Phase 5: agent metadata\n // Phase 6: config/*.ts runtime exports\n const extraIssues = await Promise.all([\n validateStacks(resolvedPath),\n validateAgents(resolvedPath),\n validateConfigFiles(resolvedPath),\n ]);\n issues.push(...extraIssues.flat());\n\n return buildResult(issues, validMetadataFiles.length);\n}\n\n/**\n * Why a YAML file could not be read, in the parser's own words. Two phases refuse the same\n * way — the skill-pair scan and the stack/agent scan — and they printed different sentences\n * for a while, one carrying the cause and one dropping it; naming the message once is what\n * stops them diverging again.\n */\nfunction yamlParseFailure(error: unknown): string {\n return `Failed to parse YAML: ${getErrorMessage(error)}`;\n}\n\n/**\n * One complete skill pair, judged four ways: its metadata.yaml parses, its keys are camelCase,\n * it satisfies the strict published-skill schema, and its directory is named after the id its\n * SKILL.md declares. A file nothing can be parsed out of reports that and stops — every check\n * after it reads the parsed value, so each would only restate the same fault.\n */\nasync function validateOneSkill(\n skillsDir: string,\n skillsDirRelPath: string,\n metadataFile: string,\n): Promise<SourceValidationIssue[]> {\n const relPath = path.join(skillsDirRelPath, metadataFile);\n\n let rawMetadata: unknown;\n try {\n rawMetadata = parseYaml(await readFile(path.join(skillsDir, metadataFile)));\n } catch (error) {\n return [{ severity: \"error\", file: relPath, message: yamlParseFailure(error) }];\n }\n\n return [\n ...checkSnakeCaseKeys(rawMetadata, relPath),\n ...checkMetadataSchema(rawMetadata, relPath),\n // Independent of metadata validity — the id lives in SKILL.md frontmatter\n ...(await checkSkillDirName(skillsDir, skillsDirRelPath, path.dirname(metadataFile))),\n ];\n}\n\n/**\n * The strict published-skill schema's verdict, as its hard errors plus the one advisory\n * (over-length cliDescription) `splitMetadataValidationIssues` separates out.\n */\nfunction checkMetadataSchema(rawMetadata: unknown, relPath: string): SourceValidationIssue[] {\n const result = validateSkillMetadata(rawMetadata);\n if (result.success) return [];\n\n const { errors, warnings } = splitMetadataValidationIssues(result.error, rawMetadata);\n return [\n ...errors.map((message) => ({ severity: \"error\" as const, file: relPath, message })),\n ...warnings.map((message) => ({ severity: \"warning\" as const, file: relPath, message })),\n ];\n}\n\n/**\n * The manifest as a reader of the report has to type it — the location half of the row\n * `doctor` prints, and therefore the file they open.\n */\nconst MARKETPLACE_MANIFEST_PATH = path.join(PLUGIN_MANIFEST_DIR, MARKETPLACE_JSON);\n\n/**\n * Whether every relationship the source declares resolves to a skill it actually holds.\n * A load that did not complete is reported by {@link matrixLoadFailure}, which decides\n * whether the failure is this marketplace's fault or merely this pass's.\n */\nasync function checkCrossReferences(\n resolvedPath: string,\n reader: MarketplaceReader,\n): Promise<SourceValidationIssue[]> {\n try {\n await loadSkillsMatrixFromSource({ sourceFlag: resolvedPath, skipExtraSources: true });\n return checkMatrixHealth(matrix).map((healthIssue) =>\n toSourceIssue(healthIssue, resolvedPath, reader),\n );\n } catch (error) {\n return [matrixLoadFailure(error)];\n }\n}\n\n/**\n * A load this pass could not complete, as the finding a reader can act on.\n *\n * Two answers, because the two failures are not one event. A manifest naming the\n * marketplace something Claude Code registers no plugin under leaves nothing here\n * installable, so it is this marketplace's own ERROR, against the file that holds the\n * name — without it the Marketplaces row counted such a marketplace as validated and\n * printed a tick beneath `doctor`'s own warning about that same file, and a warning above\n * a tick is what a reader stops believing. Everything else leaves the marketplace\n * installable and only leaves this pass unable to run, so it stays a warning against the\n * file it was reading. Read off the throw's TYPE, so nothing here matches on a sentence.\n */\nfunction matrixLoadFailure(error: unknown): SourceValidationIssue {\n if (error instanceof MarketplaceNameRefusedError) {\n return {\n severity: \"error\",\n file: MARKETPLACE_MANIFEST_PATH,\n message: getErrorMessage(error),\n };\n }\n\n return {\n severity: \"warning\",\n file: SKILL_CATEGORIES_PATH,\n message: `Cross-reference validation skipped: failed to load categories/rules: ${getErrorMessage(error)}`,\n };\n}\n\n/**\n * The audit manifest, as a path a reader can open. It is this CLI's own file rather than anything\n * in the marketplace being validated, and it has to be: the verdict a matrix contradicts is\n * recorded there and the marketplace holds no copy of it.\n */\nconst SKILL_AUDIT_PATH = \"src/cli/lib/configuration/skill-audit.ts\";\n\n/**\n * The file a finding's defect is written in — the one `doctor` renders as the location half of the\n * line, and therefore the one the reader opens.\n *\n * Each answer is the file the check actually reads, which is not always the file its name suggests:\n *\n * - a category and the `domain` it omits are both declared in the categories file, and a skill\n * naming a category nothing defines is the same file short an entry (its own metadata.yaml is\n * the other half of that fix, and the message already names the skill);\n * - every relation a resolved skill carries comes from the rules file — no metadata.yaml declares\n * one — so an unresolved reference and the dangling slug behind it are both written there;\n * - a verdict, recorded or missing, is the audit manifest's.\n *\n * Exhaustive on purpose: a seventh finding kind will not compile until someone decides where its\n * defect lives, which is the property one path shared by all six had already lost.\n */\nfunction fileHoldingDefect(finding: MatrixHealthIssue[\"finding\"]): string {\n switch (finding) {\n case \"category-missing-domain\":\n case \"skill-unknown-category\":\n return SKILL_CATEGORIES_PATH;\n case \"skill-unresolved-relation-ref\":\n case \"rule-unresolved-slug\":\n return SKILL_RULES_PATH;\n case \"audit-verdict-contradiction\":\n case \"skill-unaudited\":\n return SKILL_AUDIT_PATH;\n default: {\n const exhaustive: never = finding;\n return exhaustive;\n }\n }\n}\n\n/**\n * One health finding as this reader should hear it. Every kind but one is reported at the\n * severity the health check gave it — that severity is a property of the defect. The exception\n * is the slug a marketplace's own rules dangle, which is a property of the defect AND of who is\n * looking: a typo the author can fix, and a file the consumer cannot open.\n *\n * The reader moves the severity and the wording; it never moves the file, because which file holds\n * the defect is not a fact about who is reading.\n */\nfunction toSourceIssue(\n healthIssue: MatrixHealthIssue,\n marketplacePath: string,\n reader: MarketplaceReader,\n): SourceValidationIssue {\n const file = fileHoldingDefect(healthIssue.finding);\n\n if (reader === \"consumer\" && healthIssue.finding === \"rule-unresolved-slug\") {\n return {\n severity: \"warning\",\n file,\n message: consumedMarketplaceMessage(marketplacePath, healthIssue.details),\n };\n }\n\n return {\n severity: healthIssue.severity,\n file,\n message: healthIssue.details,\n };\n}\n\n/**\n * The same finding, addressed to someone who did not write the rule. It leads with the\n * marketplace because that is the part the slug alone does not tell them, and it says outright\n * that there is nothing here to fix — a warning that sends a reader hunting through their own\n * project for a typo in a file they do not own is worse than no warning at all.\n */\nfunction consumedMarketplaceMessage(marketplacePath: string, details: string): string {\n return `Marketplace '${marketplacePath}': ${details}. Nothing to fix here — the rule is that marketplace's, not this project's`;\n}\n\n/**\n * Validates stack-embedded skill metadata.yaml files and stack config.yaml files.\n * Skips silently when src/stacks/ does not exist.\n */\nasync function validateStacks(resolvedPath: string): Promise<SourceValidationIssue[]> {\n const stacksDir = path.join(resolvedPath, DIRS.stacks);\n if (!(await directoryExists(stacksDir))) return [];\n\n const [skillMetaIssues, configIssues] = await Promise.all([\n validateYamlFiles({\n baseDir: stacksDir,\n relBaseDir: DIRS.stacks,\n pattern: `**/skills/**/${STANDARD_FILES.METADATA_YAML}`,\n schema: metadataValidationSchema,\n }),\n validateYamlFiles({\n baseDir: stacksDir,\n relBaseDir: DIRS.stacks,\n pattern: `*/${STANDARD_FILES.CONFIG_YAML}`,\n schema: stackConfigValidationSchema,\n }),\n ]);\n return [...skillMetaIssues, ...configIssues];\n}\n\n/**\n * Validates agent metadata.yaml files against the compiled agent output schema.\n * Skips silently when src/agents/ does not exist.\n */\nasync function validateAgents(resolvedPath: string): Promise<SourceValidationIssue[]> {\n const agentsDir = path.join(resolvedPath, DIRS.agents);\n if (!(await directoryExists(agentsDir))) return [];\n\n return validateYamlFiles({\n baseDir: agentsDir,\n relBaseDir: DIRS.agents,\n pattern: `**/${STANDARD_FILES.AGENT_METADATA_YAML}`,\n schema: agentYamlGenerationSchema,\n });\n}\n\n/**\n * Validates TypeScript config files (skill-categories.ts, skill-rules.ts, stacks.ts)\n * by runtime-loading them via loadConfig and validating the default export.\n * Skips silently when a file does not exist.\n */\nasync function validateConfigFiles(resolvedPath: string): Promise<SourceValidationIssue[]> {\n const results = await Promise.all([\n validateTsConfig(resolvedPath, SKILL_CATEGORIES_PATH, skillCategoriesFileSchema),\n validateTsConfig(resolvedPath, SKILL_RULES_PATH, skillRulesFileSchema),\n validateTsConfig(resolvedPath, STACKS_FILE_PATH, stacksConfigSchema),\n ]);\n return results.flat();\n}\n\n/**\n * Globs YAML files under baseDir and validates each against the given schema.\n * Reports parse errors, schema errors (as field-path messages), and uses relBaseDir\n * for display paths so issue locations match the project-relative form used elsewhere.\n */\nasync function validateYamlFiles(opts: {\n baseDir: string;\n relBaseDir: string;\n pattern: string;\n schema: z.ZodType<unknown>;\n}): Promise<SourceValidationIssue[]> {\n const issues: SourceValidationIssue[] = [];\n const files = await glob(opts.pattern, opts.baseDir);\n\n for (const relFile of files) {\n const absPath = path.join(opts.baseDir, relFile);\n const displayPath = path.join(opts.relBaseDir, relFile);\n\n let parsed: unknown;\n try {\n parsed = parseYaml(await readFile(absPath));\n } catch (error) {\n issues.push({ severity: \"error\", file: displayPath, message: yamlParseFailure(error) });\n continue;\n }\n\n const result = opts.schema.safeParse(parsed);\n if (result.success) continue;\n\n issues.push(\n ...formatZodErrors(result.error).map((message) => ({\n severity: \"error\" as const,\n file: displayPath,\n message,\n })),\n );\n }\n return issues;\n}\n\n/**\n * Runtime-loads a TypeScript config file via loadConfig and reports validation failures.\n * Absent files are not errors — only report when the file exists but fails to load or validate.\n *\n * The two ways a file can say nothing are reported apart, because the author's next move differs\n * and they used to arrive wearing each other's words. A `null` is a file that exported nothing at\n * all; a module that exported only named bindings raises {@link ConfigDefaultExportError}, which\n * is the one this file's own config files get wrong — `export const skillRules = {...}` reads to\n * `loadConfig` as a namespace, and validating THAT against the schema reports whichever field the\n * schema names first as missing from a file the author can see it in.\n */\nasync function validateTsConfig(\n resolvedPath: string,\n relConfigPath: string,\n schema: z.ZodType<unknown>,\n): Promise<SourceValidationIssue[]> {\n const absPath = path.join(resolvedPath, relConfigPath);\n if (!(await fileExists(absPath))) return [];\n\n try {\n const loaded = await loadConfig(absPath, schema);\n if (loaded === null) {\n return [{ severity: \"error\", file: relConfigPath, message: \"Config is empty\" }];\n }\n return [];\n } catch (error) {\n if (error instanceof ConfigDefaultExportError) {\n return [{ severity: \"error\", file: relConfigPath, message: \"Config has no default export\" }];\n }\n return [\n { severity: \"error\", file: relConfigPath, message: formatLoadError(relConfigPath, error) },\n ];\n }\n}\n\n/**\n * Normalizes a loadConfig error so the message references the relative config path,\n * not the absolute path embedded by loadConfig's own template string.\n */\nfunction formatLoadError(relConfigPath: string, error: unknown): string {\n const raw = getErrorMessage(error);\n const stripped = raw.replace(/Failed to load config from '[^']+':\\s*/, \"\");\n return `Failed to load ${relConfigPath}: ${stripped}`;\n}\n\nfunction buildResult(issues: SourceValidationIssue[], skillCount: number): SourceValidationResult {\n const errorCount = issues.filter((i) => i.severity === \"error\").length;\n const warningCount = issues.filter((i) => i.severity === \"warning\").length;\n return { issues, skillCount, errorCount, warningCount };\n}\n","import os from \"os\";\nimport path from \"path\";\nimport { partition } from \"remeda\";\nimport { getErrorMessage } from \"../utils/errors.js\";\nimport { PLUGIN_MANIFEST_DIR, STANDARD_FILES } from \"../consts.js\";\nimport { directoryExists, fileExists, listDirectories } from \"../utils/fs.js\";\nimport { listAgentMdFiles, splitAgentsByProvenance } from \"./agents/index.js\";\nimport { readSkillMetadata } from \"./loading/index.js\";\nimport {\n configDirsInPlay,\n findConfigLoadFailures,\n getProjectConfigPath,\n isLocalSource,\n loadProjectConfigFromDir,\n resolvePrimarySourceEntry,\n type ConfigLoadError,\n type LoadedProjectConfig,\n type SourceEntry,\n} from \"./configuration/index.js\";\nimport { isHomeDirectory, resolveInstallPaths } from \"./installation/index.js\";\nimport {\n getInstalledPluginsRegistryPath,\n getProjectPluginsDir,\n getUserPluginsDir,\n listRegisteredPluginInstalls,\n validateAgentFrontmatter,\n validateAllPlugins,\n validatePlugin,\n validateSkillFrontmatter,\n type ResolvedPlugin,\n} from \"./plugins/index.js\";\nimport { splitMetadataValidationIssues, validateSkillMetadata } from \"./schemas.js\";\nimport { readForkedFromMetadata } from \"./skills/index.js\";\nimport { isSourceRepo, validateSource, type MarketplaceReader } from \"./source-validator.js\";\nimport type { ValidationResult } from \"../types/index.js\";\n\n/** How a source repository under the cwd is labelled when it is not a registered source. */\nconst CWD_SOURCE_NAME = \"current directory\";\n\n/** What a compiled agent is called on disk; `splitAgentsByProvenance` answers in bare names. */\nconst AGENT_FILE_EXTENSION = \".md\";\n\nexport type ContentIssue = {\n severity: \"error\" | \"warning\";\n /** The file or directory a reader has to open to fix the issue. */\n file: string;\n message: string;\n};\n\n/**\n * One content pass: what it walked, what it found, and what it deliberately did\n * not check. `notes` carries neither errors nor warnings — it is the record of\n * which sources were reached and which were skipped.\n */\nexport type ContentValidation = {\n count: number;\n issues: ContentIssue[];\n notes: string[];\n};\n\nconst NOTHING_VALIDATED: ContentValidation = { count: 0, issues: [], notes: [] };\n\nfunction mergeValidations(parts: ContentValidation[]): ContentValidation {\n return parts.reduce(\n (acc, part) => ({\n count: acc.count + part.count,\n issues: [...acc.issues, ...part.issues],\n notes: [...acc.notes, ...part.notes],\n }),\n NOTHING_VALIDATED,\n );\n}\n\n/** Render an absolute path with a `~/` prefix when it's under the user's home directory. */\nfunction displayDir(absolutePath: string): string {\n const home = os.homedir();\n if (absolutePath === home) return \"~\";\n if (absolutePath.startsWith(home + path.sep)) {\n return `~${path.sep}${path.relative(home, absolutePath)}`;\n }\n return absolutePath;\n}\n\nfunction toIssues(file: string, result: ValidationResult): ContentIssue[] {\n return [\n ...result.errors.map((message) => ({ severity: \"error\" as const, file, message })),\n ...result.warnings.map((message) => ({ severity: \"warning\" as const, file, message })),\n ];\n}\n\n/** Says which of the three load outcomes a config file is in, without restating the loader. */\nconst CONFIG_UNREADABLE = \"exists but could not be loaded\";\n\n/**\n * Validates the config files this run reads: the project's own and the global one it inlines.\n *\n * A config that exists and cannot be parsed is reported here rather than left to the operational\n * layer, for the reason that layer exists to be gated on — every operational row is read OUT of\n * this file, so each would be a cascade of the same fault. It is also the only report that can\n * carry the loader's reason: the layers below re-read the file per check, and their own\n * diagnostics for it are what used to arrive spliced between the rows.\n *\n * An ABSENT config is not a finding here. It is the legitimate state `init` exists for, and the\n * operational layer already names it and offers the remedy that fits it.\n */\nexport async function validateProjectConfigFile(projectDir: string): Promise<ContentValidation> {\n const [present, failures] = await Promise.all([\n countExistingConfigs(projectDir),\n findConfigLoadFailures(projectDir),\n ]);\n\n return { count: present, issues: failures.map(toUnreadableConfigIssue), notes: [] };\n}\n\nfunction toUnreadableConfigIssue(failure: ConfigLoadError): ContentIssue {\n return {\n severity: \"error\",\n file: displayDir(failure.configPath),\n message: `${CONFIG_UNREADABLE}: ${failure.reason}`,\n };\n}\n\nasync function countExistingConfigs(projectDir: string): Promise<number> {\n const present = await Promise.all(\n configDirsInPlay(projectDir).map((dir) => fileExists(getProjectConfigPath(dir))),\n );\n return present.filter(Boolean).length;\n}\n\n/**\n * Validates the marketplace this installation reads from when it is local, plus the current\n * directory when that is itself a skills source repository — that repository is the content a\n * marketplace author runs this against, and it is not the source they read skills from.\n * A remote marketplace is recorded as skipped rather than fetched.\n *\n * Each one is validated as the reader's own or as someone else's — see {@link readerFor}.\n */\nexport async function validateRegisteredSources(projectDir: string): Promise<ContentValidation> {\n // DEGRADE on an unreadable config. This pass declares `readsConfig: true`, so `doctor` stands it\n // down before it runs whenever the config check has already reported the file — and if it is\n // reached anyway, `safeCheck` turns the throw into a failed row rather than an aborted run. A\n // command whose job is naming what is wrong here must survive the thing it is naming.\n const primary = await resolvePrimarySourceEntry(projectDir);\n const registered = [primary];\n const remote = registered.filter((source) => !isLocalSource(source.url));\n const local = await localSourcesToValidate(projectDir, registered);\n\n const outcomes = await Promise.all(\n local.map((source) => validateOneSource(source, readerFor(projectDir, source))),\n );\n\n return {\n count: local.length,\n issues: outcomes.flatMap((outcome) => outcome.issues),\n notes: [\n ...outcomes.map((outcome) => outcome.note),\n ...remote.map((source) => `${source.name} (${source.url}) — skipped (remote)`),\n ],\n };\n}\n\nasync function localSourcesToValidate(\n projectDir: string,\n registered: SourceEntry[],\n): Promise<SourceEntry[]> {\n const local = registered.filter((source) => isLocalSource(source.url));\n const alreadyCovered = local.some((source) => isCwdMarketplace(projectDir, source));\n\n if (alreadyCovered || !(await isSourceRepo(projectDir))) return local;\n\n return [...local, { name: CWD_SOURCE_NAME, url: projectDir }];\n}\n\n/** Whether this marketplace IS the directory the command ran in, however the config spells it. */\nfunction isCwdMarketplace(projectDir: string, source: SourceEntry): boolean {\n return path.resolve(projectDir, source.url) === projectDir;\n}\n\n/**\n * Where this layer decides what the reader's relationship to a marketplace is — the one place\n * that holds both the directory the command ran in and the path of each marketplace it validates.\n * The appended `CWD_SOURCE_NAME` entry answers `\"author\"` by construction, which is the whole of\n * why a marketplace author's own repository is judged the way they need it to be.\n */\nfunction readerFor(projectDir: string, source: SourceEntry): MarketplaceReader {\n return isCwdMarketplace(projectDir, source) ? \"author\" : \"consumer\";\n}\n\ntype SourceOutcome = { note: string; issues: ContentIssue[] };\n\nasync function validateOneSource(\n source: SourceEntry,\n reader: MarketplaceReader,\n): Promise<SourceOutcome> {\n const label = `${source.name} (${source.url})`;\n try {\n const result = await validateSource(source.url, reader);\n return { note: `${label} — ${result.skillCount} skills`, issues: result.issues };\n } catch (error) {\n return {\n note: `${label} — failed`,\n issues: [{ severity: \"error\", file: source.url, message: getErrorMessage(error) }],\n };\n }\n}\n\n/** Validates every installed plugin bundle in the global and project plugin directories. */\nexport async function validateInstalledPlugins(projectDir: string): Promise<ContentValidation> {\n const dirs = [\n getUserPluginsDir(),\n ...(isHomeDirectory(projectDir) ? [] : [getProjectPluginsDir(projectDir)]),\n ];\n return mergeValidations(await Promise.all(dirs.map(validatePluginsDirectory)));\n}\n\nasync function validatePluginsDirectory(pluginsDir: string): Promise<ContentValidation> {\n if (!(await directoryExists(pluginsDir))) return NOTHING_VALIDATED;\n\n if (await fileExists(getInstalledPluginsRegistryPath(pluginsDir))) {\n const registryValidation = await validateRegistryPlugins(pluginsDir);\n if (registryValidation !== undefined) return registryValidation;\n }\n\n const pluginDirs = await findPluginDirectories(pluginsDir);\n if (pluginDirs.length === 0) return NOTHING_VALIDATED;\n\n const { results } = await validateAllPlugins(pluginsDir);\n\n return {\n count: results.length,\n issues: results.flatMap(({ name, result }) => toIssues(name, result)),\n notes: [],\n };\n}\n\n/**\n * Validates the installs recorded in the plugins directory's `installed_plugins.json`\n * (claude CLI >=2.1.220 cache layout). Returns undefined when the registry records no\n * installs so the caller can fall back to the direct-children scan (older/manual layouts).\n */\nasync function validateRegistryPlugins(pluginsDir: string): Promise<ContentValidation | undefined> {\n let installs: ResolvedPlugin[];\n try {\n installs = await listRegisteredPluginInstalls(pluginsDir);\n } catch (error) {\n return {\n count: 0,\n issues: [\n {\n severity: \"error\",\n file: displayDir(getInstalledPluginsRegistryPath(pluginsDir)),\n message: getErrorMessage(error),\n },\n ],\n notes: [],\n };\n }\n\n if (installs.length === 0) return undefined;\n\n // A recorded installPath that no longer exists surfaces as an invalid plugin\n // via validatePlugin's structure check, not a crash.\n const results = await Promise.all(\n installs.map(async ({ pluginKey, installPath }) =>\n toIssues(pluginKey, await validatePlugin(installPath)),\n ),\n );\n\n return { count: installs.length, issues: results.flat(), notes: [] };\n}\n\nasync function findPluginDirectories(pluginsDir: string): Promise<string[]> {\n const entries = await listDirectories(pluginsDir);\n const checks = await Promise.all(\n entries.map(async (name) => ({\n name,\n isPlugin: await directoryExists(path.join(pluginsDir, name, PLUGIN_MANIFEST_DIR)),\n })),\n );\n return checks.filter((check) => check.isPlugin).map((check) => check.name);\n}\n\n/**\n * Validates the SKILL.md and metadata.yaml of every installed skill this installation owns, both\n * scopes.\n *\n * Ownership has to be asked because `~/.claude/skills/` is CLAUDE CODE's directory, shared with\n * everything else that installs a skill there — not this CLI's private space. Judging every\n * directory in it against this CLI's schema reported a skill some other tool put there as a fault\n * in the user's install, in a file they never wrote and cannot fix from here.\n *\n * Two claims make a directory this installation's, and either is enough:\n *\n * - **The configuration in play names its id.** Both configs a run reads, because both scopes are\n * walked. This is the claim that keeps `doctor` loud where it matters most: the provenance\n * marker lives INSIDE metadata.yaml, so a skill whose metadata is missing or unparseable — the\n * plainest breakage there is — can carry no marker to be recognised by.\n * - **The directory carries `forkedFrom`.** The marker this CLI stamps into every skill directory\n * it writes, and the same question `uninstall` asks before removing anything. It answers for the\n * skills a configuration has stopped naming, or never got the chance to.\n *\n * A directory neither claim reaches is not judged and not counted. It IS named — see\n * {@link foreignSkillNote}: a check that quietly walks past a directory is indistinguishable from\n * one that missed it.\n */\nexport async function validateInstalledSkills(projectDir: string): Promise<ContentValidation> {\n const configuredIds = await configuredSkillIds(projectDir);\n return mergeValidations(\n await Promise.all(\n installedDirs(projectDir, \"skillsDir\").map((dir) =>\n validateSkillsDirectory(dir, configuredIds),\n ),\n ),\n );\n}\n\n/** Every skill id the configs this run reads name, across both scopes and both install modes. */\nasync function configuredSkillIds(projectDir: string): Promise<ReadonlySet<string>> {\n const loaded = await Promise.all(configDirsInPlay(projectDir).map(loadProjectConfigFromDir));\n return new Set(loaded.flatMap(configuredIdsOf));\n}\n\nfunction configuredIdsOf(loaded: LoadedProjectConfig | null): string[] {\n if (!loaded) return [];\n return loaded.config.skills.map((skill) => skill.id);\n}\n\n/** Validates the frontmatter of every compiled agent file, both scopes. */\nexport async function validateInstalledAgents(projectDir: string): Promise<ContentValidation> {\n return mergeValidations(\n await Promise.all(installedDirs(projectDir, \"agentsDir\").map(validateAgentsDirectory)),\n );\n}\n\n/**\n * The directories to walk for an installed-content pass. At the home directory both\n * scopes resolve to the same place, so it is walked once instead of twice.\n */\nfunction installedDirs(projectDir: string, key: \"skillsDir\" | \"agentsDir\"): string[] {\n const global = resolveInstallPaths(projectDir, \"global\")[key];\n if (isHomeDirectory(projectDir)) return [global];\n return [global, resolveInstallPaths(projectDir, \"project\")[key]];\n}\n\n/** What an installed-content pass walked, named rather than validated. */\nexport type InstalledArtifacts = {\n /** Every skill directory this CLI can prove it wrote, both scopes, as display paths. */\n skills: string[];\n /** Every compiled agent file this CLI can prove it wrote, both scopes, as display paths. */\n agents: string[];\n};\n\n/**\n * The same two walks {@link validateInstalledSkills} and {@link validateInstalledAgents} count,\n * naming what belongs to this installation instead of judging it. `doctor` reports this when no\n * configuration exists to compare the installation against: there is nothing to validate the\n * files AGAINST, and naming them is the whole finding.\n *\n * Each walk applies the same ownership question its own pass asks, minus the half that needs a\n * config to answer — see {@link listSkillDirsWithOurProvenance} and\n * {@link listAgentFilesWithOurProvenance}. Both are the question the command this row sends the\n * reader to asks before it removes anything, so what is named here is what `uninstall` takes.\n */\nexport async function listInstalledArtifacts(projectDir: string): Promise<InstalledArtifacts> {\n const [skills, agents] = await Promise.all([\n listAcrossScopes(installedDirs(projectDir, \"skillsDir\"), listSkillDirsWithOurProvenance),\n listAcrossScopes(installedDirs(projectDir, \"agentsDir\"), listAgentFilesWithOurProvenance),\n ]);\n return { skills, agents };\n}\n\n/**\n * The compiled agent files in one tree that this CLI can prove it wrote.\n *\n * The agent axis's counterpart to {@link listSkillDirsWithOurProvenance}, and deliberately\n * `splitAgentsByProvenance` rather than a second reading of the same marker: `uninstall` decides\n * what to remove with no configuration by asking that function, so a listing built any other way\n * could offer a file it then refused. It did — every `*.md` in the directory was named here while\n * the remover took only the marked ones, so a hand-authored agent was offered by one screen and\n * declined by the next.\n *\n * A file that cannot be read carries no marker and is not listed, which is that function's own\n * rule: \"cannot prove it is ours\" and \"is not ours\" call for the same answer. Nothing goes\n * unmentioned either way — {@link validateInstalledAgents} walks every agent file whatever state\n * the config is in.\n */\nasync function listAgentFilesWithOurProvenance(agentsDir: string): Promise<string[]> {\n const { marked } = await splitAgentsByProvenance(agentsDir);\n return marked.map((name) => `${name}${AGENT_FILE_EXTENSION}`);\n}\n\n/**\n * The skill directories in one tree that this CLI can prove it wrote.\n *\n * With no configuration left to name an id, the provenance marker is the only claim a directory\n * can carry — and it is the claim `uninstall` reads before removing anything, so every directory\n * listed here is one that command would actually remove. Listing a directory it would refuse is\n * the CLI recommending what it then declines to do.\n *\n * The marker lives INSIDE `metadata.yaml`, so a directory whose metadata is missing or unreadable\n * can carry no marker and is not listed. That is deliberate rather than a gap: \"cannot prove it is\n * ours\" and \"is not ours\" call for the same answer — leave it alone — which is the rule\n * `splitAgentsByProvenance` already applies to compiled agents. Nothing goes unmentioned either\n * way: {@link validateInstalledSkills} runs whatever state the config is in, and names every\n * directory it stepped over.\n */\nasync function listSkillDirsWithOurProvenance(skillsDir: string): Promise<string[]> {\n const names = await listDirectories(skillsDir);\n const judged = await Promise.all(\n names.map(async (name) => ({ name, ours: await carriesOurProvenance(skillsDir, name) })),\n );\n return judged.filter((entry) => entry.ours).map((entry) => entry.name);\n}\n\nasync function listAcrossScopes(\n dirs: string[],\n listEntries: (dir: string) => Promise<string[]>,\n): Promise<string[]> {\n const perDir = await Promise.all(dirs.map((dir) => listDisplayPaths(dir, listEntries)));\n return perDir.flat();\n}\n\n/** One directory's entries as display paths, or nothing when the directory is absent. */\nasync function listDisplayPaths(\n dir: string,\n listEntries: (dir: string) => Promise<string[]>,\n): Promise<string[]> {\n if (!(await directoryExists(dir))) return [];\n const entries = await listEntries(dir);\n return entries.map((entry) => displayDir(path.join(dir, entry)));\n}\n\nasync function validateSkillsDirectory(\n skillsDir: string,\n configuredIds: ReadonlySet<string>,\n): Promise<ContentValidation> {\n if (!(await directoryExists(skillsDir))) return NOTHING_VALIDATED;\n\n const skillDirs = await listDirectories(skillsDir);\n if (skillDirs.length === 0) return NOTHING_VALIDATED;\n\n const judged = await Promise.all(\n skillDirs.map(async (name) => ({\n name,\n ours: await isOurSkillDirectory(skillsDir, name, configuredIds),\n })),\n );\n const [ours, foreign] = partition(judged, (entry) => entry.ours);\n\n const results = await Promise.all(\n ours.map(async ({ name }) => {\n const skillDir = path.join(skillsDir, name);\n return toIssues(displayDir(skillDir), await validateInstalledSkill(skillDir));\n }),\n );\n\n return {\n count: ours.length,\n issues: results.flat(),\n notes: foreign.map(({ name }) => foreignSkillNote(skillsDir, name)),\n };\n}\n\n/** Either claim this installation has on a skill directory — see {@link validateInstalledSkills}. */\nasync function isOurSkillDirectory(\n skillsDir: string,\n name: string,\n configuredIds: ReadonlySet<string>,\n): Promise<boolean> {\n if (configuredIds.has(name)) return true;\n return carriesOurProvenance(skillsDir, name);\n}\n\n/**\n * The claim a skill directory carries on its own, independent of any configuration: the\n * `forkedFrom` block the copier stamps into every directory this CLI writes. One definition,\n * because the union above and the no-config listing are the same judgement with and without its\n * other half — and `uninstall` decides what to remove by asking exactly this.\n */\nasync function carriesOurProvenance(skillsDir: string, name: string): Promise<boolean> {\n return (await readForkedFromMetadata(path.join(skillsDir, name))) !== null;\n}\n\n/**\n * A directory this pass declined to judge, named so the count and the directory listing do not\n * silently disagree. Not a warning: nothing here is wrong, and a reader sent to fix a skill they\n * did not install is worse off than one told plainly that it is not this CLI's to police.\n */\nfunction foreignSkillNote(skillsDir: string, name: string): string {\n return `${displayDir(path.join(skillsDir, name))} — not installed by this CLI and named by no configuration here: not validated`;\n}\n\nasync function validateAgentsDirectory(agentsDir: string): Promise<ContentValidation> {\n if (!(await directoryExists(agentsDir))) return NOTHING_VALIDATED;\n\n const agentFiles = await listAgentMdFiles(agentsDir);\n if (agentFiles.length === 0) return NOTHING_VALIDATED;\n\n const results = await Promise.all(\n agentFiles.map(async (fileName) => {\n const agentPath = path.join(agentsDir, fileName);\n return toIssues(displayDir(agentPath), await validateAgentFrontmatter(agentPath));\n }),\n );\n\n return { count: agentFiles.length, issues: results.flat(), notes: [] };\n}\n\nasync function validateInstalledSkill(skillDir: string): Promise<ValidationResult> {\n const skillMdPath = path.join(skillDir, STANDARD_FILES.SKILL_MD);\n const metadataPath = path.join(skillDir, STANDARD_FILES.METADATA_YAML);\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(skillMdPath))) {\n errors.push(`Missing ${STANDARD_FILES.SKILL_MD}`);\n } else {\n const frontmatterResult = await validateSkillFrontmatter(skillMdPath);\n errors.push(...frontmatterResult.errors);\n warnings.push(...frontmatterResult.warnings);\n }\n\n if (!(await fileExists(metadataPath))) {\n errors.push(`Missing ${STANDARD_FILES.METADATA_YAML}`);\n } else {\n const metadataResult = await validateInstalledSkillMetadata(metadataPath);\n errors.push(...metadataResult.errors);\n warnings.push(...metadataResult.warnings);\n }\n\n return { valid: errors.length === 0, errors, warnings };\n}\n\nasync function validateInstalledSkillMetadata(metadataPath: string): Promise<ValidationResult> {\n // Same judgment `compile` refuses on and local-skill discovery skips on: a file\n // that describes no skill is reported here as the error it is. The strict\n // published-skill checks below are layered on top of that verdict, never against\n // it — doctor reports what the other two passes refuse, and then some.\n const read = await readSkillMetadata(metadataPath);\n if (!read.usable) {\n return {\n valid: false,\n errors: [`${STANDARD_FILES.METADATA_YAML}: ${read.reason}`],\n warnings: [],\n };\n }\n\n const metadata = read.metadata;\n const result = validateSkillMetadata(metadata);\n if (result.success) {\n return { valid: true, errors: [], warnings: [] };\n }\n\n // Over-length cliDescription is advisory — only hard schema violations invalidate the skill\n const { errors, warnings } = splitMetadataValidationIssues(result.error, metadata);\n return {\n valid: errors.length === 0,\n errors: errors.map((e) => `${STANDARD_FILES.METADATA_YAML}: ${e}`),\n warnings: warnings.map((w) => `${STANDARD_FILES.METADATA_YAML}: ${w}`),\n };\n}\n"],"mappings":"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","names":["os","path","path","path","matrix","os","path"]}