@claude-collective/cli 0.6.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +192 -0
- package/README.md +26 -9
- package/dist/{chunk-TOPAIL5W.js → chunk-3U3R4NCG.js} +2 -2
- package/dist/chunk-3U3R4NCG.js.map +1 -0
- package/dist/{chunk-TFV6Z7F7.js → chunk-57Y5RALO.js} +10 -10
- package/dist/chunk-57Y5RALO.js.map +1 -0
- package/dist/chunk-66UDJBF6.js +96 -0
- package/dist/chunk-66UDJBF6.js.map +1 -0
- package/dist/chunk-6DCSSORF.js +264 -0
- package/dist/chunk-6DCSSORF.js.map +1 -0
- package/dist/chunk-6Q3Y7KVB.js +31 -0
- package/dist/chunk-6Q3Y7KVB.js.map +1 -0
- package/dist/{chunk-SJYG4EJZ.js → chunk-76DWXGQE.js} +10 -8
- package/dist/chunk-76DWXGQE.js.map +1 -0
- package/dist/{chunk-AZP2AA5M.js → chunk-7Q44DMSP.js} +241 -84
- package/dist/chunk-7Q44DMSP.js.map +1 -0
- package/dist/chunk-ACNBKXXJ.js +321 -0
- package/dist/chunk-ACNBKXXJ.js.map +1 -0
- package/dist/{chunk-JMQGWQZU.js → chunk-B7CCVP6Q.js} +42 -10
- package/dist/chunk-B7CCVP6Q.js.map +1 -0
- package/dist/chunk-BDLUZVKU.js +54 -0
- package/dist/chunk-BDLUZVKU.js.map +1 -0
- package/dist/chunk-CDX4W4DM.js +120 -0
- package/dist/chunk-CDX4W4DM.js.map +1 -0
- package/dist/{chunk-MYAVQ23U.js → chunk-CJEHB4TB.js} +23 -9
- package/dist/chunk-CJEHB4TB.js.map +1 -0
- package/dist/{chunk-6WEQADPL.js → chunk-CPZOTVCI.js} +15 -14
- package/dist/chunk-CPZOTVCI.js.map +1 -0
- package/dist/chunk-D237EVNB.js +187 -0
- package/dist/chunk-D237EVNB.js.map +1 -0
- package/dist/{chunk-UFWNMW3G.js → chunk-DRXPNNPB.js} +19 -18
- package/dist/chunk-DRXPNNPB.js.map +1 -0
- package/dist/chunk-E3FJH4TF.js +80 -0
- package/dist/chunk-E3FJH4TF.js.map +1 -0
- package/dist/{chunk-D4IQAT27.js → chunk-ED4E6Q2T.js} +10 -10
- package/dist/chunk-ED4E6Q2T.js.map +1 -0
- package/dist/{chunk-SYQ7R2JO.js → chunk-EHS3TWWP.js} +3 -3
- package/dist/chunk-EHS3TWWP.js.map +1 -0
- package/dist/{chunk-AU7XVCLO.js → chunk-GDH553MV.js} +6 -6
- package/dist/chunk-GDH553MV.js.map +1 -0
- package/dist/chunk-HLJX2FTL.js +95 -0
- package/dist/chunk-HLJX2FTL.js.map +1 -0
- package/dist/chunk-I2DSLOXZ.js +75 -0
- package/dist/chunk-I2DSLOXZ.js.map +1 -0
- package/dist/{chunk-J2Y4A3LP.js → chunk-I4TPKIYX.js} +33 -18
- package/dist/chunk-I4TPKIYX.js.map +1 -0
- package/dist/{chunk-ZSKHDU5P.js → chunk-IMDW5ZUP.js} +19 -11
- package/dist/chunk-IMDW5ZUP.js.map +1 -0
- package/dist/{chunk-U4VYHKPM.js → chunk-JIPWV2FX.js} +6 -6
- package/dist/chunk-JIPWV2FX.js.map +1 -0
- package/dist/{chunk-OSQDDJXX.js → chunk-K7EVM5LY.js} +5 -10
- package/dist/chunk-K7EVM5LY.js.map +1 -0
- package/dist/{chunk-MJSFR562.js → chunk-KAAEN2PO.js} +3 -3
- package/dist/chunk-KAAEN2PO.js.map +1 -0
- package/dist/{chunk-URDV4OCP.js → chunk-LE6IY6IT.js} +22 -17
- package/dist/chunk-LE6IY6IT.js.map +1 -0
- package/dist/{chunk-FKU7VSUD.js → chunk-NDY25DTL.js} +6 -6
- package/dist/chunk-NDY25DTL.js.map +1 -0
- package/dist/{chunk-UNHCZRO4.js → chunk-P26A2K5N.js} +7 -7
- package/dist/chunk-P26A2K5N.js.map +1 -0
- package/dist/{chunk-DHFFRMF6.js → chunk-RTE64SJA.js} +2 -2
- package/dist/chunk-RTE64SJA.js.map +1 -0
- package/dist/{chunk-6ESUJMM7.js → chunk-SGJ23HIP.js} +14 -11
- package/dist/chunk-SGJ23HIP.js.map +1 -0
- package/dist/{chunk-367K3JB3.js → chunk-SVYPSDWY.js} +10 -10
- package/dist/chunk-SVYPSDWY.js.map +1 -0
- package/dist/{chunk-MMDXNZPF.js → chunk-TKFPKEV3.js} +2 -2
- package/dist/chunk-TKFPKEV3.js.map +1 -0
- package/dist/{chunk-M7YCPFIX.js → chunk-UQTEPWU7.js} +2 -2
- package/dist/chunk-UQTEPWU7.js.map +1 -0
- package/dist/{chunk-QESUUPOE.js → chunk-V46GGCCI.js} +80 -27
- package/dist/chunk-V46GGCCI.js.map +1 -0
- package/dist/chunk-X6QONICW.js +86 -0
- package/dist/chunk-X6QONICW.js.map +1 -0
- package/dist/chunk-XY3XDVMI.js +15599 -0
- package/dist/chunk-XY3XDVMI.js.map +1 -0
- package/dist/chunk-Y2LW7R3Y.js +23 -0
- package/dist/chunk-Y2LW7R3Y.js.map +1 -0
- package/dist/chunk-Z2CWURZ6.js +78 -0
- package/dist/chunk-Z2CWURZ6.js.map +1 -0
- package/dist/chunk-Z7G4B5HJ.js +377 -0
- package/dist/chunk-Z7G4B5HJ.js.map +1 -0
- package/dist/{chunk-ZDQIUHAM.js → chunk-ZENYS6KW.js} +16 -15
- package/dist/chunk-ZENYS6KW.js.map +1 -0
- package/dist/{cli-v2 → cli}/defaults/agent-mappings.yaml +5 -5
- package/dist/commands/build/marketplace.js +19 -60
- package/dist/commands/build/marketplace.js.map +1 -1
- package/dist/commands/build/plugins.js +21 -59
- package/dist/commands/build/plugins.js.map +1 -1
- package/dist/commands/build/stack.js +15 -15
- package/dist/commands/build/stack.js.map +1 -1
- package/dist/commands/compile.js +21 -21
- package/dist/commands/compile.js.map +1 -1
- package/dist/commands/config/get.js +9 -8
- package/dist/commands/config/get.js.map +1 -1
- package/dist/commands/config/index.js +7 -6
- package/dist/commands/config/index.js.map +1 -1
- package/dist/commands/config/path.js +8 -7
- package/dist/commands/config/path.js.map +1 -1
- package/dist/commands/config/set-project.js +9 -8
- package/dist/commands/config/set-project.js.map +1 -1
- package/dist/commands/config/set.js +9 -8
- package/dist/commands/config/set.js.map +1 -1
- package/dist/commands/config/show.js +6 -5
- package/dist/commands/config/unset-project.js +9 -8
- package/dist/commands/config/unset-project.js.map +1 -1
- package/dist/commands/config/unset.js +9 -8
- package/dist/commands/config/unset.js.map +1 -1
- package/dist/commands/diff.js +12 -12
- package/dist/commands/diff.js.map +1 -1
- package/dist/commands/doctor.js +10 -10
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/edit.js +52 -48
- package/dist/commands/edit.js.map +1 -1
- package/dist/commands/eject.js +180 -97
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/import/skill.js +339 -0
- package/dist/commands/import/skill.js.map +1 -0
- package/dist/commands/info.js +9 -9
- package/dist/commands/info.js.map +1 -1
- package/dist/commands/init.js +205 -77
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/list.js +9 -9
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/new/agent.js +19 -21
- package/dist/commands/new/agent.js.map +1 -1
- package/dist/commands/new/skill.js +11 -12
- package/dist/commands/new/skill.js.map +1 -1
- package/dist/commands/outdated.js +12 -12
- package/dist/commands/outdated.js.map +1 -1
- package/dist/commands/search.js +205 -17
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/test-imports.js +18 -18
- package/dist/commands/test-imports.js.map +1 -1
- package/dist/commands/uninstall.js +70 -83
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.js +22 -22
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/validate.js +9 -9
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/version/bump.js +8 -8
- package/dist/commands/version/bump.js.map +1 -1
- package/dist/commands/version/index.js +8 -8
- package/dist/commands/version/index.js.map +1 -1
- package/dist/commands/version/set.js +7 -7
- package/dist/commands/version/set.js.map +1 -1
- package/dist/commands/version/show.js +8 -8
- package/dist/commands/version/show.js.map +1 -1
- package/dist/components/common/confirm.js +1 -1
- package/dist/components/common/message.js +1 -1
- package/dist/components/common/message.js.map +1 -1
- package/dist/components/common/spinner.js +1 -1
- package/dist/components/common/spinner.js.map +1 -1
- package/dist/components/skill-search/skill-search.js +10 -0
- package/dist/components/wizard/category-grid.js +9 -0
- package/dist/components/wizard/category-grid.test.js +861 -0
- package/dist/components/wizard/category-grid.test.js.map +1 -0
- package/dist/components/wizard/section-progress.js +9 -0
- package/dist/components/wizard/section-progress.test.js +281 -0
- package/dist/components/wizard/section-progress.test.js.map +1 -0
- package/dist/components/wizard/step-approach.js +4 -3
- package/dist/components/wizard/step-build.js +16 -0
- package/dist/components/wizard/step-build.js.map +1 -0
- package/dist/components/wizard/step-build.test.js +741 -0
- package/dist/components/wizard/step-build.test.js.map +1 -0
- package/dist/components/wizard/step-confirm.js +2 -4
- package/dist/components/wizard/step-refine.js +10 -0
- package/dist/components/wizard/step-refine.js.map +1 -0
- package/dist/components/wizard/step-refine.test.js +236 -0
- package/dist/components/wizard/step-refine.test.js.map +1 -0
- package/dist/components/wizard/step-stack-options.js +11 -0
- package/dist/components/wizard/step-stack-options.js.map +1 -0
- package/dist/components/wizard/step-stack.js +3 -3
- package/dist/components/wizard/wizard-footer.js +9 -0
- package/dist/components/wizard/wizard-footer.js.map +1 -0
- package/dist/components/wizard/wizard-tabs.js +11 -0
- package/dist/components/wizard/wizard-tabs.js.map +1 -0
- package/dist/components/wizard/wizard.js +14 -11
- package/dist/hooks/init.js +5 -4
- package/dist/hooks/init.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/stores/wizard-store.js +2 -2
- package/dist/stores/wizard-store.test.js +249 -15835
- package/dist/stores/wizard-store.test.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-367K3JB3.js.map +0 -1
- package/dist/chunk-6ESUJMM7.js.map +0 -1
- package/dist/chunk-6OY6ZYQF.js +0 -93
- package/dist/chunk-6OY6ZYQF.js.map +0 -1
- package/dist/chunk-6WEQADPL.js.map +0 -1
- package/dist/chunk-AU7XVCLO.js.map +0 -1
- package/dist/chunk-AZP2AA5M.js.map +0 -1
- package/dist/chunk-D4IQAT27.js.map +0 -1
- package/dist/chunk-DHFFRMF6.js.map +0 -1
- package/dist/chunk-FKU7VSUD.js.map +0 -1
- package/dist/chunk-J2Y4A3LP.js.map +0 -1
- package/dist/chunk-JMQGWQZU.js.map +0 -1
- package/dist/chunk-JY4RO76L.js +0 -73
- package/dist/chunk-JY4RO76L.js.map +0 -1
- package/dist/chunk-M7YCPFIX.js.map +0 -1
- package/dist/chunk-MJSFR562.js.map +0 -1
- package/dist/chunk-MMDXNZPF.js.map +0 -1
- package/dist/chunk-MYAVQ23U.js.map +0 -1
- package/dist/chunk-OSQDDJXX.js.map +0 -1
- package/dist/chunk-QESUUPOE.js.map +0 -1
- package/dist/chunk-SJYG4EJZ.js.map +0 -1
- package/dist/chunk-SYQ7R2JO.js.map +0 -1
- package/dist/chunk-TD643KB3.js +0 -245
- package/dist/chunk-TD643KB3.js.map +0 -1
- package/dist/chunk-TFV6Z7F7.js.map +0 -1
- package/dist/chunk-TGOHJCQ4.js +0 -83
- package/dist/chunk-TGOHJCQ4.js.map +0 -1
- package/dist/chunk-TOPAIL5W.js.map +0 -1
- package/dist/chunk-U4VYHKPM.js.map +0 -1
- package/dist/chunk-UFWNMW3G.js.map +0 -1
- package/dist/chunk-UNHCZRO4.js.map +0 -1
- package/dist/chunk-URDV4OCP.js.map +0 -1
- package/dist/chunk-YI6JVSFO.js +0 -43
- package/dist/chunk-YI6JVSFO.js.map +0 -1
- package/dist/chunk-YNSNRR5D.js +0 -184
- package/dist/chunk-YNSNRR5D.js.map +0 -1
- package/dist/chunk-Z6DLWTBY.js +0 -46
- package/dist/chunk-Z6DLWTBY.js.map +0 -1
- package/dist/chunk-ZDQIUHAM.js.map +0 -1
- package/dist/chunk-ZSKHDU5P.js.map +0 -1
- package/dist/components/wizard/selection-header.js +0 -11
- package/dist/components/wizard/step-category.js +0 -12
- package/dist/components/wizard/step-subcategory.js +0 -13
- /package/dist/components/{wizard/selection-header.js.map → skill-search/skill-search.js.map} +0 -0
- /package/dist/components/wizard/{step-category.js.map → category-grid.js.map} +0 -0
- /package/dist/components/wizard/{step-subcategory.js.map → section-progress.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/plugin-validator.ts"],"sourcesContent":["import Ajv, { type ValidateFunction, type ErrorObject } from \"ajv\";\nimport addFormats from \"ajv-formats\";\nimport path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport fg from \"fast-glob\";\nimport {\n fileExists,\n readFile,\n directoryExists,\n listDirectories,\n} from \"../utils/fs\";\nimport { PROJECT_ROOT } from \"../consts\";\nimport type { ValidationResult } from \"../../types\";\n\nconst PLUGIN_DIR = \".claude-plugin\";\nconst PLUGIN_MANIFEST = \"plugin.json\";\nconst SKILL_FILE = \"SKILL.md\";\nconst KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;\nconst SEMVER_REGEX =\n /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$/;\n\nconst schemaCache = new Map<string, object>();\nconst validatorCache = new Map<string, ValidateFunction>();\n\n// Remote schemas hosted on GitHub (source of truth for skill schemas)\nconst REMOTE_SCHEMAS: Record<string, string> = {\n \"skill-frontmatter.schema.json\":\n \"https://raw.githubusercontent.com/claude-collective/skills/main/src/schemas/skill-frontmatter.schema.json\",\n};\n\nasync function loadSchema(schemaName: string): Promise<object> {\n if (schemaCache.has(schemaName)) {\n return schemaCache.get(schemaName)!;\n }\n\n // Try local locations first for CLI-owned schemas\n const locations = [\n path.join(PROJECT_ROOT, \"src\", \"schemas\", schemaName),\n path.join(process.cwd(), \"src\", \"schemas\", schemaName),\n ];\n\n for (const schemaPath of locations) {\n if (await fileExists(schemaPath)) {\n const content = await readFile(schemaPath);\n const schema = JSON.parse(content);\n schemaCache.set(schemaName, schema);\n return schema;\n }\n }\n\n // Fall back to remote schema from GitHub (for skill schemas)\n const remoteUrl = REMOTE_SCHEMAS[schemaName];\n if (remoteUrl) {\n try {\n const response = await fetch(remoteUrl);\n if (response.ok) {\n const schema = await response.json();\n schemaCache.set(schemaName, schema);\n return schema;\n }\n } catch {\n // Fall through to error\n }\n }\n\n throw new Error(\n `Schema not found: ${schemaName}. Searched: ${locations.join(\", \")}${remoteUrl ? ` and ${remoteUrl}` : \"\"}`,\n );\n}\n\nasync function getValidator(schemaName: string): Promise<ValidateFunction> {\n if (validatorCache.has(schemaName)) {\n return validatorCache.get(schemaName)!;\n }\n\n const ajv = new Ajv({ allErrors: true, strict: false });\n addFormats(ajv);\n const schema = await loadSchema(schemaName);\n const validate = ajv.compile(schema);\n validatorCache.set(schemaName, validate);\n return validate;\n}\n\nfunction formatAjvErrors(errors: ErrorObject[] | null | undefined): string[] {\n if (!errors) return [];\n\n return errors.map((err) => {\n const errorPath = err.instancePath\n ? err.instancePath.replace(/^\\//, \"\").replace(/\\//g, \".\")\n : \"\";\n const message = err.message || \"Unknown error\";\n\n if (err.keyword === \"additionalProperties\") {\n const prop = (err.params as { additionalProperty?: string })\n .additionalProperty;\n return `Unrecognized key: \"${prop}\"`;\n }\n\n if (err.keyword === \"enum\") {\n const allowed = (err.params as { allowedValues?: string[] })\n .allowedValues;\n return errorPath\n ? `${errorPath}: ${message}. Allowed: ${allowed?.join(\", \")}`\n : `${message}. Allowed: ${allowed?.join(\", \")}`;\n }\n\n if (err.keyword === \"pattern\") {\n let hint = \"\";\n if (errorPath === \"name\") {\n hint = \" (must be kebab-case)\";\n } else if (errorPath === \"version\") {\n hint = \" (must be semver: x.y.z)\";\n }\n return errorPath\n ? `${errorPath}: ${message}${hint}`\n : `${message}${hint}`;\n }\n\n return errorPath ? `${errorPath}: ${message}` : message;\n });\n}\n\nfunction extractFrontmatter(content: string): unknown | null {\n const frontmatterRegex = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---/;\n const match = content.match(frontmatterRegex);\n\n if (!match || !match[1]) {\n return null;\n }\n\n try {\n return parseYaml(match[1]);\n } catch {\n return null;\n }\n}\n\nfunction isKebabCase(str: string): boolean {\n return KEBAB_CASE_REGEX.test(str);\n}\n\nfunction isValidSemver(str: string): boolean {\n return SEMVER_REGEX.test(str);\n}\n\nexport async function validatePluginStructure(\n pluginPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await directoryExists(pluginPath))) {\n return {\n valid: false,\n errors: [`Plugin directory does not exist: ${pluginPath}`],\n warnings: [],\n };\n }\n\n const pluginDir = path.join(pluginPath, PLUGIN_DIR);\n if (!(await directoryExists(pluginDir))) {\n errors.push(`Missing ${PLUGIN_DIR}/ directory`);\n }\n\n const manifestPath = path.join(pluginDir, PLUGIN_MANIFEST);\n if (!(await fileExists(manifestPath))) {\n errors.push(`Missing ${PLUGIN_DIR}/${PLUGIN_MANIFEST}`);\n }\n\n const readmePath = path.join(pluginPath, \"README.md\");\n if (!(await fileExists(readmePath))) {\n warnings.push(\"Missing README.md (recommended for documentation)\");\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validatePluginManifest(\n manifestPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(manifestPath))) {\n return {\n valid: false,\n errors: [`Manifest file not found: ${manifestPath}`],\n warnings: [],\n };\n }\n\n let manifest: Record<string, unknown>;\n try {\n const content = await readFile(manifestPath);\n manifest = JSON.parse(content);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n valid: false,\n errors: [`Invalid JSON in ${PLUGIN_MANIFEST}: ${message}`],\n warnings: [],\n };\n }\n\n const validate = await getValidator(\"plugin.schema.json\");\n const isValid = validate(manifest);\n\n if (!isValid) {\n errors.push(...formatAjvErrors(validate.errors));\n }\n\n if (manifest.name && typeof manifest.name === \"string\") {\n if (!isKebabCase(manifest.name)) {\n errors.push(`name must be kebab-case: \"${manifest.name}\"`);\n }\n }\n\n if (manifest.version && typeof manifest.version === \"string\") {\n if (!isValidSemver(manifest.version)) {\n warnings.push(\n `version \"${manifest.version}\" is not valid semver (expected: major.minor.patch)`,\n );\n }\n }\n\n if (!manifest.description) {\n warnings.push(\n \"Missing description field (recommended for discoverability)\",\n );\n }\n\n const pluginDir = path.dirname(path.dirname(manifestPath));\n\n if (manifest.skills && typeof manifest.skills === \"string\") {\n const skillsPath = path.join(pluginDir, manifest.skills);\n if (!(await directoryExists(skillsPath))) {\n errors.push(`Skills path does not exist: ${manifest.skills}`);\n }\n }\n\n if (manifest.agents && typeof manifest.agents === \"string\") {\n const agentsPath = path.join(pluginDir, manifest.agents);\n if (!(await directoryExists(agentsPath))) {\n errors.push(`Agents path does not exist: ${manifest.agents}`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateSkillFrontmatter(\n skillPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(skillPath))) {\n return {\n valid: false,\n errors: [`Skill file not found: ${skillPath}`],\n warnings: [],\n };\n }\n\n const content = await readFile(skillPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return {\n valid: false,\n errors: [\"Missing or invalid YAML frontmatter\"],\n warnings: [],\n };\n }\n\n const validate = await getValidator(\"skill-frontmatter.schema.json\");\n const isValid = validate(frontmatter);\n\n if (!isValid) {\n errors.push(...formatAjvErrors(validate.errors));\n }\n\n const fm = frontmatter as Record<string, unknown>;\n\n if (fm.category) {\n warnings.push(\n 'Deprecated field: \"category\" - use metadata.yaml for category information',\n );\n }\n if (fm.author) {\n warnings.push(\n 'Deprecated field: \"author\" - use metadata.yaml for author information',\n );\n }\n if (fm.version) {\n warnings.push(\n 'Deprecated field: \"version\" - use metadata.yaml for version information',\n );\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateAgentFrontmatter(\n agentPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n if (!(await fileExists(agentPath))) {\n return {\n valid: false,\n errors: [`Agent file not found: ${agentPath}`],\n warnings: [],\n };\n }\n\n const content = await readFile(agentPath);\n const frontmatter = extractFrontmatter(content);\n\n if (frontmatter === null) {\n return {\n valid: false,\n errors: [\"Missing or invalid YAML frontmatter\"],\n warnings: [],\n };\n }\n\n const validate = await getValidator(\"agent-frontmatter.schema.json\");\n const isValid = validate(frontmatter);\n\n if (!isValid) {\n errors.push(...formatAjvErrors(validate.errors));\n }\n\n const fm = frontmatter as Record<string, unknown>;\n\n if (fm.name && typeof fm.name === \"string\") {\n if (!isKebabCase(fm.name)) {\n errors.push(`name must be kebab-case: \"${fm.name}\"`);\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validatePlugin(\n pluginPath: string,\n): Promise<ValidationResult> {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const structureResult = await validatePluginStructure(pluginPath);\n errors.push(...structureResult.errors);\n warnings.push(...structureResult.warnings);\n\n if (!structureResult.valid) {\n return { valid: false, errors, warnings };\n }\n\n const manifestPath = path.join(pluginPath, PLUGIN_DIR, PLUGIN_MANIFEST);\n const manifestResult = await validatePluginManifest(manifestPath);\n errors.push(...manifestResult.errors);\n warnings.push(...manifestResult.warnings);\n\n let manifest: Record<string, unknown> | null = null;\n try {\n const content = await readFile(manifestPath);\n manifest = JSON.parse(content);\n } catch {}\n\n if (manifest) {\n if (manifest.skills && typeof manifest.skills === \"string\") {\n const skillsDir = path.join(pluginPath, manifest.skills);\n if (await directoryExists(skillsDir)) {\n const skillFiles = await fg(\"**/SKILL.md\", {\n cwd: skillsDir,\n absolute: true,\n });\n\n if (skillFiles.length === 0) {\n warnings.push(\n `Skills directory exists but contains no SKILL.md files: ${manifest.skills}`,\n );\n }\n\n for (const skillFile of skillFiles) {\n const relativePath = path.relative(pluginPath, skillFile);\n const skillResult = await validateSkillFrontmatter(skillFile);\n\n if (!skillResult.valid) {\n errors.push(\n ...skillResult.errors.map((e) => `${relativePath}: ${e}`),\n );\n }\n warnings.push(\n ...skillResult.warnings.map((w) => `${relativePath}: ${w}`),\n );\n }\n }\n }\n\n if (manifest.agents && typeof manifest.agents === \"string\") {\n const agentsDir = path.join(pluginPath, manifest.agents);\n if (await directoryExists(agentsDir)) {\n const agentFiles = await fg(\"*.md\", {\n cwd: agentsDir,\n absolute: true,\n });\n\n if (agentFiles.length === 0) {\n warnings.push(\n `Agents directory exists but contains no .md files: ${manifest.agents}`,\n );\n }\n\n for (const agentFile of agentFiles) {\n const relativePath = path.relative(pluginPath, agentFile);\n const agentResult = await validateAgentFrontmatter(agentFile);\n\n if (!agentResult.valid) {\n errors.push(\n ...agentResult.errors.map((e) => `${relativePath}: ${e}`),\n );\n }\n warnings.push(\n ...agentResult.warnings.map((w) => `${relativePath}: ${w}`),\n );\n }\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings,\n };\n}\n\nexport async function validateAllPlugins(pluginsDir: string): Promise<{\n valid: boolean;\n results: Array<{ name: string; result: ValidationResult }>;\n summary: {\n total: number;\n valid: number;\n invalid: number;\n withWarnings: number;\n };\n}> {\n const results: Array<{ name: string; result: ValidationResult }> = [];\n\n if (!(await directoryExists(pluginsDir))) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: {\n valid: false,\n errors: [`Directory does not exist: ${pluginsDir}`],\n warnings: [],\n },\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n const allDirs = await listDirectories(pluginsDir);\n const pluginDirs: string[] = [];\n\n for (const dirName of allDirs) {\n const potentialPluginDir = path.join(pluginsDir, dirName, PLUGIN_DIR);\n if (await directoryExists(potentialPluginDir)) {\n pluginDirs.push(dirName);\n }\n }\n\n if (pluginDirs.length === 0) {\n return {\n valid: false,\n results: [\n {\n name: pluginsDir,\n result: {\n valid: false,\n errors: [\n `No plugins found in directory: ${pluginsDir}. Plugins must contain a ${PLUGIN_DIR}/ directory.`,\n ],\n warnings: [],\n },\n },\n ],\n summary: { total: 0, valid: 0, invalid: 1, withWarnings: 0 },\n };\n }\n\n for (const pluginName of pluginDirs) {\n const pluginPath = path.join(pluginsDir, pluginName);\n const result = await validatePlugin(pluginPath);\n results.push({ name: pluginName, result });\n }\n\n const summary = {\n total: results.length,\n valid: results.filter((r) => r.result.valid).length,\n invalid: results.filter((r) => !r.result.valid).length,\n withWarnings: results.filter((r) => r.result.warnings.length > 0).length,\n };\n\n return {\n valid: summary.invalid === 0,\n results,\n summary,\n };\n}\n\nexport function printPluginValidationResult(\n name: string,\n result: ValidationResult,\n verbose = false,\n): void {\n const status = result.valid ? \"\\u2713\" : \"\\u2717\";\n\n if (result.valid && result.warnings.length === 0 && !verbose) {\n return;\n }\n\n console.log(`\\n ${status} ${name}`);\n\n if (result.errors.length > 0) {\n console.log(\" Errors:\");\n result.errors.forEach((e) => console.log(` - ${e}`));\n }\n\n if (result.warnings.length > 0) {\n console.log(\" Warnings:\");\n result.warnings.forEach((w) => console.log(` - ${w}`));\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA,OAAO,SAAsD;AAC7D,OAAO,gBAAgB;AACvB,OAAO,UAAU;AACjB,SAAS,SAAS,iBAAiB;AACnC,OAAO,QAAQ;AAUf,IAAM,aAAa;AACnB,IAAM,kBAAkB;AAExB,IAAM,mBAAmB;AACzB,IAAM,eACJ;AAEF,IAAM,cAAc,oBAAI,IAAoB;AAC5C,IAAM,iBAAiB,oBAAI,IAA8B;AAGzD,IAAM,iBAAyC;AAAA,EAC7C,iCACE;AACJ;AAEA,eAAe,WAAW,YAAqC;AAC7D,MAAI,YAAY,IAAI,UAAU,GAAG;AAC/B,WAAO,YAAY,IAAI,UAAU;AAAA,EACnC;AAGA,QAAM,YAAY;AAAA,IAChB,KAAK,KAAK,cAAc,OAAO,WAAW,UAAU;AAAA,IACpD,KAAK,KAAK,QAAQ,IAAI,GAAG,OAAO,WAAW,UAAU;AAAA,EACvD;AAEA,aAAW,cAAc,WAAW;AAClC,QAAI,MAAM,WAAW,UAAU,GAAG;AAChC,YAAM,UAAU,MAAM,SAAS,UAAU;AACzC,YAAM,SAAS,KAAK,MAAM,OAAO;AACjC,kBAAY,IAAI,YAAY,MAAM;AAClC,aAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,YAAY,eAAe,UAAU;AAC3C,MAAI,WAAW;AACb,QAAI;AACF,YAAM,WAAW,MAAM,MAAM,SAAS;AACtC,UAAI,SAAS,IAAI;AACf,cAAM,SAAS,MAAM,SAAS,KAAK;AACnC,oBAAY,IAAI,YAAY,MAAM;AAClC,eAAO;AAAA,MACT;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,QAAM,IAAI;AAAA,IACR,qBAAqB,UAAU,eAAe,UAAU,KAAK,IAAI,CAAC,GAAG,YAAY,QAAQ,SAAS,KAAK,EAAE;AAAA,EAC3G;AACF;AAEA,eAAe,aAAa,YAA+C;AACzE,MAAI,eAAe,IAAI,UAAU,GAAG;AAClC,WAAO,eAAe,IAAI,UAAU;AAAA,EACtC;AAEA,QAAM,MAAM,IAAI,IAAI,EAAE,WAAW,MAAM,QAAQ,MAAM,CAAC;AACtD,aAAW,GAAG;AACd,QAAM,SAAS,MAAM,WAAW,UAAU;AAC1C,QAAM,WAAW,IAAI,QAAQ,MAAM;AACnC,iBAAe,IAAI,YAAY,QAAQ;AACvC,SAAO;AACT;AAEA,SAAS,gBAAgB,QAAoD;AAC3E,MAAI,CAAC,OAAQ,QAAO,CAAC;AAErB,SAAO,OAAO,IAAI,CAAC,QAAQ;AACzB,UAAM,YAAY,IAAI,eAClB,IAAI,aAAa,QAAQ,OAAO,EAAE,EAAE,QAAQ,OAAO,GAAG,IACtD;AACJ,UAAM,UAAU,IAAI,WAAW;AAE/B,QAAI,IAAI,YAAY,wBAAwB;AAC1C,YAAM,OAAQ,IAAI,OACf;AACH,aAAO,sBAAsB,IAAI;AAAA,IACnC;AAEA,QAAI,IAAI,YAAY,QAAQ;AAC1B,YAAM,UAAW,IAAI,OAClB;AACH,aAAO,YACH,GAAG,SAAS,KAAK,OAAO,cAAc,SAAS,KAAK,IAAI,CAAC,KACzD,GAAG,OAAO,cAAc,SAAS,KAAK,IAAI,CAAC;AAAA,IACjD;AAEA,QAAI,IAAI,YAAY,WAAW;AAC7B,UAAI,OAAO;AACX,UAAI,cAAc,QAAQ;AACxB,eAAO;AAAA,MACT,WAAW,cAAc,WAAW;AAClC,eAAO;AAAA,MACT;AACA,aAAO,YACH,GAAG,SAAS,KAAK,OAAO,GAAG,IAAI,KAC/B,GAAG,OAAO,GAAG,IAAI;AAAA,IACvB;AAEA,WAAO,YAAY,GAAG,SAAS,KAAK,OAAO,KAAK;AAAA,EAClD,CAAC;AACH;AAEA,SAAS,mBAAmB,SAAiC;AAC3D,QAAM,mBAAmB;AACzB,QAAM,QAAQ,QAAQ,MAAM,gBAAgB;AAE5C,MAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,MAAI;AACF,WAAO,UAAU,MAAM,CAAC,CAAC;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,YAAY,KAAsB;AACzC,SAAO,iBAAiB,KAAK,GAAG;AAClC;AAEA,SAAS,cAAc,KAAsB;AAC3C,SAAO,aAAa,KAAK,GAAG;AAC9B;AAEA,eAAsB,wBACpB,YAC2B;AAC3B,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,gBAAgB,UAAU,GAAI;AACxC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,oCAAoC,UAAU,EAAE;AAAA,MACzD,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,YAAY,KAAK,KAAK,YAAY,UAAU;AAClD,MAAI,CAAE,MAAM,gBAAgB,SAAS,GAAI;AACvC,WAAO,KAAK,WAAW,UAAU,aAAa;AAAA,EAChD;AAEA,QAAM,eAAe,KAAK,KAAK,WAAW,eAAe;AACzD,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO,KAAK,WAAW,UAAU,IAAI,eAAe,EAAE;AAAA,EACxD;AAEA,QAAM,aAAa,KAAK,KAAK,YAAY,WAAW;AACpD,MAAI,CAAE,MAAM,WAAW,UAAU,GAAI;AACnC,aAAS,KAAK,mDAAmD;AAAA,EACnE;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,uBACpB,cAC2B;AAC3B,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,4BAA4B,YAAY,EAAE;AAAA,MACnD,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,eAAW,KAAK,MAAM,OAAO;AAAA,EAC/B,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,mBAAmB,eAAe,KAAK,OAAO,EAAE;AAAA,MACzD,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,aAAa,oBAAoB;AACxD,QAAM,UAAU,SAAS,QAAQ;AAEjC,MAAI,CAAC,SAAS;AACZ,WAAO,KAAK,GAAG,gBAAgB,SAAS,MAAM,CAAC;AAAA,EACjD;AAEA,MAAI,SAAS,QAAQ,OAAO,SAAS,SAAS,UAAU;AACtD,QAAI,CAAC,YAAY,SAAS,IAAI,GAAG;AAC/B,aAAO,KAAK,6BAA6B,SAAS,IAAI,GAAG;AAAA,IAC3D;AAAA,EACF;AAEA,MAAI,SAAS,WAAW,OAAO,SAAS,YAAY,UAAU;AAC5D,QAAI,CAAC,cAAc,SAAS,OAAO,GAAG;AACpC,eAAS;AAAA,QACP,YAAY,SAAS,OAAO;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAEA,MAAI,CAAC,SAAS,aAAa;AACzB,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,QAAM,YAAY,KAAK,QAAQ,KAAK,QAAQ,YAAY,CAAC;AAEzD,MAAI,SAAS,UAAU,OAAO,SAAS,WAAW,UAAU;AAC1D,UAAM,aAAa,KAAK,KAAK,WAAW,SAAS,MAAM;AACvD,QAAI,CAAE,MAAM,gBAAgB,UAAU,GAAI;AACxC,aAAO,KAAK,+BAA+B,SAAS,MAAM,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,MAAI,SAAS,UAAU,OAAO,SAAS,WAAW,UAAU;AAC1D,UAAM,aAAa,KAAK,KAAK,WAAW,SAAS,MAAM;AACvD,QAAI,CAAE,MAAM,gBAAgB,UAAU,GAAI;AACxC,aAAO,KAAK,+BAA+B,SAAS,MAAM,EAAE;AAAA,IAC9D;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,yBACpB,WAC2B;AAC3B,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,WAAW,SAAS,GAAI;AAClC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,yBAAyB,SAAS,EAAE;AAAA,MAC7C,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,SAAS,SAAS;AACxC,QAAM,cAAc,mBAAmB,OAAO;AAE9C,MAAI,gBAAgB,MAAM;AACxB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,qCAAqC;AAAA,MAC9C,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,aAAa,+BAA+B;AACnE,QAAM,UAAU,SAAS,WAAW;AAEpC,MAAI,CAAC,SAAS;AACZ,WAAO,KAAK,GAAG,gBAAgB,SAAS,MAAM,CAAC;AAAA,EACjD;AAEA,QAAM,KAAK;AAEX,MAAI,GAAG,UAAU;AACf,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACA,MAAI,GAAG,QAAQ;AACb,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACA,MAAI,GAAG,SAAS;AACd,aAAS;AAAA,MACP;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,yBACpB,WAC2B;AAC3B,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAE,MAAM,WAAW,SAAS,GAAI;AAClC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,yBAAyB,SAAS,EAAE;AAAA,MAC7C,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,SAAS,SAAS;AACxC,QAAM,cAAc,mBAAmB,OAAO;AAE9C,MAAI,gBAAgB,MAAM;AACxB,WAAO;AAAA,MACL,OAAO;AAAA,MACP,QAAQ,CAAC,qCAAqC;AAAA,MAC9C,UAAU,CAAC;AAAA,IACb;AAAA,EACF;AAEA,QAAM,WAAW,MAAM,aAAa,+BAA+B;AACnE,QAAM,UAAU,SAAS,WAAW;AAEpC,MAAI,CAAC,SAAS;AACZ,WAAO,KAAK,GAAG,gBAAgB,SAAS,MAAM,CAAC;AAAA,EACjD;AAEA,QAAM,KAAK;AAEX,MAAI,GAAG,QAAQ,OAAO,GAAG,SAAS,UAAU;AAC1C,QAAI,CAAC,YAAY,GAAG,IAAI,GAAG;AACzB,aAAO,KAAK,6BAA6B,GAAG,IAAI,GAAG;AAAA,IACrD;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,eACpB,YAC2B;AAC3B,QAAM,SAAmB,CAAC;AAC1B,QAAM,WAAqB,CAAC;AAE5B,QAAM,kBAAkB,MAAM,wBAAwB,UAAU;AAChE,SAAO,KAAK,GAAG,gBAAgB,MAAM;AACrC,WAAS,KAAK,GAAG,gBAAgB,QAAQ;AAEzC,MAAI,CAAC,gBAAgB,OAAO;AAC1B,WAAO,EAAE,OAAO,OAAO,QAAQ,SAAS;AAAA,EAC1C;AAEA,QAAM,eAAe,KAAK,KAAK,YAAY,YAAY,eAAe;AACtE,QAAM,iBAAiB,MAAM,uBAAuB,YAAY;AAChE,SAAO,KAAK,GAAG,eAAe,MAAM;AACpC,WAAS,KAAK,GAAG,eAAe,QAAQ;AAExC,MAAI,WAA2C;AAC/C,MAAI;AACF,UAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,eAAW,KAAK,MAAM,OAAO;AAAA,EAC/B,QAAQ;AAAA,EAAC;AAET,MAAI,UAAU;AACZ,QAAI,SAAS,UAAU,OAAO,SAAS,WAAW,UAAU;AAC1D,YAAM,YAAY,KAAK,KAAK,YAAY,SAAS,MAAM;AACvD,UAAI,MAAM,gBAAgB,SAAS,GAAG;AACpC,cAAM,aAAa,MAAM,GAAG,eAAe;AAAA,UACzC,KAAK;AAAA,UACL,UAAU;AAAA,QACZ,CAAC;AAED,YAAI,WAAW,WAAW,GAAG;AAC3B,mBAAS;AAAA,YACP,2DAA2D,SAAS,MAAM;AAAA,UAC5E;AAAA,QACF;AAEA,mBAAW,aAAa,YAAY;AAClC,gBAAM,eAAe,KAAK,SAAS,YAAY,SAAS;AACxD,gBAAM,cAAc,MAAM,yBAAyB,SAAS;AAE5D,cAAI,CAAC,YAAY,OAAO;AACtB,mBAAO;AAAA,cACL,GAAG,YAAY,OAAO,IAAI,CAAC,MAAM,GAAG,YAAY,KAAK,CAAC,EAAE;AAAA,YAC1D;AAAA,UACF;AACA,mBAAS;AAAA,YACP,GAAG,YAAY,SAAS,IAAI,CAAC,MAAM,GAAG,YAAY,KAAK,CAAC,EAAE;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,QAAI,SAAS,UAAU,OAAO,SAAS,WAAW,UAAU;AAC1D,YAAM,YAAY,KAAK,KAAK,YAAY,SAAS,MAAM;AACvD,UAAI,MAAM,gBAAgB,SAAS,GAAG;AACpC,cAAM,aAAa,MAAM,GAAG,QAAQ;AAAA,UAClC,KAAK;AAAA,UACL,UAAU;AAAA,QACZ,CAAC;AAED,YAAI,WAAW,WAAW,GAAG;AAC3B,mBAAS;AAAA,YACP,sDAAsD,SAAS,MAAM;AAAA,UACvE;AAAA,QACF;AAEA,mBAAW,aAAa,YAAY;AAClC,gBAAM,eAAe,KAAK,SAAS,YAAY,SAAS;AACxD,gBAAM,cAAc,MAAM,yBAAyB,SAAS;AAE5D,cAAI,CAAC,YAAY,OAAO;AACtB,mBAAO;AAAA,cACL,GAAG,YAAY,OAAO,IAAI,CAAC,MAAM,GAAG,YAAY,KAAK,CAAC,EAAE;AAAA,YAC1D;AAAA,UACF;AACA,mBAAS;AAAA,YACP,GAAG,YAAY,SAAS,IAAI,CAAC,MAAM,GAAG,YAAY,KAAK,CAAC,EAAE;AAAA,UAC5D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,OAAO,OAAO,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAsB,mBAAmB,YAStC;AACD,QAAM,UAA6D,CAAC;AAEpE,MAAI,CAAE,MAAM,gBAAgB,UAAU,GAAI;AACxC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,OAAO;AAAA,YACP,QAAQ,CAAC,6BAA6B,UAAU,EAAE;AAAA,YAClD,UAAU,CAAC;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,EAAE;AAAA,IAC7D;AAAA,EACF;AAEA,QAAM,UAAU,MAAM,gBAAgB,UAAU;AAChD,QAAM,aAAuB,CAAC;AAE9B,aAAW,WAAW,SAAS;AAC7B,UAAM,qBAAqB,KAAK,KAAK,YAAY,SAAS,UAAU;AACpE,QAAI,MAAM,gBAAgB,kBAAkB,GAAG;AAC7C,iBAAW,KAAK,OAAO;AAAA,IACzB;AAAA,EACF;AAEA,MAAI,WAAW,WAAW,GAAG;AAC3B,WAAO;AAAA,MACL,OAAO;AAAA,MACP,SAAS;AAAA,QACP;AAAA,UACE,MAAM;AAAA,UACN,QAAQ;AAAA,YACN,OAAO;AAAA,YACP,QAAQ;AAAA,cACN,kCAAkC,UAAU,4BAA4B,UAAU;AAAA,YACpF;AAAA,YACA,UAAU,CAAC;AAAA,UACb;AAAA,QACF;AAAA,MACF;AAAA,MACA,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,SAAS,GAAG,cAAc,EAAE;AAAA,IAC7D;AAAA,EACF;AAEA,aAAW,cAAc,YAAY;AACnC,UAAM,aAAa,KAAK,KAAK,YAAY,UAAU;AACnD,UAAM,SAAS,MAAM,eAAe,UAAU;AAC9C,YAAQ,KAAK,EAAE,MAAM,YAAY,OAAO,CAAC;AAAA,EAC3C;AAEA,QAAM,UAAU;AAAA,IACd,OAAO,QAAQ;AAAA,IACf,OAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE;AAAA,IAC7C,SAAS,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO,KAAK,EAAE;AAAA,IAChD,cAAc,QAAQ,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,SAAS,CAAC,EAAE;AAAA,EACpE;AAEA,SAAO;AAAA,IACL,OAAO,QAAQ,YAAY;AAAA,IAC3B;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,4BACd,MACA,QACA,UAAU,OACJ;AACN,QAAM,SAAS,OAAO,QAAQ,WAAW;AAEzC,MAAI,OAAO,SAAS,OAAO,SAAS,WAAW,KAAK,CAAC,SAAS;AAC5D;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,IAAO,MAAM,IAAI,IAAI,EAAE;AAEnC,MAAI,OAAO,OAAO,SAAS,GAAG;AAC5B,YAAQ,IAAI,aAAa;AACzB,WAAO,OAAO,QAAQ,CAAC,MAAM,QAAQ,IAAI,WAAW,CAAC,EAAE,CAAC;AAAA,EAC1D;AAEA,MAAI,OAAO,SAAS,SAAS,GAAG;AAC9B,YAAQ,IAAI,eAAe;AAC3B,WAAO,SAAS,QAAQ,CAAC,MAAM,QAAQ,IAAI,WAAW,CAAC,EAAE,CAAC;AAAA,EAC5D;AACF;","names":[]}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
readFile,
|
|
4
|
+
writeFile
|
|
5
|
+
} from "./chunk-TKFPKEV3.js";
|
|
2
6
|
import {
|
|
3
7
|
DEFAULT_VERSION,
|
|
4
8
|
PLUGIN_MANIFEST_DIR,
|
|
5
9
|
PLUGIN_MANIFEST_FILE
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
readFile,
|
|
9
|
-
writeFile
|
|
10
|
-
} from "./chunk-MMDXNZPF.js";
|
|
10
|
+
} from "./chunk-76DWXGQE.js";
|
|
11
11
|
import {
|
|
12
12
|
init_esm_shims
|
|
13
13
|
} from "./chunk-DHET7RCE.js";
|
|
14
14
|
|
|
15
|
-
// src/cli
|
|
15
|
+
// src/cli/lib/plugin-version.ts
|
|
16
16
|
init_esm_shims();
|
|
17
17
|
import path from "path";
|
|
18
18
|
function parseVersion(version) {
|
|
@@ -61,4 +61,4 @@ export {
|
|
|
61
61
|
bumpPluginVersion,
|
|
62
62
|
getPluginVersion
|
|
63
63
|
};
|
|
64
|
-
//# sourceMappingURL=chunk-
|
|
64
|
+
//# sourceMappingURL=chunk-P26A2K5N.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/plugin-version.ts"],"sourcesContent":["import path from \"path\";\nimport { readFile, writeFile } from \"../utils/fs\";\nimport {\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n DEFAULT_VERSION,\n} from \"../consts\";\nimport type { PluginManifest } from \"../../types\";\n\nexport type VersionBumpType = \"major\" | \"minor\" | \"patch\";\n\nfunction parseVersion(version: string): [number, number, number] {\n const parts = version.split(\".\").map(Number);\n return [parts[0] || 1, parts[1] || 0, parts[2] || 0];\n}\n\nexport async function bumpPluginVersion(\n pluginDir: string,\n type: VersionBumpType,\n): Promise<string> {\n const manifestPath = path.join(\n pluginDir,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n );\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n\n const [major, minor, patch] = parseVersion(\n manifest.version || DEFAULT_VERSION,\n );\n\n let newVersion: string;\n switch (type) {\n case \"major\":\n newVersion = `${major + 1}.0.0`;\n break;\n case \"minor\":\n newVersion = `${major}.${minor + 1}.0`;\n break;\n case \"patch\":\n newVersion = `${major}.${minor}.${patch + 1}`;\n break;\n }\n\n manifest.version = newVersion;\n await writeFile(manifestPath, JSON.stringify(manifest, null, 2));\n\n return newVersion;\n}\n\nexport async function getPluginVersion(pluginDir: string): Promise<string> {\n const manifestPath = path.join(\n pluginDir,\n PLUGIN_MANIFEST_DIR,\n PLUGIN_MANIFEST_FILE,\n );\n const content = await readFile(manifestPath);\n const manifest = JSON.parse(content) as PluginManifest;\n return manifest.version || DEFAULT_VERSION;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AAWjB,SAAS,aAAa,SAA2C;AAC/D,QAAM,QAAQ,QAAQ,MAAM,GAAG,EAAE,IAAI,MAAM;AAC3C,SAAO,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AACrD;AAEA,eAAsB,kBACpB,WACA,MACiB;AACjB,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,KAAK,MAAM,OAAO;AAEnC,QAAM,CAAC,OAAO,OAAO,KAAK,IAAI;AAAA,IAC5B,SAAS,WAAW;AAAA,EACtB;AAEA,MAAI;AACJ,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,mBAAa,GAAG,QAAQ,CAAC;AACzB;AAAA,IACF,KAAK;AACH,mBAAa,GAAG,KAAK,IAAI,QAAQ,CAAC;AAClC;AAAA,IACF,KAAK;AACH,mBAAa,GAAG,KAAK,IAAI,KAAK,IAAI,QAAQ,CAAC;AAC3C;AAAA,EACJ;AAEA,WAAS,UAAU;AACnB,QAAM,UAAU,cAAc,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAE/D,SAAO;AACT;AAEA,eAAsB,iBAAiB,WAAoC;AACzE,QAAM,eAAe,KAAK;AAAA,IACxB;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,KAAK,MAAM,OAAO;AACnC,SAAO,SAAS,WAAW;AAC7B;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
init_esm_shims
|
|
4
4
|
} from "./chunk-DHET7RCE.js";
|
|
5
5
|
|
|
6
|
-
// src/cli
|
|
6
|
+
// src/cli/components/common/confirm.tsx
|
|
7
7
|
init_esm_shims();
|
|
8
8
|
import { Box, Text } from "ink";
|
|
9
9
|
import { ConfirmInput } from "@inkjs/ui";
|
|
@@ -28,4 +28,4 @@ var Confirm = ({
|
|
|
28
28
|
export {
|
|
29
29
|
Confirm
|
|
30
30
|
};
|
|
31
|
-
//# sourceMappingURL=chunk-
|
|
31
|
+
//# sourceMappingURL=chunk-RTE64SJA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/components/common/confirm.tsx"],"sourcesContent":["import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { ConfirmInput } from \"@inkjs/ui\";\n\ninterface ConfirmProps {\n message: string;\n onConfirm: () => void;\n onCancel: () => void;\n defaultValue?: boolean;\n}\n\nexport const Confirm: React.FC<ConfirmProps> = ({\n message,\n onConfirm,\n onCancel,\n defaultValue = false,\n}) => (\n <Box flexDirection=\"column\">\n <Text>{message}</Text>\n <ConfirmInput\n onConfirm={onConfirm}\n onCancel={onCancel}\n defaultChoice={defaultValue ? \"confirm\" : \"cancel\"}\n />\n </Box>\n);\n"],"mappings":";;;;;;AAAA;AACA,SAAS,KAAK,YAAY;AAC1B,SAAS,oBAAoB;AAe3B,SACE,KADF;AANK,IAAM,UAAkC,CAAC;AAAA,EAC9C;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,MACE,qBAAC,OAAI,eAAc,UACjB;AAAA,sBAAC,QAAM,mBAAQ;AAAA,EACf;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,eAAe,eAAe,YAAY;AAAA;AAAA,EAC5C;AAAA,GACF;","names":[]}
|
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadProjectConfig
|
|
4
|
-
} from "./chunk-MYAVQ23U.js";
|
|
5
2
|
import {
|
|
6
3
|
getCollectivePluginDir
|
|
7
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ED4E6Q2T.js";
|
|
8
5
|
import {
|
|
9
|
-
|
|
10
|
-
} from "./chunk-
|
|
6
|
+
loadProjectConfig
|
|
7
|
+
} from "./chunk-CJEHB4TB.js";
|
|
11
8
|
import {
|
|
12
9
|
directoryExists,
|
|
13
10
|
fileExists
|
|
14
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-TKFPKEV3.js";
|
|
12
|
+
import {
|
|
13
|
+
CLAUDE_DIR,
|
|
14
|
+
CLAUDE_SRC_DIR
|
|
15
|
+
} from "./chunk-76DWXGQE.js";
|
|
15
16
|
import {
|
|
16
17
|
init_esm_shims
|
|
17
18
|
} from "./chunk-DHET7RCE.js";
|
|
18
19
|
|
|
19
|
-
// src/cli
|
|
20
|
+
// src/cli/lib/installation.ts
|
|
20
21
|
init_esm_shims();
|
|
21
22
|
import path from "path";
|
|
22
23
|
async function detectInstallation(projectDir = process.cwd()) {
|
|
23
|
-
const
|
|
24
|
-
|
|
24
|
+
const srcConfigPath = path.join(projectDir, CLAUDE_SRC_DIR, "config.yaml");
|
|
25
|
+
const legacyConfigPath = path.join(projectDir, CLAUDE_DIR, "config.yaml");
|
|
26
|
+
const localConfigPath = await fileExists(srcConfigPath) ? srcConfigPath : await fileExists(legacyConfigPath) ? legacyConfigPath : null;
|
|
27
|
+
if (localConfigPath) {
|
|
25
28
|
const loaded = await loadProjectConfig(projectDir);
|
|
26
29
|
const mode = loaded?.config?.installMode ?? "local";
|
|
27
30
|
if (mode === "local") {
|
|
@@ -51,4 +54,4 @@ async function detectInstallation(projectDir = process.cwd()) {
|
|
|
51
54
|
export {
|
|
52
55
|
detectInstallation
|
|
53
56
|
};
|
|
54
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-SGJ23HIP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/installation.ts"],"sourcesContent":["/**\n * Installation detection utilities for Claude Collective.\n *\n * Detects whether a project uses local mode (.claude-src/config.yaml) or\n * plugin mode (.claude/plugins/claude-collective/).\n */\nimport path from \"path\";\nimport { directoryExists, fileExists } from \"../utils/fs\";\nimport { loadProjectConfig } from \"./project-config\";\nimport { getCollectivePluginDir } from \"./plugin-finder\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\n\nexport type InstallMode = \"local\" | \"plugin\";\n\nexport interface Installation {\n mode: InstallMode;\n configPath: string;\n agentsDir: string;\n skillsDir: string;\n projectDir: string;\n}\n\n/**\n * Detect the current installation mode by checking for local config first.\n * Priority: Local (.claude-src/config.yaml with installMode: local) > Plugin\n */\nexport async function detectInstallation(\n projectDir: string = process.cwd(),\n): Promise<Installation | null> {\n // 1. Check for local installation first\n // Check .claude-src/config.yaml first (new location)\n const srcConfigPath = path.join(projectDir, CLAUDE_SRC_DIR, \"config.yaml\");\n // Fall back to .claude/config.yaml (legacy location)\n const legacyConfigPath = path.join(projectDir, CLAUDE_DIR, \"config.yaml\");\n\n const localConfigPath = (await fileExists(srcConfigPath))\n ? srcConfigPath\n : (await fileExists(legacyConfigPath))\n ? legacyConfigPath\n : null;\n\n if (localConfigPath) {\n const loaded = await loadProjectConfig(projectDir);\n\n // If config exists and has installMode: local (or no installMode, defaults to local)\n // treat it as local mode\n const mode: InstallMode = loaded?.config?.installMode ?? \"local\";\n\n if (mode === \"local\") {\n return {\n mode: \"local\",\n configPath: localConfigPath,\n agentsDir: path.join(projectDir, CLAUDE_DIR, \"agents\"),\n skillsDir: path.join(projectDir, CLAUDE_DIR, \"skills\"),\n projectDir,\n };\n }\n }\n\n // 2. Check for plugin installation\n const pluginDir = getCollectivePluginDir(projectDir);\n const pluginConfigPath = path.join(pluginDir, \"config.yaml\");\n\n if (await directoryExists(pluginDir)) {\n return {\n mode: \"plugin\",\n configPath: pluginConfigPath,\n agentsDir: path.join(pluginDir, \"agents\"),\n skillsDir: path.join(pluginDir, \"skills\"),\n projectDir,\n };\n }\n\n // No installation found\n return null;\n}\n\n/**\n * Get installation or throw with helpful error message\n */\nexport async function getInstallationOrThrow(\n projectDir: string = process.cwd(),\n): Promise<Installation> {\n const installation = await detectInstallation(projectDir);\n\n if (!installation) {\n throw new Error(\n \"No Claude Collective installation found.\\n\" +\n \"Run 'cc init' to create one.\",\n );\n }\n\n return installation;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAMA,OAAO,UAAU;AAoBjB,eAAsB,mBACpB,aAAqB,QAAQ,IAAI,GACH;AAG9B,QAAM,gBAAgB,KAAK,KAAK,YAAY,gBAAgB,aAAa;AAEzE,QAAM,mBAAmB,KAAK,KAAK,YAAY,YAAY,aAAa;AAExE,QAAM,kBAAmB,MAAM,WAAW,aAAa,IACnD,gBACC,MAAM,WAAW,gBAAgB,IAChC,mBACA;AAEN,MAAI,iBAAiB;AACnB,UAAM,SAAS,MAAM,kBAAkB,UAAU;AAIjD,UAAM,OAAoB,QAAQ,QAAQ,eAAe;AAEzD,QAAI,SAAS,SAAS;AACpB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,WAAW,KAAK,KAAK,YAAY,YAAY,QAAQ;AAAA,QACrD,WAAW,KAAK,KAAK,YAAY,YAAY,QAAQ;AAAA,QACrD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAGA,QAAM,YAAY,uBAAuB,UAAU;AACnD,QAAM,mBAAmB,KAAK,KAAK,WAAW,aAAa;AAE3D,MAAI,MAAM,gBAAgB,SAAS,GAAG;AACpC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,WAAW,KAAK,KAAK,WAAW,QAAQ;AAAA,MACxC,WAAW,KAAK,KAAK,WAAW,QAAQ;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAGA,SAAO;AACT;","names":[]}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
fetchFromSource
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
CLAUDE_DIR,
|
|
7
|
-
DIRS,
|
|
8
|
-
PROJECT_ROOT
|
|
9
|
-
} from "./chunk-SJYG4EJZ.js";
|
|
4
|
+
} from "./chunk-IMDW5ZUP.js";
|
|
10
5
|
import {
|
|
11
6
|
verbose
|
|
12
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3U3R4NCG.js";
|
|
13
8
|
import {
|
|
14
9
|
directoryExists
|
|
15
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TKFPKEV3.js";
|
|
11
|
+
import {
|
|
12
|
+
CLAUDE_DIR,
|
|
13
|
+
DIRS,
|
|
14
|
+
PROJECT_ROOT
|
|
15
|
+
} from "./chunk-76DWXGQE.js";
|
|
16
16
|
import {
|
|
17
17
|
init_esm_shims
|
|
18
18
|
} from "./chunk-DHET7RCE.js";
|
|
19
19
|
|
|
20
|
-
// src/cli
|
|
20
|
+
// src/cli/lib/agent-fetcher.ts
|
|
21
21
|
init_esm_shims();
|
|
22
22
|
import path from "path";
|
|
23
23
|
async function getAgentDefinitions(remoteSource, options = {}) {
|
|
@@ -81,4 +81,4 @@ async function fetchAgentDefinitionsFromRemote(source, options = {}) {
|
|
|
81
81
|
export {
|
|
82
82
|
getAgentDefinitions
|
|
83
83
|
};
|
|
84
|
-
//# sourceMappingURL=chunk-
|
|
84
|
+
//# sourceMappingURL=chunk-SVYPSDWY.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/agent-fetcher.ts"],"sourcesContent":["import path from \"path\";\nimport { directoryExists } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { PROJECT_ROOT, DIRS, CLAUDE_DIR } from \"../consts\";\nimport { fetchFromSource, type FetchOptions } from \"./source-fetcher\";\nimport type { AgentSourcePaths } from \"../../types\";\n\nexport interface AgentDefinitionOptions extends FetchOptions {\n /** Project directory to check for local templates */\n projectDir?: string;\n}\n\nexport async function getAgentDefinitions(\n remoteSource?: string,\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n if (remoteSource) {\n return fetchAgentDefinitionsFromRemote(remoteSource, options);\n }\n return getLocalAgentDefinitions(options);\n}\n\nexport async function getLocalAgentDefinitions(\n options: AgentDefinitionOptions = {},\n): Promise<AgentSourcePaths> {\n const agentsDir = path.join(PROJECT_ROOT, DIRS.agents);\n let templatesDir = path.join(PROJECT_ROOT, DIRS.templates);\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(\n `Agent partials not found at: ${agentsDir}. ` +\n `Ensure the CLI is properly installed.`,\n );\n }\n\n // Check for local templates first (from eject templates)\n if (options.projectDir) {\n const localTemplatesDir = path.join(\n options.projectDir,\n CLAUDE_DIR,\n \"templates\",\n );\n if (await directoryExists(localTemplatesDir)) {\n verbose(`Using local templates from: ${localTemplatesDir}`);\n templatesDir = localTemplatesDir;\n }\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials loaded from CLI: ${agentsDir}`);\n verbose(`Templates directory: ${templatesDir}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: PROJECT_ROOT,\n };\n}\n\nexport async function fetchAgentDefinitionsFromRemote(\n source: string,\n options: FetchOptions = {},\n): Promise<AgentSourcePaths> {\n verbose(`Fetching agent partials from remote: ${source}`);\n\n const result = await fetchFromSource(source, {\n forceRefresh: options.forceRefresh,\n subdir: \"\",\n });\n\n const agentsDir = path.join(result.path, \"src\", \"agents\");\n const templatesDir = path.join(agentsDir, \"_templates\");\n\n if (!(await directoryExists(agentsDir))) {\n throw new Error(`Agent partials not found at: ${agentsDir}`);\n }\n\n if (!(await directoryExists(templatesDir))) {\n verbose(`Templates directory not found: ${templatesDir}`);\n }\n\n verbose(`Agent partials fetched from: ${result.path}`);\n\n return {\n agentsDir,\n templatesDir,\n sourcePath: result.path,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA,OAAO,UAAU;AAYjB,eAAsB,oBACpB,cACA,UAAkC,CAAC,GACR;AAC3B,MAAI,cAAc;AAChB,WAAO,gCAAgC,cAAc,OAAO;AAAA,EAC9D;AACA,SAAO,yBAAyB,OAAO;AACzC;AAEA,eAAsB,yBACpB,UAAkC,CAAC,GACR;AAC3B,QAAM,YAAY,KAAK,KAAK,cAAc,KAAK,MAAM;AACrD,MAAI,eAAe,KAAK,KAAK,cAAc,KAAK,SAAS;AAEzD,MAAI,CAAE,MAAM,gBAAgB,SAAS,GAAI;AACvC,UAAM,IAAI;AAAA,MACR,gCAAgC,SAAS;AAAA,IAE3C;AAAA,EACF;AAGA,MAAI,QAAQ,YAAY;AACtB,UAAM,oBAAoB,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AACA,QAAI,MAAM,gBAAgB,iBAAiB,GAAG;AAC5C,cAAQ,+BAA+B,iBAAiB,EAAE;AAC1D,qBAAe;AAAA,IACjB;AAAA,EACF;AAEA,MAAI,CAAE,MAAM,gBAAgB,YAAY,GAAI;AAC1C,YAAQ,kCAAkC,YAAY,EAAE;AAAA,EAC1D;AAEA,UAAQ,mCAAmC,SAAS,EAAE;AACtD,UAAQ,wBAAwB,YAAY,EAAE;AAE9C,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY;AAAA,EACd;AACF;AAEA,eAAsB,gCACpB,QACA,UAAwB,CAAC,GACE;AAC3B,UAAQ,wCAAwC,MAAM,EAAE;AAExD,QAAM,SAAS,MAAM,gBAAgB,QAAQ;AAAA,IAC3C,cAAc,QAAQ;AAAA,IACtB,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,YAAY,KAAK,KAAK,OAAO,MAAM,OAAO,QAAQ;AACxD,QAAM,eAAe,KAAK,KAAK,WAAW,YAAY;AAEtD,MAAI,CAAE,MAAM,gBAAgB,SAAS,GAAI;AACvC,UAAM,IAAI,MAAM,gCAAgC,SAAS,EAAE;AAAA,EAC7D;AAEA,MAAI,CAAE,MAAM,gBAAgB,YAAY,GAAI;AAC1C,YAAQ,kCAAkC,YAAY,EAAE;AAAA,EAC1D;AAEA,UAAQ,gCAAgC,OAAO,IAAI,EAAE;AAErD,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,YAAY,OAAO;AAAA,EACrB;AACF;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
init_esm_shims
|
|
4
4
|
} from "./chunk-DHET7RCE.js";
|
|
5
5
|
|
|
6
|
-
// src/cli
|
|
6
|
+
// src/cli/utils/fs.ts
|
|
7
7
|
init_esm_shims();
|
|
8
8
|
import fs from "fs-extra";
|
|
9
9
|
import fg from "fast-glob";
|
|
@@ -66,4 +66,4 @@ export {
|
|
|
66
66
|
remove,
|
|
67
67
|
copy
|
|
68
68
|
};
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
69
|
+
//# sourceMappingURL=chunk-TKFPKEV3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/utils/fs.ts"],"sourcesContent":["import fs from \"fs-extra\";\nimport fg from \"fast-glob\";\nimport path from \"path\";\n\nexport async function readFile(filePath: string): Promise<string> {\n return fs.readFile(filePath, \"utf-8\");\n}\n\nexport async function readFileOptional(\n filePath: string,\n fallback = \"\",\n): Promise<string> {\n try {\n return await fs.readFile(filePath, \"utf-8\");\n } catch {\n return fallback;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n return fs.pathExists(filePath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function listDirectories(dirPath: string): Promise<string[]> {\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n return entries.filter((e) => e.isDirectory()).map((e) => e.name);\n } catch {\n return [];\n }\n}\n\nexport async function glob(pattern: string, cwd: string): Promise<string[]> {\n return fg(pattern, { cwd, onlyFiles: true });\n}\n\nexport async function writeFile(\n filePath: string,\n content: string,\n): Promise<void> {\n await fs.ensureDir(path.dirname(filePath));\n await fs.writeFile(filePath, content, \"utf-8\");\n}\n\nexport async function ensureDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function remove(filePath: string): Promise<void> {\n await fs.remove(filePath);\n}\n\nexport async function copy(src: string, dest: string): Promise<void> {\n await fs.copy(src, dest);\n}\n"],"mappings":";;;;;;AAAA;AAAA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,eAAsB,SAAS,UAAmC;AAChE,SAAO,GAAG,SAAS,UAAU,OAAO;AACtC;AAEA,eAAsB,iBACpB,UACA,WAAW,IACM;AACjB,MAAI;AACF,WAAO,MAAM,GAAG,SAAS,UAAU,OAAO;AAAA,EAC5C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,WAAW,UAAoC;AACnE,SAAO,GAAG,WAAW,QAAQ;AAC/B;AAEA,eAAsB,gBAAgB,SAAmC;AACvE,MAAI;AACF,UAAM,OAAO,MAAM,GAAG,KAAK,OAAO;AAClC,WAAO,KAAK,YAAY;AAAA,EAC1B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,gBAAgB,SAAoC;AACxE,MAAI;AACF,UAAM,UAAU,MAAM,GAAG,QAAQ,SAAS,EAAE,eAAe,KAAK,CAAC;AACjE,WAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,EACjE,QAAQ;AACN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,eAAsB,KAAK,SAAiB,KAAgC;AAC1E,SAAO,GAAG,SAAS,EAAE,KAAK,WAAW,KAAK,CAAC;AAC7C;AAEA,eAAsB,UACpB,UACA,SACe;AACf,QAAM,GAAG,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACzC,QAAM,GAAG,UAAU,UAAU,SAAS,OAAO;AAC/C;AAEA,eAAsB,UAAU,SAAgC;AAC9D,QAAM,GAAG,UAAU,OAAO;AAC5B;AAEA,eAAsB,OAAO,UAAiC;AAC5D,QAAM,GAAG,OAAO,QAAQ;AAC1B;AAEA,eAAsB,KAAK,KAAa,MAA6B;AACnE,QAAM,GAAG,KAAK,KAAK,IAAI;AACzB;","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
init_esm_shims
|
|
4
4
|
} from "./chunk-DHET7RCE.js";
|
|
5
5
|
|
|
6
|
-
// src/cli
|
|
6
|
+
// src/cli/utils/exec.ts
|
|
7
7
|
init_esm_shims();
|
|
8
8
|
import { spawn } from "child_process";
|
|
9
9
|
async function execCommand(command, args, options) {
|
|
@@ -105,4 +105,4 @@ export {
|
|
|
105
105
|
claudePluginMarketplaceAdd,
|
|
106
106
|
claudePluginUninstall
|
|
107
107
|
};
|
|
108
|
-
//# sourceMappingURL=chunk-
|
|
108
|
+
//# sourceMappingURL=chunk-UQTEPWU7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/utils/exec.ts"],"sourcesContent":["import { spawn } from \"child_process\";\n\nexport interface ExecResult {\n stdout: string;\n stderr: string;\n exitCode: number;\n}\n\n/**\n * Execute a command and return the result\n */\nexport async function execCommand(\n command: string,\n args: string[],\n options?: { cwd?: string; env?: NodeJS.ProcessEnv },\n): Promise<ExecResult> {\n return new Promise((resolve, reject) => {\n const proc = spawn(command, args, {\n cwd: options?.cwd,\n env: { ...process.env, ...options?.env },\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n });\n\n let stdout = \"\";\n let stderr = \"\";\n\n proc.stdout.on(\"data\", (data) => {\n stdout += data.toString();\n });\n\n proc.stderr.on(\"data\", (data) => {\n stderr += data.toString();\n });\n\n proc.on(\"close\", (code) => {\n resolve({\n stdout,\n stderr,\n exitCode: code ?? 1,\n });\n });\n\n proc.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Install a plugin using the native claude CLI\n */\nexport async function claudePluginInstall(\n pluginPath: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"install\", pluginPath, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n throw new Error(`Plugin installation failed: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Check if the claude CLI is available\n */\nexport async function isClaudeCLIAvailable(): Promise<boolean> {\n try {\n const result = await execCommand(\"claude\", [\"--version\"], {});\n return result.exitCode === 0;\n } catch {\n return false;\n }\n}\n\nexport interface MarketplaceInfo {\n name: string;\n source: string;\n repo?: string;\n path?: string;\n}\n\n/**\n * List configured marketplaces in Claude Code\n */\nexport async function claudePluginMarketplaceList(): Promise<\n MarketplaceInfo[]\n> {\n try {\n const result = await execCommand(\n \"claude\",\n [\"plugin\", \"marketplace\", \"list\", \"--json\"],\n {},\n );\n\n if (result.exitCode !== 0) {\n return [];\n }\n\n return JSON.parse(result.stdout);\n } catch {\n // Returns empty array if claude CLI is not available or parsing fails\n return [];\n }\n}\n\n/**\n * Check if a marketplace with the given name exists\n */\nexport async function claudePluginMarketplaceExists(\n name: string,\n): Promise<boolean> {\n const marketplaces = await claudePluginMarketplaceList();\n return marketplaces.some((m) => m.name === name);\n}\n\n/**\n * Add a marketplace to Claude Code from a GitHub repository\n */\nexport async function claudePluginMarketplaceAdd(\n githubRepo: string,\n name: string,\n): Promise<void> {\n const args = [\"plugin\", \"marketplace\", \"add\", githubRepo, \"--name\", name];\n let result;\n try {\n result = await execCommand(\"claude\", args, {});\n } catch (err) {\n throw new Error(\n `Failed to add marketplace: ${err instanceof Error ? err.message : \"Unknown error\"}`,\n );\n }\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n if (errorMessage.includes(\"already installed\")) {\n return;\n }\n throw new Error(`Failed to add marketplace: ${errorMessage.trim()}`);\n }\n}\n\n/**\n * Uninstall a plugin using the native claude CLI\n */\nexport async function claudePluginUninstall(\n pluginName: string,\n scope: \"project\" | \"user\",\n projectDir: string,\n): Promise<void> {\n const args = [\"plugin\", \"uninstall\", pluginName, \"--scope\", scope];\n const result = await execCommand(\"claude\", args, { cwd: projectDir });\n\n if (result.exitCode !== 0) {\n const errorMessage = result.stderr || result.stdout || \"Unknown error\";\n // Ignore \"not installed\" errors - plugin may already be removed\n if (\n errorMessage.includes(\"not installed\") ||\n errorMessage.includes(\"not found\")\n ) {\n return;\n }\n throw new Error(`Plugin uninstall failed: ${errorMessage.trim()}`);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
verbose
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-3U3R4NCG.js";
|
|
5
5
|
import {
|
|
6
6
|
ensureDir,
|
|
7
7
|
fileExists,
|
|
8
8
|
readFile,
|
|
9
9
|
writeFile
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-TKFPKEV3.js";
|
|
11
|
+
import {
|
|
12
|
+
CLAUDE_DIR,
|
|
13
|
+
CLAUDE_SRC_DIR
|
|
14
|
+
} from "./chunk-76DWXGQE.js";
|
|
11
15
|
import {
|
|
12
16
|
init_esm_shims
|
|
13
17
|
} from "./chunk-DHET7RCE.js";
|
|
14
18
|
|
|
15
|
-
// src/cli
|
|
19
|
+
// src/cli/lib/config.ts
|
|
16
20
|
init_esm_shims();
|
|
17
21
|
import path from "path";
|
|
18
22
|
import os from "os";
|
|
19
23
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
20
|
-
var PROJECT_CONFIG_DIR = ".claude-collective";
|
|
21
24
|
var DEFAULT_SOURCE = "github:claude-collective/skills";
|
|
22
25
|
var SOURCE_ENV_VAR = "CC_SOURCE";
|
|
23
26
|
var CONFIG_HOME_ENV_VAR = "CC_CONFIG_HOME";
|
|
@@ -27,6 +30,19 @@ function getGlobalConfigDir() {
|
|
|
27
30
|
return process.env[CONFIG_HOME_ENV_VAR] || path.join(os.homedir(), ".claude-collective");
|
|
28
31
|
}
|
|
29
32
|
var GLOBAL_CONFIG_DIR = path.join(os.homedir(), ".claude-collective");
|
|
33
|
+
function isValidSourceEntry(entry) {
|
|
34
|
+
if (typeof entry !== "object" || entry === null) return false;
|
|
35
|
+
const e = entry;
|
|
36
|
+
if (typeof e.name !== "string" || typeof e.url !== "string") return false;
|
|
37
|
+
if (e.description !== void 0 && typeof e.description !== "string")
|
|
38
|
+
return false;
|
|
39
|
+
if (e.ref !== void 0 && typeof e.ref !== "string") return false;
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
function isValidSourcesArray(arr) {
|
|
43
|
+
if (!Array.isArray(arr)) return false;
|
|
44
|
+
return arr.every(isValidSourceEntry);
|
|
45
|
+
}
|
|
30
46
|
function isValidGlobalConfig(obj) {
|
|
31
47
|
if (typeof obj !== "object" || obj === null) return false;
|
|
32
48
|
const config = obj;
|
|
@@ -38,6 +54,8 @@ function isValidGlobalConfig(obj) {
|
|
|
38
54
|
return false;
|
|
39
55
|
if (config.agents_source !== void 0 && typeof config.agents_source !== "string")
|
|
40
56
|
return false;
|
|
57
|
+
if (config.sources !== void 0 && !isValidSourcesArray(config.sources))
|
|
58
|
+
return false;
|
|
41
59
|
return true;
|
|
42
60
|
}
|
|
43
61
|
function isValidProjectConfig(obj) {
|
|
@@ -45,17 +63,21 @@ function isValidProjectConfig(obj) {
|
|
|
45
63
|
const config = obj;
|
|
46
64
|
if (config.source !== void 0 && typeof config.source !== "string")
|
|
47
65
|
return false;
|
|
66
|
+
if (config.author !== void 0 && typeof config.author !== "string")
|
|
67
|
+
return false;
|
|
48
68
|
if (config.marketplace !== void 0 && typeof config.marketplace !== "string")
|
|
49
69
|
return false;
|
|
50
70
|
if (config.agents_source !== void 0 && typeof config.agents_source !== "string")
|
|
51
71
|
return false;
|
|
72
|
+
if (config.sources !== void 0 && !isValidSourcesArray(config.sources))
|
|
73
|
+
return false;
|
|
52
74
|
return true;
|
|
53
75
|
}
|
|
54
76
|
function getGlobalConfigPath() {
|
|
55
77
|
return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);
|
|
56
78
|
}
|
|
57
79
|
function getProjectConfigPath(projectDir) {
|
|
58
|
-
return path.join(projectDir,
|
|
80
|
+
return path.join(projectDir, CLAUDE_SRC_DIR, PROJECT_CONFIG_FILE);
|
|
59
81
|
}
|
|
60
82
|
async function loadGlobalConfig() {
|
|
61
83
|
const configPath = getGlobalConfigPath();
|
|
@@ -78,10 +100,19 @@ async function loadGlobalConfig() {
|
|
|
78
100
|
}
|
|
79
101
|
}
|
|
80
102
|
async function loadProjectConfig(projectDir) {
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
103
|
+
const srcConfigPath = getProjectConfigPath(projectDir);
|
|
104
|
+
const legacyConfigPath = path.join(projectDir, CLAUDE_DIR, "config.yaml");
|
|
105
|
+
let configPath = srcConfigPath;
|
|
106
|
+
if (!await fileExists(srcConfigPath)) {
|
|
107
|
+
if (await fileExists(legacyConfigPath)) {
|
|
108
|
+
configPath = legacyConfigPath;
|
|
109
|
+
verbose(`Using legacy config location: ${legacyConfigPath}`);
|
|
110
|
+
} else {
|
|
111
|
+
verbose(
|
|
112
|
+
`Project config not found at ${srcConfigPath} or ${legacyConfigPath}`
|
|
113
|
+
);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
85
116
|
}
|
|
86
117
|
try {
|
|
87
118
|
const content = await readFile(configPath);
|
|
@@ -106,15 +137,14 @@ async function saveGlobalConfig(config) {
|
|
|
106
137
|
}
|
|
107
138
|
async function saveProjectConfig(projectDir, config) {
|
|
108
139
|
const configPath = getProjectConfigPath(projectDir);
|
|
109
|
-
await ensureDir(path.join(projectDir,
|
|
140
|
+
await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));
|
|
110
141
|
const content = stringifyYaml(config, { lineWidth: 0 });
|
|
111
142
|
await writeFile(configPath, content);
|
|
112
143
|
verbose(`Saved project config to ${configPath}`);
|
|
113
144
|
}
|
|
114
145
|
async function resolveSource(flagValue, projectDir) {
|
|
115
146
|
const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;
|
|
116
|
-
const
|
|
117
|
-
const marketplace = projectConfig?.marketplace || globalConfig?.marketplace;
|
|
147
|
+
const marketplace = projectConfig?.marketplace;
|
|
118
148
|
if (flagValue !== void 0) {
|
|
119
149
|
if (flagValue === "" || flagValue.trim() === "") {
|
|
120
150
|
throw new Error("--source flag cannot be empty");
|
|
@@ -135,10 +165,6 @@ async function resolveSource(flagValue, projectDir) {
|
|
|
135
165
|
marketplace
|
|
136
166
|
};
|
|
137
167
|
}
|
|
138
|
-
if (globalConfig?.source) {
|
|
139
|
-
verbose(`Source from global config: ${globalConfig.source}`);
|
|
140
|
-
return { source: globalConfig.source, sourceOrigin: "global", marketplace };
|
|
141
|
-
}
|
|
142
168
|
verbose(`Using default source: ${DEFAULT_SOURCE}`);
|
|
143
169
|
return { source: DEFAULT_SOURCE, sourceOrigin: "default", marketplace };
|
|
144
170
|
}
|
|
@@ -160,14 +186,6 @@ async function resolveAgentsSource(flagValue, projectDir) {
|
|
|
160
186
|
agentsSourceOrigin: "project"
|
|
161
187
|
};
|
|
162
188
|
}
|
|
163
|
-
const globalConfig = await loadGlobalConfig();
|
|
164
|
-
if (globalConfig?.agents_source) {
|
|
165
|
-
verbose(`Agents source from global config: ${globalConfig.agents_source}`);
|
|
166
|
-
return {
|
|
167
|
-
agentsSource: globalConfig.agents_source,
|
|
168
|
-
agentsSourceOrigin: "global"
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
189
|
verbose("Using default agents source (local CLI)");
|
|
172
190
|
return { agentsSource: void 0, agentsSourceOrigin: "default" };
|
|
173
191
|
}
|
|
@@ -176,13 +194,17 @@ function formatAgentsSourceOrigin(origin) {
|
|
|
176
194
|
case "flag":
|
|
177
195
|
return "--agent-source flag";
|
|
178
196
|
case "project":
|
|
179
|
-
return "project config (.claude-
|
|
197
|
+
return "project config (.claude-src/config.yaml)";
|
|
180
198
|
case "global":
|
|
181
199
|
return "global config (~/.claude-collective/config.yaml)";
|
|
182
200
|
case "default":
|
|
183
201
|
return "default (local CLI)";
|
|
184
202
|
}
|
|
185
203
|
}
|
|
204
|
+
async function resolveAuthor(projectDir) {
|
|
205
|
+
const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;
|
|
206
|
+
return projectConfig?.author;
|
|
207
|
+
}
|
|
186
208
|
function formatSourceOrigin(origin) {
|
|
187
209
|
switch (origin) {
|
|
188
210
|
case "flag":
|
|
@@ -190,13 +212,42 @@ function formatSourceOrigin(origin) {
|
|
|
190
212
|
case "env":
|
|
191
213
|
return `${SOURCE_ENV_VAR} environment variable`;
|
|
192
214
|
case "project":
|
|
193
|
-
return "project config (.claude-
|
|
215
|
+
return "project config (.claude-src/config.yaml)";
|
|
194
216
|
case "global":
|
|
195
217
|
return "global config (~/.claude-collective/config.yaml)";
|
|
196
218
|
case "default":
|
|
197
219
|
return "default";
|
|
198
220
|
}
|
|
199
221
|
}
|
|
222
|
+
async function resolveAllSources(projectDir) {
|
|
223
|
+
const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;
|
|
224
|
+
const globalConfig = await loadGlobalConfig();
|
|
225
|
+
const resolvedConfig = await resolveSource(void 0, projectDir);
|
|
226
|
+
const primary = {
|
|
227
|
+
name: "marketplace",
|
|
228
|
+
url: resolvedConfig.source,
|
|
229
|
+
description: "Primary skills marketplace"
|
|
230
|
+
};
|
|
231
|
+
const extras = [];
|
|
232
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
233
|
+
if (projectConfig?.sources) {
|
|
234
|
+
for (const source of projectConfig.sources) {
|
|
235
|
+
if (!seenNames.has(source.name)) {
|
|
236
|
+
seenNames.add(source.name);
|
|
237
|
+
extras.push(source);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (globalConfig?.sources) {
|
|
242
|
+
for (const source of globalConfig.sources) {
|
|
243
|
+
if (!seenNames.has(source.name)) {
|
|
244
|
+
seenNames.add(source.name);
|
|
245
|
+
extras.push(source);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
return { primary, extras };
|
|
250
|
+
}
|
|
200
251
|
function isLocalSource(source) {
|
|
201
252
|
if (source.startsWith("/") || source.startsWith(".")) {
|
|
202
253
|
return true;
|
|
@@ -235,7 +286,9 @@ export {
|
|
|
235
286
|
resolveSource,
|
|
236
287
|
resolveAgentsSource,
|
|
237
288
|
formatAgentsSourceOrigin,
|
|
289
|
+
resolveAuthor,
|
|
238
290
|
formatSourceOrigin,
|
|
291
|
+
resolveAllSources,
|
|
239
292
|
isLocalSource
|
|
240
293
|
};
|
|
241
|
-
//# sourceMappingURL=chunk-
|
|
294
|
+
//# sourceMappingURL=chunk-V46GGCCI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/lib/config.ts"],"sourcesContent":["import path from \"path\";\nimport os from \"os\";\nimport { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport { readFile, writeFile, fileExists, ensureDir } from \"../utils/fs\";\nimport { verbose } from \"../utils/logger\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\n\nexport const DEFAULT_SOURCE = \"github:claude-collective/skills\";\nexport const SOURCE_ENV_VAR = \"CC_SOURCE\";\n/** Environment variable to override global config directory (used for testing) */\nexport const CONFIG_HOME_ENV_VAR = \"CC_CONFIG_HOME\";\nexport const GLOBAL_CONFIG_FILE = \"config.yaml\";\nexport const PROJECT_CONFIG_FILE = \"config.yaml\";\n\n/**\n * Get global config directory path.\n * Can be overridden via CC_CONFIG_HOME environment variable for testing isolation.\n * This is a function (not constant) to allow tests to set the env var after module load.\n */\nexport function getGlobalConfigDir(): string {\n return (\n process.env[CONFIG_HOME_ENV_VAR] ||\n path.join(os.homedir(), \".claude-collective\")\n );\n}\n\n/**\n * @deprecated Use getGlobalConfigDir() instead. This constant is kept for backwards compatibility\n * but won't respect CC_CONFIG_HOME set after module load.\n */\nexport const GLOBAL_CONFIG_DIR = path.join(os.homedir(), \".claude-collective\");\n\n/**\n * Extra source entry for third-party skill repositories.\n * Used in both global and project configs.\n */\nexport interface SourceEntry {\n /** Short name for the source (e.g., \"company\", \"team\") */\n name: string;\n /** GitHub URL or path (e.g., \"github:owner/repo\") */\n url: string;\n /** Optional description */\n description?: string;\n /** Optional ref to pin to (branch, tag, or commit) */\n ref?: string;\n}\n\nexport interface GlobalConfig {\n source?: string;\n author?: string;\n marketplace?: string;\n agents_source?: string;\n /** Extra sources for third-party skills */\n sources?: SourceEntry[];\n}\n\nexport interface ProjectConfig {\n source?: string;\n author?: string;\n marketplace?: string;\n agents_source?: string;\n /** Extra sources for third-party skills */\n sources?: SourceEntry[];\n}\n\nexport interface ResolvedConfig {\n source: string;\n sourceOrigin: \"flag\" | \"env\" | \"project\" | \"global\" | \"default\";\n marketplace?: string;\n}\n\nfunction isValidSourceEntry(entry: unknown): entry is SourceEntry {\n if (typeof entry !== \"object\" || entry === null) return false;\n const e = entry as Record<string, unknown>;\n if (typeof e.name !== \"string\" || typeof e.url !== \"string\") return false;\n if (e.description !== undefined && typeof e.description !== \"string\")\n return false;\n if (e.ref !== undefined && typeof e.ref !== \"string\") return false;\n return true;\n}\n\nfunction isValidSourcesArray(arr: unknown): arr is SourceEntry[] {\n if (!Array.isArray(arr)) return false;\n return arr.every(isValidSourceEntry);\n}\n\nfunction isValidGlobalConfig(obj: unknown): obj is GlobalConfig {\n if (typeof obj !== \"object\" || obj === null) return false;\n const config = obj as Record<string, unknown>;\n if (config.source !== undefined && typeof config.source !== \"string\")\n return false;\n if (config.author !== undefined && typeof config.author !== \"string\")\n return false;\n if (\n config.marketplace !== undefined &&\n typeof config.marketplace !== \"string\"\n )\n return false;\n if (\n config.agents_source !== undefined &&\n typeof config.agents_source !== \"string\"\n )\n return false;\n if (config.sources !== undefined && !isValidSourcesArray(config.sources))\n return false;\n return true;\n}\n\nfunction isValidProjectConfig(obj: unknown): obj is ProjectConfig {\n if (typeof obj !== \"object\" || obj === null) return false;\n const config = obj as Record<string, unknown>;\n if (config.source !== undefined && typeof config.source !== \"string\")\n return false;\n if (config.author !== undefined && typeof config.author !== \"string\")\n return false;\n if (\n config.marketplace !== undefined &&\n typeof config.marketplace !== \"string\"\n )\n return false;\n if (\n config.agents_source !== undefined &&\n typeof config.agents_source !== \"string\"\n )\n return false;\n if (config.sources !== undefined && !isValidSourcesArray(config.sources))\n return false;\n return true;\n}\n\nexport function getGlobalConfigPath(): string {\n return path.join(getGlobalConfigDir(), GLOBAL_CONFIG_FILE);\n}\n\nexport function getProjectConfigPath(projectDir: string): string {\n return path.join(projectDir, CLAUDE_SRC_DIR, PROJECT_CONFIG_FILE);\n}\n\n/**\n * @deprecated Global config is deprecated. Use project-level config at .claude/config.yaml instead.\n * This function is kept for backwards compatibility during migration.\n */\nexport async function loadGlobalConfig(): Promise<GlobalConfig | null> {\n const configPath = getGlobalConfigPath();\n\n if (!(await fileExists(configPath))) {\n verbose(`Global config not found at ${configPath}`);\n return null;\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n if (!isValidGlobalConfig(parsed)) {\n verbose(`Invalid global config structure at ${configPath}`);\n return null;\n }\n verbose(`Loaded global config from ${configPath}`);\n return parsed;\n } catch (error) {\n verbose(`Failed to parse global config: ${error}`);\n return null;\n }\n}\n\nexport async function loadProjectConfig(\n projectDir: string,\n): Promise<ProjectConfig | null> {\n // Check .claude-src/config.yaml first (new location)\n const srcConfigPath = getProjectConfigPath(projectDir);\n // Fall back to .claude/config.yaml (legacy location)\n const legacyConfigPath = path.join(projectDir, CLAUDE_DIR, \"config.yaml\");\n\n let configPath = srcConfigPath;\n if (!(await fileExists(srcConfigPath))) {\n if (await fileExists(legacyConfigPath)) {\n configPath = legacyConfigPath;\n verbose(`Using legacy config location: ${legacyConfigPath}`);\n } else {\n verbose(\n `Project config not found at ${srcConfigPath} or ${legacyConfigPath}`,\n );\n return null;\n }\n }\n\n try {\n const content = await readFile(configPath);\n const parsed = parseYaml(content);\n if (!isValidProjectConfig(parsed)) {\n verbose(`Invalid project config structure at ${configPath}`);\n return null;\n }\n verbose(`Loaded project config from ${configPath}`);\n return parsed;\n } catch (error) {\n verbose(`Failed to parse project config: ${error}`);\n return null;\n }\n}\n\n/**\n * @deprecated Global config is deprecated. Use project-level config at .claude/config.yaml instead.\n * This function is kept for backwards compatibility during migration.\n */\nexport async function saveGlobalConfig(config: GlobalConfig): Promise<void> {\n const configPath = getGlobalConfigPath();\n await ensureDir(getGlobalConfigDir());\n const content = stringifyYaml(config, { lineWidth: 0 });\n await writeFile(configPath, content);\n verbose(`Saved global config to ${configPath}`);\n}\n\nexport async function saveProjectConfig(\n projectDir: string,\n config: ProjectConfig,\n): Promise<void> {\n const configPath = getProjectConfigPath(projectDir);\n await ensureDir(path.join(projectDir, CLAUDE_SRC_DIR));\n const content = stringifyYaml(config, { lineWidth: 0 });\n await writeFile(configPath, content);\n verbose(`Saved project config to ${configPath}`);\n}\n\n/** Resolve source with precedence: flag > env > project > default */\nexport async function resolveSource(\n flagValue?: string,\n projectDir?: string,\n): Promise<ResolvedConfig> {\n // Load project config for marketplace (marketplace is resolved separately from source)\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n\n // Resolve marketplace: project config only (no flag/env support for marketplace)\n const marketplace = projectConfig?.marketplace;\n\n if (flagValue !== undefined) {\n if (flagValue === \"\" || flagValue.trim() === \"\") {\n throw new Error(\"--source flag cannot be empty\");\n }\n verbose(`Source from --source flag: ${flagValue}`);\n return { source: flagValue, sourceOrigin: \"flag\", marketplace };\n }\n\n const envValue = process.env[SOURCE_ENV_VAR];\n if (envValue) {\n verbose(`Source from ${SOURCE_ENV_VAR} env var: ${envValue}`);\n return { source: envValue, sourceOrigin: \"env\", marketplace };\n }\n\n if (projectConfig?.source) {\n verbose(`Source from project config: ${projectConfig.source}`);\n return {\n source: projectConfig.source,\n sourceOrigin: \"project\",\n marketplace,\n };\n }\n\n verbose(`Using default source: ${DEFAULT_SOURCE}`);\n return { source: DEFAULT_SOURCE, sourceOrigin: \"default\", marketplace };\n}\n\nexport type AgentsSourceOrigin = \"flag\" | \"project\" | \"global\" | \"default\";\n\nexport interface ResolvedAgentsSource {\n agentsSource?: string;\n agentsSourceOrigin: AgentsSourceOrigin;\n}\n\n/** Resolve agents_source with precedence: flag > project > default (undefined) */\nexport async function resolveAgentsSource(\n flagValue?: string,\n projectDir?: string,\n): Promise<ResolvedAgentsSource> {\n if (flagValue !== undefined) {\n if (flagValue === \"\" || flagValue.trim() === \"\") {\n throw new Error(\"--agent-source flag cannot be empty\");\n }\n verbose(`Agents source from --agent-source flag: ${flagValue}`);\n return { agentsSource: flagValue, agentsSourceOrigin: \"flag\" };\n }\n\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n if (projectConfig?.agents_source) {\n verbose(\n `Agents source from project config: ${projectConfig.agents_source}`,\n );\n return {\n agentsSource: projectConfig.agents_source,\n agentsSourceOrigin: \"project\",\n };\n }\n\n verbose(\"Using default agents source (local CLI)\");\n return { agentsSource: undefined, agentsSourceOrigin: \"default\" };\n}\n\nexport function formatAgentsSourceOrigin(origin: AgentsSourceOrigin): string {\n switch (origin) {\n case \"flag\":\n return \"--agent-source flag\";\n case \"project\":\n return \"project config (.claude-src/config.yaml)\";\n case \"global\":\n return \"global config (~/.claude-collective/config.yaml)\";\n case \"default\":\n return \"default (local CLI)\";\n }\n}\n\n/** Resolve author from project config */\nexport async function resolveAuthor(\n projectDir?: string,\n): Promise<string | undefined> {\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n return projectConfig?.author;\n}\n\nexport function formatSourceOrigin(\n origin: ResolvedConfig[\"sourceOrigin\"],\n): string {\n switch (origin) {\n case \"flag\":\n return \"--source flag\";\n case \"env\":\n return `${SOURCE_ENV_VAR} environment variable`;\n case \"project\":\n return \"project config (.claude-src/config.yaml)\";\n case \"global\":\n return \"global config (~/.claude-collective/config.yaml)\";\n case \"default\":\n return \"default\";\n }\n}\n\n/**\n * Resolve all configured sources for skill search.\n * Returns primary source plus any extra sources from project/global config.\n */\nexport async function resolveAllSources(\n projectDir?: string,\n): Promise<{ primary: SourceEntry; extras: SourceEntry[] }> {\n const projectConfig = projectDir ? await loadProjectConfig(projectDir) : null;\n const globalConfig = await loadGlobalConfig();\n\n // Get primary source\n const resolvedConfig = await resolveSource(undefined, projectDir);\n const primary: SourceEntry = {\n name: \"marketplace\",\n url: resolvedConfig.source,\n description: \"Primary skills marketplace\",\n };\n\n // Merge extra sources: project takes precedence, then global\n const extras: SourceEntry[] = [];\n const seenNames = new Set<string>();\n\n // Add project sources first (higher priority)\n if (projectConfig?.sources) {\n for (const source of projectConfig.sources) {\n if (!seenNames.has(source.name)) {\n seenNames.add(source.name);\n extras.push(source);\n }\n }\n }\n\n // Add global sources (lower priority, skip duplicates)\n if (globalConfig?.sources) {\n for (const source of globalConfig.sources) {\n if (!seenNames.has(source.name)) {\n seenNames.add(source.name);\n extras.push(source);\n }\n }\n }\n\n return { primary, extras };\n}\n\nexport function isLocalSource(source: string): boolean {\n if (source.startsWith(\"/\") || source.startsWith(\".\")) {\n return true;\n }\n\n const remoteProtocols = [\n \"github:\",\n \"gh:\",\n \"gitlab:\",\n \"bitbucket:\",\n \"sourcehut:\",\n \"https://\",\n \"http://\",\n ];\n\n const hasRemoteProtocol = remoteProtocols.some((prefix) =>\n source.startsWith(prefix),\n );\n\n if (!hasRemoteProtocol) {\n if (source.includes(\"..\") || source.includes(\"~\")) {\n throw new Error(\n `Invalid source path: ${source}. Path traversal patterns are not allowed.`,\n );\n }\n }\n\n return !hasRemoteProtocol;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
WizardFooter
|
|
4
|
+
} from "./chunk-Y2LW7R3Y.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-DHET7RCE.js";
|
|
8
|
+
|
|
9
|
+
// src/cli/components/wizard/step-confirm.tsx
|
|
10
|
+
init_esm_shims();
|
|
11
|
+
import { Box, Text, useInput } from "ink";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
var formatDomainName = (domain) => {
|
|
14
|
+
const names = {
|
|
15
|
+
web: "Web",
|
|
16
|
+
api: "API",
|
|
17
|
+
cli: "CLI",
|
|
18
|
+
mobile: "Mobile"
|
|
19
|
+
};
|
|
20
|
+
return names[domain] || domain.charAt(0).toUpperCase() + domain.slice(1);
|
|
21
|
+
};
|
|
22
|
+
var StepConfirm = ({
|
|
23
|
+
matrix,
|
|
24
|
+
onComplete,
|
|
25
|
+
stackName,
|
|
26
|
+
selectedDomains,
|
|
27
|
+
domainSelections,
|
|
28
|
+
technologyCount,
|
|
29
|
+
skillCount,
|
|
30
|
+
installMode,
|
|
31
|
+
onBack
|
|
32
|
+
}) => {
|
|
33
|
+
useInput((input, key) => {
|
|
34
|
+
if (key.return) {
|
|
35
|
+
onComplete();
|
|
36
|
+
}
|
|
37
|
+
if (key.escape && onBack) {
|
|
38
|
+
onBack();
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const domainsText = selectedDomains?.map(formatDomainName).join(" + ") || "";
|
|
42
|
+
const title = stackName ? `Ready to install ${stackName}` : `Ready to install your custom stack${domainsText ? ` (${domainsText})` : ""}`;
|
|
43
|
+
return /* @__PURE__ */ jsxs(Box, { flexDirection: "column", paddingX: 2, children: [
|
|
44
|
+
/* @__PURE__ */ jsx(Text, { bold: true, color: "green", children: title }),
|
|
45
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
46
|
+
domainSelections && selectedDomains && !stackName && /* @__PURE__ */ jsx(Box, { flexDirection: "column", marginBottom: 1, children: selectedDomains.map((domain) => {
|
|
47
|
+
const selections = domainSelections[domain] || {};
|
|
48
|
+
const techs = Object.values(selections).flat();
|
|
49
|
+
if (techs.length === 0) return null;
|
|
50
|
+
return /* @__PURE__ */ jsxs(Text, { children: [
|
|
51
|
+
/* @__PURE__ */ jsxs(Text, { bold: true, children: [
|
|
52
|
+
formatDomainName(domain),
|
|
53
|
+
":"
|
|
54
|
+
] }),
|
|
55
|
+
" ",
|
|
56
|
+
/* @__PURE__ */ jsx(Text, { children: techs.join(", ") })
|
|
57
|
+
] }, domain);
|
|
58
|
+
}) }),
|
|
59
|
+
/* @__PURE__ */ jsxs(Box, { flexDirection: "column", marginY: 1, children: [
|
|
60
|
+
technologyCount !== void 0 && /* @__PURE__ */ jsxs(Text, { children: [
|
|
61
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Technologies:" }),
|
|
62
|
+
" ",
|
|
63
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: technologyCount })
|
|
64
|
+
] }),
|
|
65
|
+
skillCount !== void 0 && /* @__PURE__ */ jsxs(Text, { children: [
|
|
66
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Skills:" }),
|
|
67
|
+
" ",
|
|
68
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: skillCount }),
|
|
69
|
+
" ",
|
|
70
|
+
/* @__PURE__ */ jsx(Text, { color: "green", children: "(all verified)" })
|
|
71
|
+
] }),
|
|
72
|
+
installMode && /* @__PURE__ */ jsxs(Text, { children: [
|
|
73
|
+
/* @__PURE__ */ jsx(Text, { dimColor: true, children: "Install mode:" }),
|
|
74
|
+
" ",
|
|
75
|
+
/* @__PURE__ */ jsx(Text, { bold: true, children: installMode === "plugin" ? "Plugin" : "Local" })
|
|
76
|
+
] })
|
|
77
|
+
] }),
|
|
78
|
+
/* @__PURE__ */ jsx(Text, { children: " " }),
|
|
79
|
+
/* @__PURE__ */ jsx(WizardFooter, { navigation: "ENTER confirm", action: "ESC back" })
|
|
80
|
+
] });
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
StepConfirm
|
|
85
|
+
};
|
|
86
|
+
//# sourceMappingURL=chunk-X6QONICW.js.map
|