@claude-collective/cli 0.1.2 → 0.1.3
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 +14 -0
- package/dist/cli/index.js +191 -139
- package/dist/cli/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,20 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.3] - 2026-01-30
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `--output` option for eject command to specify custom output directory
|
|
13
|
+
- Remote schema fetching for skill validation from GitHub
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Plugin manifest no longer includes agents field (Claude Code discovers automatically)
|
|
18
|
+
- Source loader now supports source-provided skills matrix
|
|
19
|
+
|
|
20
|
+
[0.1.3]: https://github.com/claude-collective/cli/releases/tag/v0.1.3
|
|
21
|
+
|
|
8
22
|
## [0.1.2] - 2026-01-30
|
|
9
23
|
|
|
10
24
|
### Changed
|
package/dist/cli/index.js
CHANGED
|
@@ -891,9 +891,6 @@ function generateStackPluginManifest(options) {
|
|
|
891
891
|
if (options.keywords && options.keywords.length > 0) {
|
|
892
892
|
manifest.keywords = options.keywords;
|
|
893
893
|
}
|
|
894
|
-
if (options.hasAgents) {
|
|
895
|
-
manifest.agents = "./agents/";
|
|
896
|
-
}
|
|
897
894
|
if (options.hasHooks) {
|
|
898
895
|
manifest.hooks = "./hooks/hooks.json";
|
|
899
896
|
}
|
|
@@ -3329,12 +3326,97 @@ async function runWizard(matrix, options = {}) {
|
|
|
3329
3326
|
// src/cli/lib/source-loader.ts
|
|
3330
3327
|
import path21 from "path";
|
|
3331
3328
|
|
|
3332
|
-
// src/cli/lib/
|
|
3329
|
+
// src/cli/lib/local-skill-loader.ts
|
|
3333
3330
|
import { parse as parseYaml7 } from "yaml";
|
|
3334
3331
|
import path19 from "path";
|
|
3332
|
+
var LOCAL_CATEGORY = "local";
|
|
3333
|
+
var LOCAL_AUTHOR = "@local";
|
|
3334
|
+
var TEST_SKILL_PREFIX = "test-";
|
|
3335
|
+
async function discoverLocalSkills(projectDir) {
|
|
3336
|
+
const localSkillsPath = path19.join(projectDir, LOCAL_SKILLS_PATH);
|
|
3337
|
+
if (!await directoryExists(localSkillsPath)) {
|
|
3338
|
+
verbose(`Local skills directory not found: ${localSkillsPath}`);
|
|
3339
|
+
return null;
|
|
3340
|
+
}
|
|
3341
|
+
const skills = [];
|
|
3342
|
+
const skillDirs = await listDirectories(localSkillsPath);
|
|
3343
|
+
for (const skillDirName of skillDirs) {
|
|
3344
|
+
if (!skillDirName.startsWith(TEST_SKILL_PREFIX)) {
|
|
3345
|
+
verbose(
|
|
3346
|
+
`Skipping local skill '${skillDirName}': Does not have test- prefix (temporary filter)`
|
|
3347
|
+
);
|
|
3348
|
+
continue;
|
|
3349
|
+
}
|
|
3350
|
+
const skill = await extractLocalSkill(localSkillsPath, skillDirName);
|
|
3351
|
+
if (skill) {
|
|
3352
|
+
skills.push(skill);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);
|
|
3356
|
+
return {
|
|
3357
|
+
skills,
|
|
3358
|
+
localSkillsPath
|
|
3359
|
+
};
|
|
3360
|
+
}
|
|
3361
|
+
async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
3362
|
+
const skillDir = path19.join(localSkillsPath, skillDirName);
|
|
3363
|
+
const metadataPath = path19.join(skillDir, "metadata.yaml");
|
|
3364
|
+
const skillMdPath = path19.join(skillDir, "SKILL.md");
|
|
3365
|
+
if (!await fileExists(metadataPath)) {
|
|
3366
|
+
verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);
|
|
3367
|
+
return null;
|
|
3368
|
+
}
|
|
3369
|
+
if (!await fileExists(skillMdPath)) {
|
|
3370
|
+
verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);
|
|
3371
|
+
return null;
|
|
3372
|
+
}
|
|
3373
|
+
const metadataContent = await readFile(metadataPath);
|
|
3374
|
+
const metadata = parseYaml7(metadataContent);
|
|
3375
|
+
if (!metadata.cli_name) {
|
|
3376
|
+
verbose(
|
|
3377
|
+
`Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`
|
|
3378
|
+
);
|
|
3379
|
+
return null;
|
|
3380
|
+
}
|
|
3381
|
+
const skillMdContent = await readFile(skillMdPath);
|
|
3382
|
+
const frontmatter = parseFrontmatter(skillMdContent);
|
|
3383
|
+
if (!frontmatter) {
|
|
3384
|
+
verbose(
|
|
3385
|
+
`Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`
|
|
3386
|
+
);
|
|
3387
|
+
return null;
|
|
3388
|
+
}
|
|
3389
|
+
const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;
|
|
3390
|
+
const skillId = frontmatter.name;
|
|
3391
|
+
const extracted = {
|
|
3392
|
+
id: skillId,
|
|
3393
|
+
directoryPath: skillDirName,
|
|
3394
|
+
name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,
|
|
3395
|
+
description: metadata.cli_description || frontmatter.description,
|
|
3396
|
+
usageGuidance: void 0,
|
|
3397
|
+
category: LOCAL_CATEGORY,
|
|
3398
|
+
categoryExclusive: false,
|
|
3399
|
+
author: LOCAL_AUTHOR,
|
|
3400
|
+
tags: [],
|
|
3401
|
+
compatibleWith: [],
|
|
3402
|
+
conflictsWith: [],
|
|
3403
|
+
requires: [],
|
|
3404
|
+
requiresSetup: [],
|
|
3405
|
+
providesSetupFor: [],
|
|
3406
|
+
path: relativePath,
|
|
3407
|
+
local: true,
|
|
3408
|
+
localPath: relativePath
|
|
3409
|
+
};
|
|
3410
|
+
verbose(`Extracted local skill: ${skillId}`);
|
|
3411
|
+
return extracted;
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
// src/cli/lib/matrix-loader.ts
|
|
3415
|
+
import { parse as parseYaml8 } from "yaml";
|
|
3416
|
+
import path20 from "path";
|
|
3335
3417
|
async function loadSkillsMatrix(configPath) {
|
|
3336
3418
|
const content = await readFile(configPath);
|
|
3337
|
-
const config =
|
|
3419
|
+
const config = parseYaml8(content);
|
|
3338
3420
|
validateMatrixStructure(config, configPath);
|
|
3339
3421
|
verbose(`Loaded skills matrix: ${configPath}`);
|
|
3340
3422
|
return config;
|
|
@@ -3390,15 +3472,15 @@ async function extractAllSkills(skillsDir) {
|
|
|
3390
3472
|
const skills = [];
|
|
3391
3473
|
const metadataFiles = await glob("**/metadata.yaml", skillsDir);
|
|
3392
3474
|
for (const metadataFile of metadataFiles) {
|
|
3393
|
-
const skillDir =
|
|
3394
|
-
const skillMdPath =
|
|
3395
|
-
const metadataPath =
|
|
3475
|
+
const skillDir = path20.dirname(metadataFile);
|
|
3476
|
+
const skillMdPath = path20.join(skillsDir, skillDir, "SKILL.md");
|
|
3477
|
+
const metadataPath = path20.join(skillsDir, metadataFile);
|
|
3396
3478
|
if (!await fileExists(skillMdPath)) {
|
|
3397
3479
|
verbose(`Skipping ${metadataFile}: No SKILL.md found`);
|
|
3398
3480
|
continue;
|
|
3399
3481
|
}
|
|
3400
3482
|
const metadataContent = await readFile(metadataPath);
|
|
3401
|
-
const metadata =
|
|
3483
|
+
const metadata = parseYaml8(metadataContent);
|
|
3402
3484
|
const skillMdContent = await readFile(skillMdPath);
|
|
3403
3485
|
const frontmatter = parseFrontmatter(skillMdContent);
|
|
3404
3486
|
if (!frontmatter) {
|
|
@@ -3686,91 +3768,6 @@ function resolveSuggestedStacks(matrix, aliases) {
|
|
|
3686
3768
|
});
|
|
3687
3769
|
}
|
|
3688
3770
|
|
|
3689
|
-
// src/cli/lib/local-skill-loader.ts
|
|
3690
|
-
import { parse as parseYaml8 } from "yaml";
|
|
3691
|
-
import path20 from "path";
|
|
3692
|
-
var LOCAL_CATEGORY = "local";
|
|
3693
|
-
var LOCAL_AUTHOR = "@local";
|
|
3694
|
-
var TEST_SKILL_PREFIX = "test-";
|
|
3695
|
-
async function discoverLocalSkills(projectDir) {
|
|
3696
|
-
const localSkillsPath = path20.join(projectDir, LOCAL_SKILLS_PATH);
|
|
3697
|
-
if (!await directoryExists(localSkillsPath)) {
|
|
3698
|
-
verbose(`Local skills directory not found: ${localSkillsPath}`);
|
|
3699
|
-
return null;
|
|
3700
|
-
}
|
|
3701
|
-
const skills = [];
|
|
3702
|
-
const skillDirs = await listDirectories(localSkillsPath);
|
|
3703
|
-
for (const skillDirName of skillDirs) {
|
|
3704
|
-
if (!skillDirName.startsWith(TEST_SKILL_PREFIX)) {
|
|
3705
|
-
verbose(
|
|
3706
|
-
`Skipping local skill '${skillDirName}': Does not have test- prefix (temporary filter)`
|
|
3707
|
-
);
|
|
3708
|
-
continue;
|
|
3709
|
-
}
|
|
3710
|
-
const skill = await extractLocalSkill(localSkillsPath, skillDirName);
|
|
3711
|
-
if (skill) {
|
|
3712
|
-
skills.push(skill);
|
|
3713
|
-
}
|
|
3714
|
-
}
|
|
3715
|
-
verbose(`Discovered ${skills.length} local skills from ${localSkillsPath}`);
|
|
3716
|
-
return {
|
|
3717
|
-
skills,
|
|
3718
|
-
localSkillsPath
|
|
3719
|
-
};
|
|
3720
|
-
}
|
|
3721
|
-
async function extractLocalSkill(localSkillsPath, skillDirName) {
|
|
3722
|
-
const skillDir = path20.join(localSkillsPath, skillDirName);
|
|
3723
|
-
const metadataPath = path20.join(skillDir, "metadata.yaml");
|
|
3724
|
-
const skillMdPath = path20.join(skillDir, "SKILL.md");
|
|
3725
|
-
if (!await fileExists(metadataPath)) {
|
|
3726
|
-
verbose(`Skipping local skill '${skillDirName}': No metadata.yaml found`);
|
|
3727
|
-
return null;
|
|
3728
|
-
}
|
|
3729
|
-
if (!await fileExists(skillMdPath)) {
|
|
3730
|
-
verbose(`Skipping local skill '${skillDirName}': No SKILL.md found`);
|
|
3731
|
-
return null;
|
|
3732
|
-
}
|
|
3733
|
-
const metadataContent = await readFile(metadataPath);
|
|
3734
|
-
const metadata = parseYaml8(metadataContent);
|
|
3735
|
-
if (!metadata.cli_name) {
|
|
3736
|
-
verbose(
|
|
3737
|
-
`Skipping local skill '${skillDirName}': Missing required 'cli_name' in metadata.yaml`
|
|
3738
|
-
);
|
|
3739
|
-
return null;
|
|
3740
|
-
}
|
|
3741
|
-
const skillMdContent = await readFile(skillMdPath);
|
|
3742
|
-
const frontmatter = parseFrontmatter(skillMdContent);
|
|
3743
|
-
if (!frontmatter) {
|
|
3744
|
-
verbose(
|
|
3745
|
-
`Skipping local skill '${skillDirName}': Invalid SKILL.md frontmatter`
|
|
3746
|
-
);
|
|
3747
|
-
return null;
|
|
3748
|
-
}
|
|
3749
|
-
const relativePath = `${LOCAL_SKILLS_PATH}/${skillDirName}/`;
|
|
3750
|
-
const skillId = frontmatter.name;
|
|
3751
|
-
const extracted = {
|
|
3752
|
-
id: skillId,
|
|
3753
|
-
directoryPath: skillDirName,
|
|
3754
|
-
name: `${metadata.cli_name} ${LOCAL_AUTHOR}`,
|
|
3755
|
-
description: metadata.cli_description || frontmatter.description,
|
|
3756
|
-
usageGuidance: void 0,
|
|
3757
|
-
category: LOCAL_CATEGORY,
|
|
3758
|
-
categoryExclusive: false,
|
|
3759
|
-
author: LOCAL_AUTHOR,
|
|
3760
|
-
tags: [],
|
|
3761
|
-
compatibleWith: [],
|
|
3762
|
-
conflictsWith: [],
|
|
3763
|
-
requires: [],
|
|
3764
|
-
requiresSetup: [],
|
|
3765
|
-
providesSetupFor: [],
|
|
3766
|
-
path: relativePath,
|
|
3767
|
-
local: true,
|
|
3768
|
-
localPath: relativePath
|
|
3769
|
-
};
|
|
3770
|
-
verbose(`Extracted local skill: ${skillId}`);
|
|
3771
|
-
return extracted;
|
|
3772
|
-
}
|
|
3773
|
-
|
|
3774
3771
|
// src/cli/lib/source-loader.ts
|
|
3775
3772
|
async function loadSkillsMatrixFromSource(options = {}) {
|
|
3776
3773
|
const {
|
|
@@ -3810,9 +3807,17 @@ async function loadFromLocal(source, sourceConfig) {
|
|
|
3810
3807
|
skillsPath = PROJECT_ROOT;
|
|
3811
3808
|
}
|
|
3812
3809
|
verbose(`Loading skills from local path: ${skillsPath}`);
|
|
3813
|
-
const
|
|
3810
|
+
const sourceMatrixPath = path21.join(skillsPath, SKILLS_MATRIX_PATH);
|
|
3811
|
+
const cliMatrixPath = path21.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);
|
|
3812
|
+
let matrixPath;
|
|
3813
|
+
if (await fileExists(sourceMatrixPath)) {
|
|
3814
|
+
matrixPath = sourceMatrixPath;
|
|
3815
|
+
verbose(`Matrix from source: ${matrixPath}`);
|
|
3816
|
+
} else {
|
|
3817
|
+
matrixPath = cliMatrixPath;
|
|
3818
|
+
verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);
|
|
3819
|
+
}
|
|
3814
3820
|
const skillsDir = path21.join(skillsPath, SKILLS_DIR_PATH);
|
|
3815
|
-
verbose(`Matrix from CLI: ${matrixPath}`);
|
|
3816
3821
|
verbose(`Skills from source: ${skillsDir}`);
|
|
3817
3822
|
const matrix = await loadSkillsMatrix(matrixPath);
|
|
3818
3823
|
const skills = await extractAllSkills(skillsDir);
|
|
@@ -3828,9 +3833,17 @@ async function loadFromRemote(source, sourceConfig, forceRefresh) {
|
|
|
3828
3833
|
verbose(`Fetching skills from remote source: ${source}`);
|
|
3829
3834
|
const fetchResult = await fetchFromSource(source, { forceRefresh });
|
|
3830
3835
|
verbose(`Fetched to: ${fetchResult.path}`);
|
|
3831
|
-
const
|
|
3836
|
+
const sourceMatrixPath = path21.join(fetchResult.path, SKILLS_MATRIX_PATH);
|
|
3837
|
+
const cliMatrixPath = path21.join(PROJECT_ROOT, SKILLS_MATRIX_PATH);
|
|
3838
|
+
let matrixPath;
|
|
3839
|
+
if (await fileExists(sourceMatrixPath)) {
|
|
3840
|
+
matrixPath = sourceMatrixPath;
|
|
3841
|
+
verbose(`Matrix from source: ${matrixPath}`);
|
|
3842
|
+
} else {
|
|
3843
|
+
matrixPath = cliMatrixPath;
|
|
3844
|
+
verbose(`Matrix from CLI (source has no matrix): ${matrixPath}`);
|
|
3845
|
+
}
|
|
3832
3846
|
const skillsDir = path21.join(fetchResult.path, SKILLS_DIR_PATH);
|
|
3833
|
-
verbose(`Matrix from CLI: ${matrixPath}`);
|
|
3834
3847
|
verbose(`Skills from source: ${skillsDir}`);
|
|
3835
3848
|
const matrix = await loadSkillsMatrix(matrixPath);
|
|
3836
3849
|
const skills = await extractAllSkills(skillsDir);
|
|
@@ -5182,6 +5195,9 @@ var KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
|
|
|
5182
5195
|
var SEMVER_REGEX = /^(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-]+)*))?$/;
|
|
5183
5196
|
var schemaCache2 = /* @__PURE__ */ new Map();
|
|
5184
5197
|
var validatorCache2 = /* @__PURE__ */ new Map();
|
|
5198
|
+
var REMOTE_SCHEMAS = {
|
|
5199
|
+
"skill-frontmatter.schema.json": "https://raw.githubusercontent.com/claude-collective/skills/main/src/schemas/skill-frontmatter.schema.json"
|
|
5200
|
+
};
|
|
5185
5201
|
async function loadSchema2(schemaName) {
|
|
5186
5202
|
if (schemaCache2.has(schemaName)) {
|
|
5187
5203
|
return schemaCache2.get(schemaName);
|
|
@@ -5198,8 +5214,20 @@ async function loadSchema2(schemaName) {
|
|
|
5198
5214
|
return schema;
|
|
5199
5215
|
}
|
|
5200
5216
|
}
|
|
5217
|
+
const remoteUrl = REMOTE_SCHEMAS[schemaName];
|
|
5218
|
+
if (remoteUrl) {
|
|
5219
|
+
try {
|
|
5220
|
+
const response = await fetch(remoteUrl);
|
|
5221
|
+
if (response.ok) {
|
|
5222
|
+
const schema = await response.json();
|
|
5223
|
+
schemaCache2.set(schemaName, schema);
|
|
5224
|
+
return schema;
|
|
5225
|
+
}
|
|
5226
|
+
} catch {
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5201
5229
|
throw new Error(
|
|
5202
|
-
`Schema not found: ${schemaName}. Searched: ${locations.join(", ")}`
|
|
5230
|
+
`Schema not found: ${schemaName}. Searched: ${locations.join(", ")}${remoteUrl ? ` and ${remoteUrl}` : ""}`
|
|
5203
5231
|
);
|
|
5204
5232
|
}
|
|
5205
5233
|
async function getValidator2(schemaName) {
|
|
@@ -5909,6 +5937,7 @@ import { Command as Command10 } from "commander";
|
|
|
5909
5937
|
import * as p12 from "@clack/prompts";
|
|
5910
5938
|
import pc12 from "picocolors";
|
|
5911
5939
|
import path30 from "path";
|
|
5940
|
+
import os4 from "os";
|
|
5912
5941
|
var EJECT_TYPES = ["templates", "skills", "config", "all"];
|
|
5913
5942
|
var DEFAULT_CONFIG_CONTENT = `# Claude Collective Configuration
|
|
5914
5943
|
# Agent-skill mappings for this project
|
|
@@ -5959,44 +5988,65 @@ author: "@local"
|
|
|
5959
5988
|
cli_name: Example Skill
|
|
5960
5989
|
cli_description: Short description for CLI
|
|
5961
5990
|
`;
|
|
5962
|
-
var ejectCommand = new Command10("eject").description("Eject bundled content for local customization").argument("[type]", "What to eject: templates, skills, config, all").option("-f, --force", "Overwrite existing files", false).
|
|
5991
|
+
var ejectCommand = new Command10("eject").description("Eject bundled content for local customization").argument("[type]", "What to eject: templates, skills, config, all").option("-f, --force", "Overwrite existing files", false).option(
|
|
5992
|
+
"-o, --output <dir>",
|
|
5993
|
+
"Output directory (default: .claude/ in current directory)"
|
|
5994
|
+
).configureOutput({
|
|
5963
5995
|
writeErr: (str) => console.error(pc12.red(str))
|
|
5964
|
-
}).showHelpAfterError(true).action(
|
|
5965
|
-
|
|
5966
|
-
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5996
|
+
}).showHelpAfterError(true).action(
|
|
5997
|
+
async (type, options) => {
|
|
5998
|
+
const projectDir = process.cwd();
|
|
5999
|
+
if (!type) {
|
|
6000
|
+
p12.log.error(
|
|
6001
|
+
"Please specify what to eject: templates, skills, config, or all"
|
|
6002
|
+
);
|
|
6003
|
+
process.exit(EXIT_CODES.INVALID_ARGS);
|
|
6004
|
+
}
|
|
6005
|
+
if (!EJECT_TYPES.includes(type)) {
|
|
6006
|
+
p12.log.error(`Unknown eject type: ${type}`);
|
|
6007
|
+
p12.log.info(`Valid types: ${EJECT_TYPES.join(", ")}`);
|
|
6008
|
+
process.exit(EXIT_CODES.INVALID_ARGS);
|
|
6009
|
+
}
|
|
6010
|
+
let outputBase;
|
|
6011
|
+
if (options.output) {
|
|
6012
|
+
const expandedPath = options.output.startsWith("~") ? path30.join(os4.homedir(), options.output.slice(1)) : options.output;
|
|
6013
|
+
outputBase = path30.resolve(projectDir, expandedPath);
|
|
6014
|
+
if (await fileExists(outputBase)) {
|
|
6015
|
+
p12.log.error(`Output path exists as a file: ${outputBase}`);
|
|
6016
|
+
p12.log.info("Please specify a directory path, not a file.");
|
|
6017
|
+
process.exit(EXIT_CODES.INVALID_ARGS);
|
|
6018
|
+
}
|
|
6019
|
+
} else {
|
|
6020
|
+
outputBase = path30.join(projectDir, ".claude");
|
|
6021
|
+
}
|
|
6022
|
+
p12.intro(pc12.cyan("Claude Collective Eject"));
|
|
6023
|
+
if (options.output) {
|
|
6024
|
+
p12.log.info(`Output directory: ${pc12.cyan(outputBase)}`);
|
|
6025
|
+
}
|
|
6026
|
+
const ejectType = type;
|
|
6027
|
+
const directOutput = !!options.output;
|
|
6028
|
+
switch (ejectType) {
|
|
6029
|
+
case "templates":
|
|
6030
|
+
await ejectTemplates(outputBase, options.force, directOutput);
|
|
6031
|
+
break;
|
|
6032
|
+
case "skills":
|
|
6033
|
+
await ejectSkills(outputBase, options.force, directOutput);
|
|
6034
|
+
break;
|
|
6035
|
+
case "config":
|
|
6036
|
+
await ejectConfig(outputBase, options.force, directOutput);
|
|
6037
|
+
break;
|
|
6038
|
+
case "all":
|
|
6039
|
+
await ejectTemplates(outputBase, options.force, directOutput);
|
|
6040
|
+
await ejectSkills(outputBase, options.force, directOutput);
|
|
6041
|
+
await ejectConfig(outputBase, options.force, directOutput);
|
|
6042
|
+
break;
|
|
6043
|
+
}
|
|
6044
|
+
p12.outro(pc12.green("Eject complete!"));
|
|
5994
6045
|
}
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
async function ejectTemplates(projectDir, force) {
|
|
6046
|
+
);
|
|
6047
|
+
async function ejectTemplates(outputBase, force, directOutput = false) {
|
|
5998
6048
|
const sourceDir = path30.join(PROJECT_ROOT, DIRS.templates);
|
|
5999
|
-
const destDir = path30.join(
|
|
6049
|
+
const destDir = directOutput ? outputBase : path30.join(outputBase, "templates");
|
|
6000
6050
|
if (await directoryExists(destDir) && !force) {
|
|
6001
6051
|
p12.log.warn(
|
|
6002
6052
|
`Templates already exist at ${destDir}. Use --force to overwrite.`
|
|
@@ -6010,8 +6060,8 @@ async function ejectTemplates(projectDir, force) {
|
|
|
6010
6060
|
pc12.dim("You can now customize agent.liquid and partials locally.")
|
|
6011
6061
|
);
|
|
6012
6062
|
}
|
|
6013
|
-
async function ejectSkills(
|
|
6014
|
-
const destDir = path30.join(
|
|
6063
|
+
async function ejectSkills(outputBase, force, directOutput = false) {
|
|
6064
|
+
const destDir = directOutput ? outputBase : path30.join(outputBase, "skill-templates");
|
|
6015
6065
|
if (await directoryExists(destDir) && !force) {
|
|
6016
6066
|
p12.log.warn(
|
|
6017
6067
|
`Skill templates already exist at ${destDir}. Use --force to overwrite.`
|
|
@@ -6030,10 +6080,12 @@ async function ejectSkills(projectDir, force) {
|
|
|
6030
6080
|
DEFAULT_METADATA_CONTENT
|
|
6031
6081
|
);
|
|
6032
6082
|
p12.log.success(`Skill templates ejected to ${pc12.cyan(destDir)}`);
|
|
6033
|
-
p12.log.info(
|
|
6083
|
+
p12.log.info(
|
|
6084
|
+
pc12.dim("Copy example-skill/ to your skills/ directory and customize.")
|
|
6085
|
+
);
|
|
6034
6086
|
}
|
|
6035
|
-
async function ejectConfig(
|
|
6036
|
-
const destPath = path30.join(
|
|
6087
|
+
async function ejectConfig(outputBase, force, directOutput = false) {
|
|
6088
|
+
const destPath = path30.join(outputBase, "config.yaml");
|
|
6037
6089
|
if (await fileExists(destPath) && !force) {
|
|
6038
6090
|
p12.log.warn(
|
|
6039
6091
|
`Config already exists at ${destPath}. Use --force to overwrite.`
|