ccski 2.3.1 → 2.4.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/README.md +79 -9
- package/dist/cli.mjs +89 -5
- package/dist/cli.mjs.map +1 -1
- package/dist/{esm-CCJbAK42.mjs → esm-BdE_kIOe.mjs} +2 -2
- package/dist/{esm-CCJbAK42.mjs.map → esm-BdE_kIOe.mjs.map} +1 -1
- package/dist/index.d.mts +93 -29
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{server-y5_8eQ5a.mjs → workflow-install-D85Tfr9z.mjs} +456 -315
- package/dist/workflow-install-D85Tfr9z.mjs.map +1 -0
- package/package.json +1 -1
- package/dist/server-y5_8eQ5a.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { S as __toESM, _ as isSpaceKey, a as useRef, b as __commonJS, c as esm_default$1, d as useState, f as withPointer, g as isNumberKey, h as isEnterKey, i as useKeypress, l as require_yoctocolors_cjs, m as isDownKey, n as breakLines, o as usePrefix, p as ValidationError$1, r as readlineWidth, s as makeTheme, t as createPrompt, u as useEffect, x as __require, y as isUpKey } from "./create-prompt-CIJV_96B.mjs";
|
|
2
|
-
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync } from "node:fs";
|
|
2
|
+
import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { TextDecoder } from "node:util";
|
|
4
4
|
import { homedir, tmpdir } from "node:os";
|
|
5
5
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
@@ -3698,9 +3698,10 @@ const SKILL_SOURCE_PRIORITIES = {
|
|
|
3698
3698
|
plugin: 0,
|
|
3699
3699
|
"user-shared": 100,
|
|
3700
3700
|
"user-agent": 200,
|
|
3701
|
-
"workspace-
|
|
3702
|
-
"workspace-
|
|
3703
|
-
|
|
3701
|
+
"workspace-root": 300,
|
|
3702
|
+
"workspace-shared": 400,
|
|
3703
|
+
"workspace-agent": 500,
|
|
3704
|
+
custom: 600
|
|
3704
3705
|
};
|
|
3705
3706
|
|
|
3706
3707
|
//#endregion
|
|
@@ -12152,7 +12153,7 @@ function getDefaultSkillDirectories(userDir, workspaceDir = process.cwd()) {
|
|
|
12152
12153
|
return uniqueByPath([
|
|
12153
12154
|
...builtInAgentRoots(workspace, "project", "workspace-agent"),
|
|
12154
12155
|
...discoverDynamicAgentRoots(workspace, "project", "workspace-agent"),
|
|
12155
|
-
sharedRoot(join(workspace, "skills"), "project", "workspace-
|
|
12156
|
+
sharedRoot(join(workspace, "skills"), "project", "workspace-root"),
|
|
12156
12157
|
sharedRoot(join(workspace, ".agents", "skills"), "project", "workspace-shared"),
|
|
12157
12158
|
...legacySharedRoot(workspace, "project", "workspace-shared"),
|
|
12158
12159
|
...builtInAgentRoots(user, "user", "user-agent"),
|
|
@@ -14104,28 +14105,6 @@ function buildRegistryOptions(argv$1, extras = {}) {
|
|
|
14104
14105
|
};
|
|
14105
14106
|
}
|
|
14106
14107
|
|
|
14107
|
-
//#endregion
|
|
14108
|
-
//#region src/api/filters.ts
|
|
14109
|
-
function resolveFilters(options, parseOptions = {}) {
|
|
14110
|
-
const includeArgs = options.include;
|
|
14111
|
-
const { includes, excludes } = parseFilters(!includeArgs?.length && options.all ? ["all"] : includeArgs, options.exclude, parseOptions);
|
|
14112
|
-
const state = options.disabled ? "disabled" : options.all ? "all" : "enabled";
|
|
14113
|
-
return {
|
|
14114
|
-
includes,
|
|
14115
|
-
excludes,
|
|
14116
|
-
state,
|
|
14117
|
-
includeDisabled: state === "all" || state === "disabled"
|
|
14118
|
-
};
|
|
14119
|
-
}
|
|
14120
|
-
|
|
14121
|
-
//#endregion
|
|
14122
|
-
//#region src/api/list.ts
|
|
14123
|
-
async function listSkills(options = {}) {
|
|
14124
|
-
const registry = new SkillRegistry(buildRegistryOptions(options, { includeDisabled: resolveFilters(options).includeDisabled }));
|
|
14125
|
-
const { includes, excludes, state } = resolveFilters(options, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
14126
|
-
return applyFilters(registry.getAll(), includes, excludes, state).sort((a, b) => a.name.localeCompare(b.name));
|
|
14127
|
-
}
|
|
14128
|
-
|
|
14129
14108
|
//#endregion
|
|
14130
14109
|
//#region src/utils/resolution.ts
|
|
14131
14110
|
function matchesName(skill, target) {
|
|
@@ -14155,6 +14134,20 @@ function resolveSelectors(skills, selectors) {
|
|
|
14155
14134
|
return selected;
|
|
14156
14135
|
}
|
|
14157
14136
|
|
|
14137
|
+
//#endregion
|
|
14138
|
+
//#region src/api/filters.ts
|
|
14139
|
+
function resolveFilters(options, parseOptions = {}) {
|
|
14140
|
+
const includeArgs = options.include;
|
|
14141
|
+
const { includes, excludes } = parseFilters(!includeArgs?.length && options.all ? ["all"] : includeArgs, options.exclude, parseOptions);
|
|
14142
|
+
const state = options.disabled ? "disabled" : options.all ? "all" : "enabled";
|
|
14143
|
+
return {
|
|
14144
|
+
includes,
|
|
14145
|
+
excludes,
|
|
14146
|
+
state,
|
|
14147
|
+
includeDisabled: state === "all" || state === "disabled"
|
|
14148
|
+
};
|
|
14149
|
+
}
|
|
14150
|
+
|
|
14158
14151
|
//#endregion
|
|
14159
14152
|
//#region src/api/info.ts
|
|
14160
14153
|
async function getSkillInfo(options) {
|
|
@@ -14181,94 +14174,6 @@ async function getSkillInfo(options) {
|
|
|
14181
14174
|
};
|
|
14182
14175
|
}
|
|
14183
14176
|
|
|
14184
|
-
//#endregion
|
|
14185
|
-
//#region src/api/search.ts
|
|
14186
|
-
function buildSearchContext(options) {
|
|
14187
|
-
const registry = new SkillRegistry(buildRegistryOptions(options, { includeDisabled: resolveFilters(options).includeDisabled }));
|
|
14188
|
-
const { includes, excludes, state } = resolveFilters(options, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
14189
|
-
const skills = applyFilters(registry.getAll(), includes, excludes, state);
|
|
14190
|
-
const ranked = rankStrings(skills.map((skill) => `${skill.name} ${skill.description}`), options.query);
|
|
14191
|
-
const picked = ranked.length > 0 ? ranked.map((i$4) => skills[i$4]) : skills;
|
|
14192
|
-
return {
|
|
14193
|
-
registry,
|
|
14194
|
-
matches: options.content ? picked.filter((skill) => {
|
|
14195
|
-
const resolved = resolveSkill(skills, skill.name);
|
|
14196
|
-
const content = registry.load(`${resolved.provider}:${resolved.name}`).content;
|
|
14197
|
-
return containsCaseInsensitive(content, options.query);
|
|
14198
|
-
}) : picked.filter((skill) => containsCaseInsensitive(`${skill.name} ${skill.description}`, options.query))
|
|
14199
|
-
};
|
|
14200
|
-
}
|
|
14201
|
-
function searchSkillsDetailed(options) {
|
|
14202
|
-
const { matches } = buildSearchContext(options);
|
|
14203
|
-
return matches;
|
|
14204
|
-
}
|
|
14205
|
-
async function searchSkills(options) {
|
|
14206
|
-
return searchSkillsDetailed(options).map((skill) => ({
|
|
14207
|
-
name: skill.name,
|
|
14208
|
-
description: skill.description,
|
|
14209
|
-
location: skill.location,
|
|
14210
|
-
provider: skill.provider,
|
|
14211
|
-
disabled: skill.disabled ?? false,
|
|
14212
|
-
path: skill.path
|
|
14213
|
-
}));
|
|
14214
|
-
}
|
|
14215
|
-
|
|
14216
|
-
//#endregion
|
|
14217
|
-
//#region src/api/validate.ts
|
|
14218
|
-
async function validateSkill(options) {
|
|
14219
|
-
const registry = new SkillRegistry(buildRegistryOptions(options));
|
|
14220
|
-
const { includes, excludes, state } = resolveFilters(options, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
14221
|
-
const filtered = applyFilters(registry.getAll(), includes, excludes, state);
|
|
14222
|
-
const target = resolve(options.path);
|
|
14223
|
-
const skillFile = resolveSkillFile(target);
|
|
14224
|
-
if (!skillFile) throw new Error(`Could not find SKILL.md at ${target}`);
|
|
14225
|
-
const result = validateSkillFile(skillFile);
|
|
14226
|
-
const provider = inferProvider(skillFile, filtered);
|
|
14227
|
-
const codexIssues = [];
|
|
14228
|
-
const codexWarnings = [];
|
|
14229
|
-
if (result.success && provider === "codex") try {
|
|
14230
|
-
const parsed = parseSkillFile(skillFile);
|
|
14231
|
-
codexIssues.push(...codexRuleViolations(parsed.frontmatter.name, parsed.frontmatter.description));
|
|
14232
|
-
if (lstatSync(skillFile).isSymbolicLink()) codexWarnings.push(`SKILL.md is a symlink (${skillFile})`);
|
|
14233
|
-
if (lstatSync(resolve(skillFile, "..")).isSymbolicLink()) codexWarnings.push(`Skill directory is a symlink (${resolve(skillFile, "..")})`);
|
|
14234
|
-
} catch {}
|
|
14235
|
-
const errors = [...result.errors, ...codexIssues];
|
|
14236
|
-
const warnings = [...result.suggestions, ...codexWarnings];
|
|
14237
|
-
return {
|
|
14238
|
-
file: skillFile,
|
|
14239
|
-
success: errors.length === 0,
|
|
14240
|
-
errors,
|
|
14241
|
-
warnings
|
|
14242
|
-
};
|
|
14243
|
-
}
|
|
14244
|
-
function resolveSkillFile(input) {
|
|
14245
|
-
if (!existsSync(input)) return null;
|
|
14246
|
-
const stats = statSync(input);
|
|
14247
|
-
if (stats.isDirectory()) {
|
|
14248
|
-
const candidate = join(input, "SKILL.md");
|
|
14249
|
-
return existsSync(candidate) ? candidate : null;
|
|
14250
|
-
}
|
|
14251
|
-
if (stats.isFile() && input.toLowerCase().endsWith("skill.md")) return input;
|
|
14252
|
-
return null;
|
|
14253
|
-
}
|
|
14254
|
-
function inferProvider(skillPath, filtered) {
|
|
14255
|
-
const lower = skillPath.toLowerCase();
|
|
14256
|
-
const match = filtered.find((s) => s.path === resolve(skillPath, ".."));
|
|
14257
|
-
if (match) return match.provider;
|
|
14258
|
-
const provider = lower.split("/").find((segment) => segment.startsWith("."))?.slice(1);
|
|
14259
|
-
if (provider === "agent" || provider === "agents") return "agents";
|
|
14260
|
-
if (provider && lower.includes(`/.${provider}/skills`)) return provider;
|
|
14261
|
-
return "file";
|
|
14262
|
-
}
|
|
14263
|
-
function codexRuleViolations(name, description) {
|
|
14264
|
-
const issues = [];
|
|
14265
|
-
if (name.length > 100) issues.push("Codex rule: name exceeds 100 characters");
|
|
14266
|
-
if (description.length > 500) issues.push("Codex rule: description exceeds 500 characters");
|
|
14267
|
-
if (name.includes("\n")) issues.push("Codex rule: name must be single-line");
|
|
14268
|
-
if (description.includes("\n")) issues.push("Codex rule: description must be single-line");
|
|
14269
|
-
return issues;
|
|
14270
|
-
}
|
|
14271
|
-
|
|
14272
14177
|
//#endregion
|
|
14273
14178
|
//#region src/cli/prompts/commandBuilder.ts
|
|
14274
14179
|
/**
|
|
@@ -14397,7 +14302,7 @@ var InteractiveCommandBuilder = class InteractiveCommandBuilder {
|
|
|
14397
14302
|
console.log(`${tone.bold("Command:")}`);
|
|
14398
14303
|
console.log(` ${tone.accent(this.buildFull())}`);
|
|
14399
14304
|
console.log();
|
|
14400
|
-
const { confirm } = await import("./esm-
|
|
14305
|
+
const { confirm } = await import("./esm-BdE_kIOe.mjs");
|
|
14401
14306
|
return confirm({
|
|
14402
14307
|
message: "Proceed?",
|
|
14403
14308
|
default: true
|
|
@@ -15751,8 +15656,10 @@ function buildPreview(selection, destinations) {
|
|
|
15751
15656
|
}
|
|
15752
15657
|
async function installSkills(options, output = silentOutput$1) {
|
|
15753
15658
|
try {
|
|
15754
|
-
|
|
15755
|
-
const
|
|
15659
|
+
if (!options.source) throw new Error("installSkills requires a source. Use installCcskiWorkflow for workflow setup.");
|
|
15660
|
+
const source = options.source;
|
|
15661
|
+
const parsed = parseGitUrl(source);
|
|
15662
|
+
const resolvedSource = parsed?.repo ?? source;
|
|
15756
15663
|
const resolvedBranch = options.branch ?? parsed?.branch;
|
|
15757
15664
|
const resolvedPath = options.path ?? (parsed?.type === "blob" ? parsed.path : void 0);
|
|
15758
15665
|
const cmdBuilder = new InteractiveCommandBuilder("ccski install");
|
|
@@ -15761,14 +15668,14 @@ async function installSkills(options, output = silentOutput$1) {
|
|
|
15761
15668
|
if (resolvedPath) cmdBuilder.addArg("path", resolvedPath);
|
|
15762
15669
|
if (options.force || options.override) cmdBuilder.addFlag("force");
|
|
15763
15670
|
const destinations = await resolveDestinations(options, cmdBuilder, output);
|
|
15764
|
-
const materialized = await materializeSource(
|
|
15671
|
+
const materialized = await materializeSource(source, {
|
|
15765
15672
|
...options.mode ? { mode: options.mode } : {},
|
|
15766
15673
|
...options.branch ? { branch: options.branch } : {},
|
|
15767
15674
|
...options.timeout ? { timeout: options.timeout } : {}
|
|
15768
15675
|
}, output);
|
|
15769
15676
|
const explicitPath = options.path ?? materialized.useHint;
|
|
15770
15677
|
if (materialized.useHint && !resolvedPath) cmdBuilder.addArg("path", materialized.useHint);
|
|
15771
|
-
const sourceArgs = buildSourceArgs(
|
|
15678
|
+
const sourceArgs = buildSourceArgs(source, materialized.branch ?? options.branch, explicitPath, materialized.repo);
|
|
15772
15679
|
const sourceLabel = formatSourceLabel(sourceArgs.source, sourceArgs.branch, sourceArgs.path);
|
|
15773
15680
|
const targets = resolveInstallTargets(materialized.base, explicitPath, sourceLabel);
|
|
15774
15681
|
if (targets.length === 0) throw new Error(`No skills found for ${sourceLabel}. Resolved directory: ${materialized.base}`);
|
|
@@ -15830,199 +15737,11 @@ async function installSkills(options, output = silentOutput$1) {
|
|
|
15830
15737
|
}
|
|
15831
15738
|
|
|
15832
15739
|
//#endregion
|
|
15833
|
-
//#region src/api/
|
|
15834
|
-
|
|
15835
|
-
|
|
15836
|
-
const
|
|
15837
|
-
|
|
15838
|
-
const skills = applyFilters(registry.getAll(), includes, excludes, "all");
|
|
15839
|
-
const candidates = mode === "disable" ? skills.filter((s) => !s.disabled) : skills.filter((s) => s.disabled);
|
|
15840
|
-
if (candidates.length === 0) return {
|
|
15841
|
-
mode,
|
|
15842
|
-
results: [],
|
|
15843
|
-
succeeded: 0,
|
|
15844
|
-
skipped: 0,
|
|
15845
|
-
failed: 0
|
|
15846
|
-
};
|
|
15847
|
-
const cmdBuilder = new InteractiveCommandBuilder(`ccski ${mode}`);
|
|
15848
|
-
if (options.include?.length) cmdBuilder.addArg("include", options.include);
|
|
15849
|
-
if (options.exclude?.length) cmdBuilder.addArg("exclude", options.exclude);
|
|
15850
|
-
const force = options.force === true || options.override === true;
|
|
15851
|
-
if (force) cmdBuilder.addFlag("force");
|
|
15852
|
-
const selected = await pickSkills(mode, candidates, options, cmdBuilder);
|
|
15853
|
-
const conflicts = detectConflicts(selected);
|
|
15854
|
-
if (options.interactive && selected.length > 0 && !options.yes) {
|
|
15855
|
-
if (!await confirmToggle(mode, cmdBuilder, selected, conflicts, force, output)) throw new ToggleCancelledError(mode);
|
|
15856
|
-
}
|
|
15857
|
-
const results = [];
|
|
15858
|
-
for (const skill of selected) results.push(executeToggle(mode, skill, force));
|
|
15859
|
-
return {
|
|
15860
|
-
mode,
|
|
15861
|
-
results,
|
|
15862
|
-
succeeded: results.filter((r) => r.status === `${mode}d`).length,
|
|
15863
|
-
skipped: results.filter((r) => r.status === "skipped").length,
|
|
15864
|
-
failed: results.filter((r) => r.status === "failed").length
|
|
15865
|
-
};
|
|
15866
|
-
}
|
|
15867
|
-
var MultiSelectError = class extends Error {
|
|
15868
|
-
constructor(message, listing) {
|
|
15869
|
-
super(message);
|
|
15870
|
-
this.listing = listing;
|
|
15871
|
-
this.name = "MultiSelectError";
|
|
15872
|
-
}
|
|
15873
|
-
};
|
|
15874
|
-
var ToggleCancelledError = class extends Error {
|
|
15875
|
-
constructor(mode) {
|
|
15876
|
-
super(`${mode} cancelled`);
|
|
15877
|
-
this.mode = mode;
|
|
15878
|
-
this.name = "ToggleCancelledError";
|
|
15879
|
-
}
|
|
15880
|
-
};
|
|
15881
|
-
function detectConflicts(skills) {
|
|
15882
|
-
const conflicts = [];
|
|
15883
|
-
for (const skill of skills) {
|
|
15884
|
-
const skillFile = join(skill.path, "SKILL.md");
|
|
15885
|
-
const disabledFile = join(skill.path, ".SKILL.md");
|
|
15886
|
-
const hasSkill = existsSync(skillFile);
|
|
15887
|
-
const hasDisabled = existsSync(disabledFile);
|
|
15888
|
-
if (hasSkill && hasDisabled) conflicts.push({
|
|
15889
|
-
skill: skill.name,
|
|
15890
|
-
path: skill.path,
|
|
15891
|
-
reason: "Both SKILL.md and .SKILL.md exist"
|
|
15892
|
-
});
|
|
15893
|
-
}
|
|
15894
|
-
return conflicts;
|
|
15895
|
-
}
|
|
15896
|
-
function executeToggle(mode, skill, force) {
|
|
15897
|
-
const skillFile = join(skill.path, "SKILL.md");
|
|
15898
|
-
const disabledFile = join(skill.path, ".SKILL.md");
|
|
15899
|
-
const hasSkill = existsSync(skillFile);
|
|
15900
|
-
const hasDisabled = existsSync(disabledFile);
|
|
15901
|
-
try {
|
|
15902
|
-
if (mode === "disable") {
|
|
15903
|
-
if (!hasSkill && hasDisabled) return {
|
|
15904
|
-
skill: skill.name,
|
|
15905
|
-
path: skill.path,
|
|
15906
|
-
status: "skipped",
|
|
15907
|
-
error: "Already disabled"
|
|
15908
|
-
};
|
|
15909
|
-
if (hasSkill && hasDisabled && !force) return {
|
|
15910
|
-
skill: skill.name,
|
|
15911
|
-
path: skill.path,
|
|
15912
|
-
status: "skipped",
|
|
15913
|
-
error: "Both files exist, use --force"
|
|
15914
|
-
};
|
|
15915
|
-
if (hasDisabled && force) rmSync(disabledFile);
|
|
15916
|
-
if (hasSkill) renameSync(skillFile, disabledFile);
|
|
15917
|
-
return {
|
|
15918
|
-
skill: skill.name,
|
|
15919
|
-
path: skill.path,
|
|
15920
|
-
status: "disabled"
|
|
15921
|
-
};
|
|
15922
|
-
}
|
|
15923
|
-
if (hasSkill && !hasDisabled) return {
|
|
15924
|
-
skill: skill.name,
|
|
15925
|
-
path: skill.path,
|
|
15926
|
-
status: "skipped",
|
|
15927
|
-
error: "Already enabled"
|
|
15928
|
-
};
|
|
15929
|
-
if (hasSkill && hasDisabled && !force) return {
|
|
15930
|
-
skill: skill.name,
|
|
15931
|
-
path: skill.path,
|
|
15932
|
-
status: "skipped",
|
|
15933
|
-
error: "Both files exist, use --force"
|
|
15934
|
-
};
|
|
15935
|
-
if (hasSkill && force) rmSync(skillFile);
|
|
15936
|
-
if (!hasDisabled) return {
|
|
15937
|
-
skill: skill.name,
|
|
15938
|
-
path: skill.path,
|
|
15939
|
-
status: "failed",
|
|
15940
|
-
error: "No .SKILL.md found"
|
|
15941
|
-
};
|
|
15942
|
-
renameSync(disabledFile, skillFile);
|
|
15943
|
-
return {
|
|
15944
|
-
skill: skill.name,
|
|
15945
|
-
path: skill.path,
|
|
15946
|
-
status: "enabled"
|
|
15947
|
-
};
|
|
15948
|
-
} catch (err) {
|
|
15949
|
-
return {
|
|
15950
|
-
skill: skill.name,
|
|
15951
|
-
path: skill.path,
|
|
15952
|
-
status: "failed",
|
|
15953
|
-
error: err instanceof Error ? err.message : String(err)
|
|
15954
|
-
};
|
|
15955
|
-
}
|
|
15956
|
-
}
|
|
15957
|
-
async function confirmToggle(mode, cmdBuilder, selected, conflicts, force, output) {
|
|
15958
|
-
output.log();
|
|
15959
|
-
output.log(heading(`${capitalize(mode)} Summary`));
|
|
15960
|
-
output.log();
|
|
15961
|
-
output.log(`${tone.bold("Skills:")} ${selected.length} selected`);
|
|
15962
|
-
for (const skill of selected) output.log(` ${tone.primary("•")} ${skill.name} ${dim(`(${skill.location})`)}`);
|
|
15963
|
-
output.log();
|
|
15964
|
-
if (conflicts.length > 0) {
|
|
15965
|
-
if (force) output.log(`${tone.warning("Will overwrite:")} ${conflicts.length} skill(s) with conflicts`);
|
|
15966
|
-
else output.log(`${tone.warning("Will skip:")} ${conflicts.length} skill(s) with conflicts`);
|
|
15967
|
-
for (const c of conflicts.slice(0, 5)) output.log(` ${tone.warning("•")} ${c.skill}: ${dim(c.reason)}`);
|
|
15968
|
-
if (conflicts.length > 5) output.log(dim(` ... and ${conflicts.length - 5} more`));
|
|
15969
|
-
output.log();
|
|
15970
|
-
}
|
|
15971
|
-
output.log(`${tone.bold("Command:")}`);
|
|
15972
|
-
output.log(` ${tone.accent(cmdBuilder.buildFull())}`);
|
|
15973
|
-
output.log();
|
|
15974
|
-
const { confirm } = await import("./esm-CCJbAK42.mjs");
|
|
15975
|
-
return confirm({
|
|
15976
|
-
message: "Proceed?",
|
|
15977
|
-
default: true
|
|
15978
|
-
});
|
|
15979
|
-
}
|
|
15980
|
-
async function pickSkills(mode, candidates, options, cmdBuilder) {
|
|
15981
|
-
const selectors = parseNames(options);
|
|
15982
|
-
const listing = `${heading(mode === "disable" ? "Enabled skills" : "Disabled skills")} (${candidates.length})\n${renderList(skillsToListItems(candidates))}`;
|
|
15983
|
-
if (options.all) {
|
|
15984
|
-
cmdBuilder.addFlag("all");
|
|
15985
|
-
return candidates;
|
|
15986
|
-
}
|
|
15987
|
-
if (selectors.length > 0) {
|
|
15988
|
-
cmdBuilder.addArg("names", selectors, { positional: true });
|
|
15989
|
-
return resolveSelectors(candidates, selectors);
|
|
15990
|
-
}
|
|
15991
|
-
if (options.interactive) {
|
|
15992
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new MultiSelectError("Interactive mode requires a TTY.", listing);
|
|
15993
|
-
cmdBuilder.addArg("names", candidates.map((c) => c.name), {
|
|
15994
|
-
positional: true,
|
|
15995
|
-
totalChoices: candidates.length,
|
|
15996
|
-
shortRender: (values, total) => {
|
|
15997
|
-
if (total && values.length === total && values.length > 1) return ["--all"];
|
|
15998
|
-
if (values.length <= 3) return values;
|
|
15999
|
-
return [...values.slice(0, 3), `... (+${values.length - 3} more)`];
|
|
16000
|
-
}
|
|
16001
|
-
});
|
|
16002
|
-
const names$1 = await promptMultiSelect({
|
|
16003
|
-
message: mode === "disable" ? "Select skills to disable" : "Select skills to enable",
|
|
16004
|
-
choices: candidates.map((skill) => ({
|
|
16005
|
-
value: skill.name,
|
|
16006
|
-
label: formatSkillChoiceLabel(skill),
|
|
16007
|
-
description: skill.description,
|
|
16008
|
-
checked: false
|
|
16009
|
-
})),
|
|
16010
|
-
defaultChecked: false,
|
|
16011
|
-
commandBuilder: cmdBuilder,
|
|
16012
|
-
commandArgKey: "names"
|
|
16013
|
-
});
|
|
16014
|
-
if (!Array.isArray(names$1) || names$1.length === 0) throw new MultiSelectError("No skills selected.", listing);
|
|
16015
|
-
cmdBuilder.updateArg("names", names$1);
|
|
16016
|
-
const pickedSet = new Set(names$1.map((n) => n.toLowerCase()));
|
|
16017
|
-
return candidates.filter((c) => skillAliases(c).some((alias) => pickedSet.has(alias)));
|
|
16018
|
-
}
|
|
16019
|
-
throw new MultiSelectError("Multiple skills available. Provide names, use --all, or enable interactive mode (-i).", listing);
|
|
16020
|
-
}
|
|
16021
|
-
function parseNames(options) {
|
|
16022
|
-
return [].concat(Array.isArray(options.names) ? options.names : []).flatMap((item) => item.split(/[\\/,]/)).map((s) => s.trim()).filter(Boolean);
|
|
16023
|
-
}
|
|
16024
|
-
function capitalize(value) {
|
|
16025
|
-
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
15740
|
+
//#region src/api/list.ts
|
|
15741
|
+
async function listSkills(options = {}) {
|
|
15742
|
+
const registry = new SkillRegistry(buildRegistryOptions(options, { includeDisabled: resolveFilters(options).includeDisabled }));
|
|
15743
|
+
const { includes, excludes, state } = resolveFilters(options, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
15744
|
+
return applyFilters(registry.getAll(), includes, excludes, state).sort((a, b) => a.name.localeCompare(b.name));
|
|
16026
15745
|
}
|
|
16027
15746
|
|
|
16028
15747
|
//#endregion
|
|
@@ -34593,5 +34312,427 @@ function formatSkillContent(skill) {
|
|
|
34593
34312
|
}
|
|
34594
34313
|
|
|
34595
34314
|
//#endregion
|
|
34596
|
-
|
|
34597
|
-
|
|
34315
|
+
//#region src/api/search.ts
|
|
34316
|
+
function buildSearchContext(options) {
|
|
34317
|
+
const registry = new SkillRegistry(buildRegistryOptions(options, { includeDisabled: resolveFilters(options).includeDisabled }));
|
|
34318
|
+
const { includes, excludes, state } = resolveFilters(options, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
34319
|
+
const skills = applyFilters(registry.getAll(), includes, excludes, state);
|
|
34320
|
+
const ranked = rankStrings(skills.map((skill) => `${skill.name} ${skill.description}`), options.query);
|
|
34321
|
+
const picked = ranked.length > 0 ? ranked.map((i$4) => skills[i$4]) : skills;
|
|
34322
|
+
return {
|
|
34323
|
+
registry,
|
|
34324
|
+
matches: options.content ? picked.filter((skill) => {
|
|
34325
|
+
const resolved = resolveSkill(skills, skill.name);
|
|
34326
|
+
const content = registry.load(`${resolved.provider}:${resolved.name}`).content;
|
|
34327
|
+
return containsCaseInsensitive(content, options.query);
|
|
34328
|
+
}) : picked.filter((skill) => containsCaseInsensitive(`${skill.name} ${skill.description}`, options.query))
|
|
34329
|
+
};
|
|
34330
|
+
}
|
|
34331
|
+
function searchSkillsDetailed(options) {
|
|
34332
|
+
const { matches } = buildSearchContext(options);
|
|
34333
|
+
return matches;
|
|
34334
|
+
}
|
|
34335
|
+
async function searchSkills(options) {
|
|
34336
|
+
return searchSkillsDetailed(options).map((skill) => ({
|
|
34337
|
+
name: skill.name,
|
|
34338
|
+
description: skill.description,
|
|
34339
|
+
location: skill.location,
|
|
34340
|
+
provider: skill.provider,
|
|
34341
|
+
disabled: skill.disabled ?? false,
|
|
34342
|
+
path: skill.path
|
|
34343
|
+
}));
|
|
34344
|
+
}
|
|
34345
|
+
|
|
34346
|
+
//#endregion
|
|
34347
|
+
//#region src/api/toggle.ts
|
|
34348
|
+
const silentOutput = { log: () => {} };
|
|
34349
|
+
async function toggleSkills(mode, options, output = silentOutput) {
|
|
34350
|
+
const registry = new SkillRegistry(buildRegistryOptions(options, { includeDisabled: true }));
|
|
34351
|
+
const { includes, excludes } = parseFilters(options.include, options.exclude, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
34352
|
+
const skills = applyFilters(registry.getAll(), includes, excludes, "all");
|
|
34353
|
+
const candidates = mode === "disable" ? skills.filter((s) => !s.disabled) : skills.filter((s) => s.disabled);
|
|
34354
|
+
if (candidates.length === 0) return {
|
|
34355
|
+
mode,
|
|
34356
|
+
results: [],
|
|
34357
|
+
succeeded: 0,
|
|
34358
|
+
skipped: 0,
|
|
34359
|
+
failed: 0
|
|
34360
|
+
};
|
|
34361
|
+
const cmdBuilder = new InteractiveCommandBuilder(`ccski ${mode}`);
|
|
34362
|
+
if (options.include?.length) cmdBuilder.addArg("include", options.include);
|
|
34363
|
+
if (options.exclude?.length) cmdBuilder.addArg("exclude", options.exclude);
|
|
34364
|
+
const force = options.force === true || options.override === true;
|
|
34365
|
+
if (force) cmdBuilder.addFlag("force");
|
|
34366
|
+
const selected = await pickSkills(mode, candidates, options, cmdBuilder);
|
|
34367
|
+
const conflicts = detectConflicts(selected);
|
|
34368
|
+
if (options.interactive && selected.length > 0 && !options.yes) {
|
|
34369
|
+
if (!await confirmToggle(mode, cmdBuilder, selected, conflicts, force, output)) throw new ToggleCancelledError(mode);
|
|
34370
|
+
}
|
|
34371
|
+
const results = [];
|
|
34372
|
+
for (const skill of selected) results.push(executeToggle(mode, skill, force));
|
|
34373
|
+
return {
|
|
34374
|
+
mode,
|
|
34375
|
+
results,
|
|
34376
|
+
succeeded: results.filter((r) => r.status === `${mode}d`).length,
|
|
34377
|
+
skipped: results.filter((r) => r.status === "skipped").length,
|
|
34378
|
+
failed: results.filter((r) => r.status === "failed").length
|
|
34379
|
+
};
|
|
34380
|
+
}
|
|
34381
|
+
var MultiSelectError = class extends Error {
|
|
34382
|
+
constructor(message, listing) {
|
|
34383
|
+
super(message);
|
|
34384
|
+
this.listing = listing;
|
|
34385
|
+
this.name = "MultiSelectError";
|
|
34386
|
+
}
|
|
34387
|
+
};
|
|
34388
|
+
var ToggleCancelledError = class extends Error {
|
|
34389
|
+
constructor(mode) {
|
|
34390
|
+
super(`${mode} cancelled`);
|
|
34391
|
+
this.mode = mode;
|
|
34392
|
+
this.name = "ToggleCancelledError";
|
|
34393
|
+
}
|
|
34394
|
+
};
|
|
34395
|
+
function detectConflicts(skills) {
|
|
34396
|
+
const conflicts = [];
|
|
34397
|
+
for (const skill of skills) {
|
|
34398
|
+
const skillFile = join(skill.path, "SKILL.md");
|
|
34399
|
+
const disabledFile = join(skill.path, ".SKILL.md");
|
|
34400
|
+
const hasSkill = existsSync(skillFile);
|
|
34401
|
+
const hasDisabled = existsSync(disabledFile);
|
|
34402
|
+
if (hasSkill && hasDisabled) conflicts.push({
|
|
34403
|
+
skill: skill.name,
|
|
34404
|
+
path: skill.path,
|
|
34405
|
+
reason: "Both SKILL.md and .SKILL.md exist"
|
|
34406
|
+
});
|
|
34407
|
+
}
|
|
34408
|
+
return conflicts;
|
|
34409
|
+
}
|
|
34410
|
+
function executeToggle(mode, skill, force) {
|
|
34411
|
+
const skillFile = join(skill.path, "SKILL.md");
|
|
34412
|
+
const disabledFile = join(skill.path, ".SKILL.md");
|
|
34413
|
+
const hasSkill = existsSync(skillFile);
|
|
34414
|
+
const hasDisabled = existsSync(disabledFile);
|
|
34415
|
+
try {
|
|
34416
|
+
if (mode === "disable") {
|
|
34417
|
+
if (!hasSkill && hasDisabled) return {
|
|
34418
|
+
skill: skill.name,
|
|
34419
|
+
path: skill.path,
|
|
34420
|
+
status: "skipped",
|
|
34421
|
+
error: "Already disabled"
|
|
34422
|
+
};
|
|
34423
|
+
if (hasSkill && hasDisabled && !force) return {
|
|
34424
|
+
skill: skill.name,
|
|
34425
|
+
path: skill.path,
|
|
34426
|
+
status: "skipped",
|
|
34427
|
+
error: "Both files exist, use --force"
|
|
34428
|
+
};
|
|
34429
|
+
if (hasDisabled && force) rmSync(disabledFile);
|
|
34430
|
+
if (hasSkill) renameSync(skillFile, disabledFile);
|
|
34431
|
+
return {
|
|
34432
|
+
skill: skill.name,
|
|
34433
|
+
path: skill.path,
|
|
34434
|
+
status: "disabled"
|
|
34435
|
+
};
|
|
34436
|
+
}
|
|
34437
|
+
if (hasSkill && !hasDisabled) return {
|
|
34438
|
+
skill: skill.name,
|
|
34439
|
+
path: skill.path,
|
|
34440
|
+
status: "skipped",
|
|
34441
|
+
error: "Already enabled"
|
|
34442
|
+
};
|
|
34443
|
+
if (hasSkill && hasDisabled && !force) return {
|
|
34444
|
+
skill: skill.name,
|
|
34445
|
+
path: skill.path,
|
|
34446
|
+
status: "skipped",
|
|
34447
|
+
error: "Both files exist, use --force"
|
|
34448
|
+
};
|
|
34449
|
+
if (hasSkill && force) rmSync(skillFile);
|
|
34450
|
+
if (!hasDisabled) return {
|
|
34451
|
+
skill: skill.name,
|
|
34452
|
+
path: skill.path,
|
|
34453
|
+
status: "failed",
|
|
34454
|
+
error: "No .SKILL.md found"
|
|
34455
|
+
};
|
|
34456
|
+
renameSync(disabledFile, skillFile);
|
|
34457
|
+
return {
|
|
34458
|
+
skill: skill.name,
|
|
34459
|
+
path: skill.path,
|
|
34460
|
+
status: "enabled"
|
|
34461
|
+
};
|
|
34462
|
+
} catch (err) {
|
|
34463
|
+
return {
|
|
34464
|
+
skill: skill.name,
|
|
34465
|
+
path: skill.path,
|
|
34466
|
+
status: "failed",
|
|
34467
|
+
error: err instanceof Error ? err.message : String(err)
|
|
34468
|
+
};
|
|
34469
|
+
}
|
|
34470
|
+
}
|
|
34471
|
+
async function confirmToggle(mode, cmdBuilder, selected, conflicts, force, output) {
|
|
34472
|
+
output.log();
|
|
34473
|
+
output.log(heading(`${capitalize(mode)} Summary`));
|
|
34474
|
+
output.log();
|
|
34475
|
+
output.log(`${tone.bold("Skills:")} ${selected.length} selected`);
|
|
34476
|
+
for (const skill of selected) output.log(` ${tone.primary("•")} ${skill.name} ${dim(`(${skill.location})`)}`);
|
|
34477
|
+
output.log();
|
|
34478
|
+
if (conflicts.length > 0) {
|
|
34479
|
+
if (force) output.log(`${tone.warning("Will overwrite:")} ${conflicts.length} skill(s) with conflicts`);
|
|
34480
|
+
else output.log(`${tone.warning("Will skip:")} ${conflicts.length} skill(s) with conflicts`);
|
|
34481
|
+
for (const c of conflicts.slice(0, 5)) output.log(` ${tone.warning("•")} ${c.skill}: ${dim(c.reason)}`);
|
|
34482
|
+
if (conflicts.length > 5) output.log(dim(` ... and ${conflicts.length - 5} more`));
|
|
34483
|
+
output.log();
|
|
34484
|
+
}
|
|
34485
|
+
output.log(`${tone.bold("Command:")}`);
|
|
34486
|
+
output.log(` ${tone.accent(cmdBuilder.buildFull())}`);
|
|
34487
|
+
output.log();
|
|
34488
|
+
const { confirm } = await import("./esm-BdE_kIOe.mjs");
|
|
34489
|
+
return confirm({
|
|
34490
|
+
message: "Proceed?",
|
|
34491
|
+
default: true
|
|
34492
|
+
});
|
|
34493
|
+
}
|
|
34494
|
+
async function pickSkills(mode, candidates, options, cmdBuilder) {
|
|
34495
|
+
const selectors = parseNames(options);
|
|
34496
|
+
const listing = `${heading(mode === "disable" ? "Enabled skills" : "Disabled skills")} (${candidates.length})\n${renderList(skillsToListItems(candidates))}`;
|
|
34497
|
+
if (options.all) {
|
|
34498
|
+
cmdBuilder.addFlag("all");
|
|
34499
|
+
return candidates;
|
|
34500
|
+
}
|
|
34501
|
+
if (selectors.length > 0) {
|
|
34502
|
+
cmdBuilder.addArg("names", selectors, { positional: true });
|
|
34503
|
+
return resolveSelectors(candidates, selectors);
|
|
34504
|
+
}
|
|
34505
|
+
if (options.interactive) {
|
|
34506
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) throw new MultiSelectError("Interactive mode requires a TTY.", listing);
|
|
34507
|
+
cmdBuilder.addArg("names", candidates.map((c) => c.name), {
|
|
34508
|
+
positional: true,
|
|
34509
|
+
totalChoices: candidates.length,
|
|
34510
|
+
shortRender: (values, total) => {
|
|
34511
|
+
if (total && values.length === total && values.length > 1) return ["--all"];
|
|
34512
|
+
if (values.length <= 3) return values;
|
|
34513
|
+
return [...values.slice(0, 3), `... (+${values.length - 3} more)`];
|
|
34514
|
+
}
|
|
34515
|
+
});
|
|
34516
|
+
const names$1 = await promptMultiSelect({
|
|
34517
|
+
message: mode === "disable" ? "Select skills to disable" : "Select skills to enable",
|
|
34518
|
+
choices: candidates.map((skill) => ({
|
|
34519
|
+
value: skill.name,
|
|
34520
|
+
label: formatSkillChoiceLabel(skill),
|
|
34521
|
+
description: skill.description,
|
|
34522
|
+
checked: false
|
|
34523
|
+
})),
|
|
34524
|
+
defaultChecked: false,
|
|
34525
|
+
commandBuilder: cmdBuilder,
|
|
34526
|
+
commandArgKey: "names"
|
|
34527
|
+
});
|
|
34528
|
+
if (!Array.isArray(names$1) || names$1.length === 0) throw new MultiSelectError("No skills selected.", listing);
|
|
34529
|
+
cmdBuilder.updateArg("names", names$1);
|
|
34530
|
+
const pickedSet = new Set(names$1.map((n) => n.toLowerCase()));
|
|
34531
|
+
return candidates.filter((c) => skillAliases(c).some((alias) => pickedSet.has(alias)));
|
|
34532
|
+
}
|
|
34533
|
+
throw new MultiSelectError("Multiple skills available. Provide names, use --all, or enable interactive mode (-i).", listing);
|
|
34534
|
+
}
|
|
34535
|
+
function parseNames(options) {
|
|
34536
|
+
return [].concat(Array.isArray(options.names) ? options.names : []).flatMap((item) => item.split(/[\\/,]/)).map((s) => s.trim()).filter(Boolean);
|
|
34537
|
+
}
|
|
34538
|
+
function capitalize(value) {
|
|
34539
|
+
return value.charAt(0).toUpperCase() + value.slice(1);
|
|
34540
|
+
}
|
|
34541
|
+
|
|
34542
|
+
//#endregion
|
|
34543
|
+
//#region src/api/validate.ts
|
|
34544
|
+
async function validateSkill(options) {
|
|
34545
|
+
const registry = new SkillRegistry(buildRegistryOptions(options));
|
|
34546
|
+
const { includes, excludes, state } = resolveFilters(options, { providers: providerNamesFromSkills(registry.getAll()) });
|
|
34547
|
+
const filtered = applyFilters(registry.getAll(), includes, excludes, state);
|
|
34548
|
+
const target = resolve(options.path);
|
|
34549
|
+
const skillFile = resolveSkillFile(target);
|
|
34550
|
+
if (!skillFile) throw new Error(`Could not find SKILL.md at ${target}`);
|
|
34551
|
+
const result = validateSkillFile(skillFile);
|
|
34552
|
+
const provider = inferProvider(skillFile, filtered);
|
|
34553
|
+
const codexIssues = [];
|
|
34554
|
+
const codexWarnings = [];
|
|
34555
|
+
if (result.success && provider === "codex") try {
|
|
34556
|
+
const parsed = parseSkillFile(skillFile);
|
|
34557
|
+
codexIssues.push(...codexRuleViolations(parsed.frontmatter.name, parsed.frontmatter.description));
|
|
34558
|
+
if (lstatSync(skillFile).isSymbolicLink()) codexWarnings.push(`SKILL.md is a symlink (${skillFile})`);
|
|
34559
|
+
if (lstatSync(resolve(skillFile, "..")).isSymbolicLink()) codexWarnings.push(`Skill directory is a symlink (${resolve(skillFile, "..")})`);
|
|
34560
|
+
} catch {}
|
|
34561
|
+
const errors = [...result.errors, ...codexIssues];
|
|
34562
|
+
const warnings = [...result.suggestions, ...codexWarnings];
|
|
34563
|
+
return {
|
|
34564
|
+
file: skillFile,
|
|
34565
|
+
success: errors.length === 0,
|
|
34566
|
+
errors,
|
|
34567
|
+
warnings
|
|
34568
|
+
};
|
|
34569
|
+
}
|
|
34570
|
+
function resolveSkillFile(input) {
|
|
34571
|
+
if (!existsSync(input)) return null;
|
|
34572
|
+
const stats = statSync(input);
|
|
34573
|
+
if (stats.isDirectory()) {
|
|
34574
|
+
const candidate = join(input, "SKILL.md");
|
|
34575
|
+
return existsSync(candidate) ? candidate : null;
|
|
34576
|
+
}
|
|
34577
|
+
if (stats.isFile() && input.toLowerCase().endsWith("skill.md")) return input;
|
|
34578
|
+
return null;
|
|
34579
|
+
}
|
|
34580
|
+
function inferProvider(skillPath, filtered) {
|
|
34581
|
+
const lower = skillPath.toLowerCase();
|
|
34582
|
+
const match = filtered.find((s) => s.path === resolve(skillPath, ".."));
|
|
34583
|
+
if (match) return match.provider;
|
|
34584
|
+
const provider = lower.split("/").find((segment) => segment.startsWith("."))?.slice(1);
|
|
34585
|
+
if (provider === "agent" || provider === "agents") return "agents";
|
|
34586
|
+
if (provider && lower.includes(`/.${provider}/skills`)) return provider;
|
|
34587
|
+
return "file";
|
|
34588
|
+
}
|
|
34589
|
+
function codexRuleViolations(name, description) {
|
|
34590
|
+
const issues = [];
|
|
34591
|
+
if (name.length > 100) issues.push("Codex rule: name exceeds 100 characters");
|
|
34592
|
+
if (description.length > 500) issues.push("Codex rule: description exceeds 500 characters");
|
|
34593
|
+
if (name.includes("\n")) issues.push("Codex rule: name must be single-line");
|
|
34594
|
+
if (description.includes("\n")) issues.push("Codex rule: description must be single-line");
|
|
34595
|
+
return issues;
|
|
34596
|
+
}
|
|
34597
|
+
|
|
34598
|
+
//#endregion
|
|
34599
|
+
//#region src/api/workflow-install.ts
|
|
34600
|
+
const WORKFLOW_BLOCK = `<workflow name="ccski">
|
|
34601
|
+
When starting a new context, run \`bunx ccski list --no-color\` to discover extra local skills available on this machine, especially shared \`agents:user\` skills and agent-specific skills such as \`claude:user\`, \`codex:user\`, and \`gemini:user\`.
|
|
34602
|
+
If the user names a skill, or a task clearly matches a skill that is not already exposed in the current session, do not assume the skill is unavailable. First run \`bunx ccski list --no-color\`, then run \`bunx ccski info <name>\` and load the \`SKILL.md\` path reported by the output.
|
|
34603
|
+
\`ccski\` may emit compatibility warnings while reading local agent or plugin metadata, such as \`installed_plugins.json\`. These warnings do not necessarily block \`list\` or \`info\`; prefer \`--no-color\` for readable output and downstream parsing.
|
|
34604
|
+
</workflow>`;
|
|
34605
|
+
const WORKFLOW_BLOCK_PATTERN = /<workflow\s+name=["']ccski["'][^>]*>[\s\S]*?<\/workflow>/m;
|
|
34606
|
+
const AGENT_INSTRUCTION_TARGETS = [
|
|
34607
|
+
{
|
|
34608
|
+
id: "codex",
|
|
34609
|
+
label: "Codex",
|
|
34610
|
+
aliases: ["openai-codex", "codex-cli"],
|
|
34611
|
+
userPath: [".codex", "AGENTS.md"],
|
|
34612
|
+
projectPath: ["AGENTS.md"]
|
|
34613
|
+
},
|
|
34614
|
+
{
|
|
34615
|
+
id: "claude-code",
|
|
34616
|
+
label: "Claude Code",
|
|
34617
|
+
aliases: ["claude", "claudecode"],
|
|
34618
|
+
userPath: [".claude", "CLAUDE.md"],
|
|
34619
|
+
projectPath: ["CLAUDE.md"]
|
|
34620
|
+
},
|
|
34621
|
+
{
|
|
34622
|
+
id: "gemini",
|
|
34623
|
+
label: "Gemini CLI",
|
|
34624
|
+
aliases: ["gemini-cli"],
|
|
34625
|
+
userPath: [".gemini", "GEMINI.md"],
|
|
34626
|
+
projectPath: ["GEMINI.md"]
|
|
34627
|
+
},
|
|
34628
|
+
{
|
|
34629
|
+
id: "opencode",
|
|
34630
|
+
label: "OpenCode",
|
|
34631
|
+
aliases: ["open-code"],
|
|
34632
|
+
userPath: [
|
|
34633
|
+
".config",
|
|
34634
|
+
"opencode",
|
|
34635
|
+
"AGENTS.md"
|
|
34636
|
+
],
|
|
34637
|
+
projectPath: ["AGENTS.md"]
|
|
34638
|
+
}
|
|
34639
|
+
];
|
|
34640
|
+
function getCcskiWorkflowBlock() {
|
|
34641
|
+
return WORKFLOW_BLOCK;
|
|
34642
|
+
}
|
|
34643
|
+
function resolveAgentInstructionTarget(name) {
|
|
34644
|
+
const normalized = name.trim().toLowerCase();
|
|
34645
|
+
return AGENT_INSTRUCTION_TARGETS.find((target) => target.id === normalized || target.aliases.some((alias) => alias.toLowerCase() === normalized)) ?? null;
|
|
34646
|
+
}
|
|
34647
|
+
function listAgentInstructionTargets() {
|
|
34648
|
+
return AGENT_INSTRUCTION_TARGETS;
|
|
34649
|
+
}
|
|
34650
|
+
function installCcskiWorkflow(options = {}) {
|
|
34651
|
+
const scope = options.scope ?? "user";
|
|
34652
|
+
const userDir = resolve(options.userDir ?? homedir());
|
|
34653
|
+
const projectDir = resolve(options.projectDir ?? process.cwd());
|
|
34654
|
+
const results = resolveRequestedTargets(options.agents).map((target) => installTargetWorkflow({
|
|
34655
|
+
target,
|
|
34656
|
+
scope,
|
|
34657
|
+
userDir,
|
|
34658
|
+
projectDir,
|
|
34659
|
+
dryRun: options.dryRun === true
|
|
34660
|
+
}));
|
|
34661
|
+
return {
|
|
34662
|
+
scope,
|
|
34663
|
+
dryRun: options.dryRun === true,
|
|
34664
|
+
results,
|
|
34665
|
+
installed: results.filter((entry) => entry.status === "installed").length,
|
|
34666
|
+
updated: results.filter((entry) => entry.status === "updated").length,
|
|
34667
|
+
unchanged: results.filter((entry) => entry.status === "unchanged").length,
|
|
34668
|
+
failed: results.filter((entry) => entry.status === "failed").length
|
|
34669
|
+
};
|
|
34670
|
+
}
|
|
34671
|
+
function resolveRequestedTargets(agents) {
|
|
34672
|
+
if (!agents || agents.length === 0) return [...AGENT_INSTRUCTION_TARGETS];
|
|
34673
|
+
const resolved = [];
|
|
34674
|
+
for (const agent of agents.flatMap((value) => value.split(","))) {
|
|
34675
|
+
const trimmed = agent.trim();
|
|
34676
|
+
if (!trimmed) continue;
|
|
34677
|
+
if (trimmed.toLowerCase() === "all") {
|
|
34678
|
+
for (const target$1 of AGENT_INSTRUCTION_TARGETS) appendUniqueTarget(resolved, target$1);
|
|
34679
|
+
continue;
|
|
34680
|
+
}
|
|
34681
|
+
const target = resolveAgentInstructionTarget(trimmed);
|
|
34682
|
+
if (!target) {
|
|
34683
|
+
const known = AGENT_INSTRUCTION_TARGETS.map((entry) => entry.id).join(", ");
|
|
34684
|
+
throw new Error(`Unknown agent target '${trimmed}'. Known targets: ${known}.`);
|
|
34685
|
+
}
|
|
34686
|
+
appendUniqueTarget(resolved, target);
|
|
34687
|
+
}
|
|
34688
|
+
if (resolved.length === 0) throw new Error("No agent targets selected.");
|
|
34689
|
+
return resolved;
|
|
34690
|
+
}
|
|
34691
|
+
function appendUniqueTarget(collection, target) {
|
|
34692
|
+
if (!collection.some((entry) => entry.id === target.id)) collection.push(target);
|
|
34693
|
+
}
|
|
34694
|
+
function installTargetWorkflow(options) {
|
|
34695
|
+
const targetPath = resolveTargetPath(options);
|
|
34696
|
+
try {
|
|
34697
|
+
const current = existsSync(targetPath) ? readFileSync(targetPath, "utf8") : "";
|
|
34698
|
+
const next = upsertWorkflowBlock(current);
|
|
34699
|
+
const status$1 = current === next ? "unchanged" : current.trim().length === 0 ? "installed" : "updated";
|
|
34700
|
+
if (!options.dryRun && status$1 !== "unchanged") {
|
|
34701
|
+
mkdirSync(dirname(targetPath), { recursive: true });
|
|
34702
|
+
writeFileSync(targetPath, next, "utf8");
|
|
34703
|
+
}
|
|
34704
|
+
return {
|
|
34705
|
+
agent: options.target.id,
|
|
34706
|
+
label: options.target.label,
|
|
34707
|
+
scope: options.scope,
|
|
34708
|
+
path: targetPath,
|
|
34709
|
+
status: status$1
|
|
34710
|
+
};
|
|
34711
|
+
} catch (err) {
|
|
34712
|
+
return {
|
|
34713
|
+
agent: options.target.id,
|
|
34714
|
+
label: options.target.label,
|
|
34715
|
+
scope: options.scope,
|
|
34716
|
+
path: targetPath,
|
|
34717
|
+
status: "failed",
|
|
34718
|
+
error: err instanceof Error ? err.message : String(err)
|
|
34719
|
+
};
|
|
34720
|
+
}
|
|
34721
|
+
}
|
|
34722
|
+
function resolveTargetPath(options) {
|
|
34723
|
+
const segments = options.scope === "user" ? options.target.userPath : options.target.projectPath;
|
|
34724
|
+
return join(options.scope === "user" ? options.userDir : options.projectDir, ...segments);
|
|
34725
|
+
}
|
|
34726
|
+
function upsertWorkflowBlock(content) {
|
|
34727
|
+
const normalized = normalizeNewline(content);
|
|
34728
|
+
if (WORKFLOW_BLOCK_PATTERN.test(normalized)) return normalized.replace(WORKFLOW_BLOCK_PATTERN, WORKFLOW_BLOCK);
|
|
34729
|
+
const prefix = normalized.trimEnd();
|
|
34730
|
+
return prefix.length > 0 ? `${prefix}\n\n${WORKFLOW_BLOCK}\n` : `${WORKFLOW_BLOCK}\n`;
|
|
34731
|
+
}
|
|
34732
|
+
function normalizeNewline(content) {
|
|
34733
|
+
return content.replace(/\r\n/g, "\n");
|
|
34734
|
+
}
|
|
34735
|
+
|
|
34736
|
+
//#endregion
|
|
34737
|
+
export { BUILT_IN_SKILL_PROVIDERS as $, colors$1 as A, success as B, resolveSkill as C, parseFilters as D, computeDuplicateGroups as E, heading as F, discoverSkills as G, warn as H, highlight as I, getDefaultSkillDirectories as J, loadSkill as K, info as L, duplicateBadge as M, error$1 as N, SkillRegistry as O, formatBytes as P, validateSkillFile as Q, renderList as R, getSkillInfo as S, applyFilters as T, containsCaseInsensitive as U, tone as V, rankStrings as W, providerNamesFromSkills as X, compareSkillProviders as Y, parseSkillFile as Z, installSkillDir as _, resolveAgentInstructionTarget as a, AmbiguousSkillNameError as at, promptMultiSelect as b, ToggleCancelledError as c, SkillNotFoundError as ct, searchSkillsDetailed as d, SKILL_SOURCE_PRIORITIES as et, startMCPServer as f, createConsoleInstallOutput as g, MultiSkillSelectionError as h, listAgentInstructionTargets as i, SkillFrontmatterSchema as it, dim as j, formatSkillLabel as k, toggleSkills as l, ValidationError$2 as lt, InstallCancelledError as m, getCcskiWorkflowBlock as n, InstalledPluginsSchema as nt, validateSkill as o, CcskiError as ot, listSkills as p, scanSkillDirectory as q, installCcskiWorkflow as r, PluginEntrySchema as rt, MultiSelectError as s, ParseError as st, AGENT_INSTRUCTION_TARGETS as t, ClaudeSettingsSchema as tt, searchSkills as u, diagnosticToWarning as ut, installSkills as v, buildRegistryOptions as w, Separator as x, registerInstallCleanupHandlers as y, setColorEnabled as z };
|
|
34738
|
+
//# sourceMappingURL=workflow-install-D85Tfr9z.mjs.map
|