vskill 1.0.14 → 1.0.16
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 +61 -0
- package/agents.json +1 -1
- package/dist/agents/agents-registry.d.ts +8 -3
- package/dist/agents/agents-registry.js.map +1 -1
- package/dist/bin.js +0 -0
- package/dist/clone/github-scaffold.d.ts +38 -0
- package/dist/clone/github-scaffold.js +108 -0
- package/dist/clone/github-scaffold.js.map +1 -0
- package/dist/clone/provenance-fork.d.ts +34 -0
- package/dist/clone/provenance-fork.js +97 -0
- package/dist/clone/provenance-fork.js.map +1 -0
- package/dist/clone/reference-scanner.d.ts +19 -0
- package/dist/clone/reference-scanner.js +144 -0
- package/dist/clone/reference-scanner.js.map +1 -0
- package/dist/clone/skill-locator.d.ts +26 -0
- package/dist/clone/skill-locator.js +248 -0
- package/dist/clone/skill-locator.js.map +1 -0
- package/dist/clone/target-router.d.ts +73 -0
- package/dist/clone/target-router.js +200 -0
- package/dist/clone/target-router.js.map +1 -0
- package/dist/clone/types.d.ts +82 -0
- package/dist/clone/types.js +11 -0
- package/dist/clone/types.js.map +1 -0
- package/dist/commands/add.js +96 -32
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/auth.d.ts +23 -0
- package/dist/commands/auth.js +273 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/clone-prompts.d.ts +13 -0
- package/dist/commands/clone-prompts.js +67 -0
- package/dist/commands/clone-prompts.js.map +1 -0
- package/dist/commands/clone.d.ts +70 -0
- package/dist/commands/clone.js +649 -0
- package/dist/commands/clone.js.map +1 -0
- package/dist/commands/eval/serve.js +8 -1
- package/dist/commands/eval/serve.js.map +1 -1
- package/dist/commands/keys.js +54 -2
- package/dist/commands/keys.js.map +1 -1
- package/dist/eval/skill-scanner.d.ts +2 -12
- package/dist/eval/skill-scanner.js +27 -5
- package/dist/eval/skill-scanner.js.map +1 -1
- package/dist/eval-server/api-routes.js +527 -35
- package/dist/eval-server/api-routes.js.map +1 -1
- package/dist/eval-server/data-events.d.ts +1 -1
- package/dist/eval-server/data-events.js.map +1 -1
- package/dist/eval-server/eval-server.js +8 -1
- package/dist/eval-server/eval-server.js.map +1 -1
- package/dist/eval-server/install-engine-routes-helpers.d.ts +1 -3
- package/dist/eval-server/install-engine-routes-helpers.js +6 -14
- package/dist/eval-server/install-engine-routes-helpers.js.map +1 -1
- package/dist/eval-server/install-state-routes.d.ts +21 -0
- package/dist/eval-server/install-state-routes.js +111 -0
- package/dist/eval-server/install-state-routes.js.map +1 -0
- package/dist/eval-server/origin-resolver.d.ts +42 -0
- package/dist/eval-server/origin-resolver.js +168 -0
- package/dist/eval-server/origin-resolver.js.map +1 -0
- package/dist/eval-server/platform-proxy.d.ts +10 -0
- package/dist/eval-server/platform-proxy.js +58 -2
- package/dist/eval-server/platform-proxy.js.map +1 -1
- package/dist/eval-server/skill-resolver.js +40 -0
- package/dist/eval-server/skill-resolver.js.map +1 -1
- package/dist/eval-server/utils/resolve-editor.d.ts +6 -1
- package/dist/eval-server/utils/resolve-editor.js +11 -26
- package/dist/eval-server/utils/resolve-editor.js.map +1 -1
- package/dist/eval-server/utils/scan-install-locations.d.ts +7 -0
- package/dist/eval-server/utils/scan-install-locations.js +20 -0
- package/dist/eval-server/utils/scan-install-locations.js.map +1 -1
- package/dist/eval-server/utils/which.d.ts +15 -0
- package/dist/eval-server/utils/which.js +76 -0
- package/dist/eval-server/utils/which.js.map +1 -0
- package/dist/eval-ui/assets/{CreateSkillPage-CKvqAya0.js → CreateSkillPage-CvdYq8Rr.js} +5 -5
- package/dist/eval-ui/assets/{FindSkillsPalette-B8pTa5NP.js → FindSkillsPalette-DsSgotS9.js} +2 -2
- package/dist/eval-ui/assets/{SearchPaletteCore-CkVRvaZk.js → SearchPaletteCore-Bf3PBC64.js} +2 -2
- package/dist/eval-ui/assets/SkillDetailPanel-DAD2yJO-.js +1 -0
- package/dist/eval-ui/assets/{UpdateDropdown-DA7OktXO.js → UpdateDropdown-h5Hg3h7Z.js} +1 -1
- package/dist/eval-ui/assets/{index-BKAvJDDF.css → index-CKLqBL52.css} +1 -1
- package/dist/eval-ui/assets/index-JaDg6FlU.js +124 -0
- package/dist/eval-ui/index.html +2 -2
- package/dist/index.js +39 -0
- package/dist/index.js.map +1 -1
- package/dist/installer/canonical.js +2 -11
- package/dist/installer/canonical.js.map +1 -1
- package/dist/installer/frontmatter.d.ts +26 -0
- package/dist/installer/frontmatter.js +91 -1
- package/dist/installer/frontmatter.js.map +1 -1
- package/dist/lib/github-fetch.d.ts +22 -0
- package/dist/lib/github-fetch.js +152 -0
- package/dist/lib/github-fetch.js.map +1 -0
- package/dist/lib/keychain.d.ts +41 -0
- package/dist/lib/keychain.js +232 -0
- package/dist/lib/keychain.js.map +1 -0
- package/dist/studio/lib/provenance.js +3 -2
- package/dist/studio/lib/provenance.js.map +1 -1
- package/dist/studio/lib/query.d.ts +1 -0
- package/dist/studio/lib/query.js +7 -0
- package/dist/studio/lib/query.js.map +1 -0
- package/dist/studio/lib/scope-transfer.d.ts +6 -0
- package/dist/studio/lib/scope-transfer.js +5 -2
- package/dist/studio/lib/scope-transfer.js.map +1 -1
- package/dist/studio/routes/index.js +3 -0
- package/dist/studio/routes/index.js.map +1 -1
- package/dist/studio/routes/ops.js +1 -3
- package/dist/studio/routes/ops.js.map +1 -1
- package/dist/studio/routes/promote.js +1 -3
- package/dist/studio/routes/promote.js.map +1 -1
- package/dist/studio/routes/revert.js +2 -17
- package/dist/studio/routes/revert.js.map +1 -1
- package/dist/studio/routes/test-install.js +1 -3
- package/dist/studio/routes/test-install.js.map +1 -1
- package/dist/studio/types.d.ts +13 -0
- package/dist/utils/claude-plugin.d.ts +26 -0
- package/dist/utils/claude-plugin.js +60 -0
- package/dist/utils/claude-plugin.js.map +1 -1
- package/dist/utils/skill-builder-detection.d.ts +14 -1
- package/dist/utils/skill-builder-detection.js +20 -8
- package/dist/utils/skill-builder-detection.js.map +1 -1
- package/dist/utils/skill-creator-detection.d.ts +10 -2
- package/dist/utils/skill-creator-detection.js +12 -43
- package/dist/utils/skill-creator-detection.js.map +1 -1
- package/package.json +2 -1
- package/dist/eval-ui/assets/SkillDetailPanel-d4_LquVH.js +0 -1
- package/dist/eval-ui/assets/index-DCbohW6l.js +0 -122
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// vskill clone — reference-scanner (READ-ONLY)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Detects cross-skill reference patterns and self-name occurrences in
|
|
5
|
+
// SKILL.md prose. **Reports only — never rewrites anything.** The orchestrator
|
|
6
|
+
// appends the report to the success summary so the user can decide what to do.
|
|
7
|
+
//
|
|
8
|
+
// Patterns:
|
|
9
|
+
// - backtick: `sw:foo` (single-backtick inline code)
|
|
10
|
+
// - skill-call: Skill({ skill: "sw:foo" }) / Skill({ skill: 'sw:foo' })
|
|
11
|
+
// - slash-command: /sw:foo
|
|
12
|
+
// - self-name: literal occurrence of the OLD skill name in prose
|
|
13
|
+
//
|
|
14
|
+
// False-positive guard: matches inside fenced code blocks (```...```) are
|
|
15
|
+
// excluded for the slash-command and self-name patterns. Backtick and
|
|
16
|
+
// Skill({...}) patterns are themselves code-shaped, so they are reported
|
|
17
|
+
// unconditionally — that's the user's signal that an actual cross-skill
|
|
18
|
+
// dependency exists in the source.
|
|
19
|
+
//
|
|
20
|
+
// See spec.md AC-US1-04, plan.md §6.
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
const BACKTICK_RE = /`([a-z][a-z0-9-]*:[a-z][a-z0-9-]*)`/g;
|
|
23
|
+
const SKILL_CALL_RE = /Skill\s*\(\s*\{\s*skill\s*:\s*["']([^"']+)["']/g;
|
|
24
|
+
const SLASH_COMMAND_RE = /(?:^|\s)(\/[a-z][a-z0-9-]*:[a-z][a-z0-9-]*)\b/g;
|
|
25
|
+
/**
|
|
26
|
+
* Build a regex that matches the OLD skill name as a whole "word", where word
|
|
27
|
+
* boundaries here mean the surrounding chars are not [A-Za-z0-9-/] (so
|
|
28
|
+
* "ado-mapper" matches but "ado-mapperx" or "my-ado-mapper-thing" do not).
|
|
29
|
+
*
|
|
30
|
+
* The `oldSkillName` is escaped before being embedded in the pattern so any
|
|
31
|
+
* regex metacharacters in the skill name are treated literally.
|
|
32
|
+
*/
|
|
33
|
+
function escapeRegex(s) {
|
|
34
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Detect lines covered by fenced code blocks (triple-backtick). Returns a Set
|
|
38
|
+
* of 1-indexed line numbers that are INSIDE a fence. Used to suppress
|
|
39
|
+
* slash-command and self-name false positives that live in code samples.
|
|
40
|
+
*
|
|
41
|
+
* The opening/closing fence lines themselves are also considered "inside"
|
|
42
|
+
* for the purpose of suppression — they don't contain meaningful prose
|
|
43
|
+
* references, so this is a deliberate slight overreach.
|
|
44
|
+
*/
|
|
45
|
+
function computeFencedLines(lines) {
|
|
46
|
+
const fenced = new Set();
|
|
47
|
+
let inFence = false;
|
|
48
|
+
for (let i = 0; i < lines.length; i++) {
|
|
49
|
+
const trimmed = lines[i].trimStart();
|
|
50
|
+
if (trimmed.startsWith("```")) {
|
|
51
|
+
// The fence-opening line and fence-closing line are both fenced.
|
|
52
|
+
fenced.add(i + 1);
|
|
53
|
+
inFence = !inFence;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (inFence)
|
|
57
|
+
fenced.add(i + 1);
|
|
58
|
+
}
|
|
59
|
+
return fenced;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Scan SKILL.md content for cross-skill references and self-name occurrences.
|
|
63
|
+
* Returns matches in document order with line numbers (1-indexed).
|
|
64
|
+
*/
|
|
65
|
+
export function scanReferences(content, opts) {
|
|
66
|
+
const file = opts.file ?? "SKILL.md";
|
|
67
|
+
const normalized = content.replace(/^/, "").replace(/\r\n/g, "\n");
|
|
68
|
+
const lines = normalized.split("\n");
|
|
69
|
+
const fenced = computeFencedLines(lines);
|
|
70
|
+
const out = [];
|
|
71
|
+
// Pattern 1: backtick `sw:foo` — reported unconditionally (already code-shaped).
|
|
72
|
+
for (let i = 0; i < lines.length; i++) {
|
|
73
|
+
const line = lines[i];
|
|
74
|
+
BACKTICK_RE.lastIndex = 0;
|
|
75
|
+
let m;
|
|
76
|
+
while ((m = BACKTICK_RE.exec(line)) !== null) {
|
|
77
|
+
out.push({ file, line: i + 1, match: m[1], kind: "backtick" });
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// Pattern 2: Skill({ skill: "sw:foo" }) — reported unconditionally.
|
|
81
|
+
for (let i = 0; i < lines.length; i++) {
|
|
82
|
+
const line = lines[i];
|
|
83
|
+
SKILL_CALL_RE.lastIndex = 0;
|
|
84
|
+
let m;
|
|
85
|
+
while ((m = SKILL_CALL_RE.exec(line)) !== null) {
|
|
86
|
+
out.push({ file, line: i + 1, match: m[1], kind: "skill-call" });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// Pattern 3: /sw:foo — slash-command. Suppressed inside fenced code blocks.
|
|
90
|
+
for (let i = 0; i < lines.length; i++) {
|
|
91
|
+
if (fenced.has(i + 1))
|
|
92
|
+
continue;
|
|
93
|
+
const line = lines[i];
|
|
94
|
+
SLASH_COMMAND_RE.lastIndex = 0;
|
|
95
|
+
let m;
|
|
96
|
+
while ((m = SLASH_COMMAND_RE.exec(line)) !== null) {
|
|
97
|
+
// Strip the leading "/" so the recorded match is the bare slash-command name.
|
|
98
|
+
const matched = m[1];
|
|
99
|
+
out.push({ file, line: i + 1, match: matched, kind: "slash-command" });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Scan for literal occurrences of the OLD skill name in prose.
|
|
106
|
+
* Suppressed inside fenced code blocks. Returned as a separate array because
|
|
107
|
+
* it's informational at a different level (manual rename candidates, not
|
|
108
|
+
* cross-skill dependencies).
|
|
109
|
+
*/
|
|
110
|
+
export function scanSelfNameOccurrences(content, opts) {
|
|
111
|
+
const file = opts.file ?? "SKILL.md";
|
|
112
|
+
const normalized = content.replace(/^/, "").replace(/\r\n/g, "\n");
|
|
113
|
+
const lines = normalized.split("\n");
|
|
114
|
+
const fenced = computeFencedLines(lines);
|
|
115
|
+
// The full name may contain "/" (e.g. "sw/ado-mapper") — we scan for both
|
|
116
|
+
// the bare skill segment and the full name. Bare segment first ensures we
|
|
117
|
+
// catch occurrences like "the ado-mapper does X" in prose.
|
|
118
|
+
const slashIdx = opts.oldSkillName.indexOf("/");
|
|
119
|
+
const bareSkill = slashIdx >= 0 ? opts.oldSkillName.slice(slashIdx + 1) : opts.oldSkillName;
|
|
120
|
+
const patterns = new Set();
|
|
121
|
+
patterns.add(opts.oldSkillName);
|
|
122
|
+
if (bareSkill !== opts.oldSkillName)
|
|
123
|
+
patterns.add(bareSkill);
|
|
124
|
+
const out = [];
|
|
125
|
+
for (const pattern of patterns) {
|
|
126
|
+
const escaped = escapeRegex(pattern);
|
|
127
|
+
// Word-boundary that treats letters, digits, hyphen, slash as part of the "word".
|
|
128
|
+
// (?<![A-Za-z0-9-/]) — preceded by neither a name char nor a slash
|
|
129
|
+
// (?![A-Za-z0-9-/]) — followed by neither a name char nor a slash
|
|
130
|
+
const re = new RegExp(`(?<![A-Za-z0-9\\-/])${escaped}(?![A-Za-z0-9\\-/])`, "g");
|
|
131
|
+
for (let i = 0; i < lines.length; i++) {
|
|
132
|
+
if (fenced.has(i + 1))
|
|
133
|
+
continue;
|
|
134
|
+
const line = lines[i];
|
|
135
|
+
re.lastIndex = 0;
|
|
136
|
+
let m;
|
|
137
|
+
while ((m = re.exec(line)) !== null) {
|
|
138
|
+
out.push({ file, line: i + 1, match: m[0], kind: "self-name" });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=reference-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reference-scanner.js","sourceRoot":"","sources":["../../src/clone/reference-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { SkillSource } from "./types.js";
|
|
2
|
+
export interface LocateOptions {
|
|
3
|
+
/** Working directory to use as the project root (defaults to process.cwd()). */
|
|
4
|
+
cwd?: string;
|
|
5
|
+
/** Home directory (defaults to os.homedir() — explicit for testability). */
|
|
6
|
+
home: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Split a source identifier like "sw/ado-mapper" into namespace + skill, or
|
|
10
|
+
* return only the skill when no namespace is present.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseSourceIdent(source: string): {
|
|
13
|
+
namespace?: string;
|
|
14
|
+
skill: string;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Discover a skill across project / personal / cache. Returns every match in
|
|
18
|
+
* search order — the orchestrator handles disambiguation when there is more
|
|
19
|
+
* than one and `--source` was not explicitly provided.
|
|
20
|
+
*/
|
|
21
|
+
export declare function locateSkill(source: string, opts: LocateOptions): Promise<SkillSource[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Enumerate every skill inside a cached plugin. Used by the whole-plugin
|
|
24
|
+
* clone path (T-010). Returns a list of SkillSource entries (one per skill).
|
|
25
|
+
*/
|
|
26
|
+
export declare function enumeratePluginSkills(pluginName: string, opts: LocateOptions): Promise<SkillSource[]>;
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// vskill clone — skill-locator
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Discover a source skill across the three supported locations, in deterministic
|
|
5
|
+
// order. The caller (orchestrator in src/commands/clone.ts) decides what to do
|
|
6
|
+
// with multiple matches (interactive disambiguation or honor --source override).
|
|
7
|
+
//
|
|
8
|
+
// Search order:
|
|
9
|
+
// 1. project → <cwd>/.claude/skills/<skill>/SKILL.md
|
|
10
|
+
// 2. personal → <home>/.claude/skills/<skill>/SKILL.md
|
|
11
|
+
// 3. cache → <home>/.claude/plugins/cache/<org>/<plugin>/<version>/skills/<skill>/SKILL.md
|
|
12
|
+
//
|
|
13
|
+
// Source identifiers may be passed as:
|
|
14
|
+
// - "ado-mapper" (bare skill name)
|
|
15
|
+
// - "sw/ado-mapper" (namespace/skill — namespace is treated informationally)
|
|
16
|
+
//
|
|
17
|
+
// See spec.md AC-US1-01 and plan.md §4.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
import { promises as fs } from "node:fs";
|
|
20
|
+
import { join, basename } from "node:path";
|
|
21
|
+
import { readProvenance } from "../studio/lib/provenance.js";
|
|
22
|
+
const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---/;
|
|
23
|
+
const NAME_LINE_RE = /^name:\s*(.+?)\s*$/m;
|
|
24
|
+
const VERSION_LINE_RE = /^version:\s*(.+?)\s*$/m;
|
|
25
|
+
function unquote(value) {
|
|
26
|
+
const trimmed = value.trim();
|
|
27
|
+
if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
|
|
28
|
+
(trimmed.startsWith("'") && trimmed.endsWith("'"))) {
|
|
29
|
+
return trimmed.slice(1, -1);
|
|
30
|
+
}
|
|
31
|
+
return trimmed;
|
|
32
|
+
}
|
|
33
|
+
async function parseSkillMd(skillMdPath) {
|
|
34
|
+
try {
|
|
35
|
+
const raw = await fs.readFile(skillMdPath, "utf-8");
|
|
36
|
+
const normalized = raw.replace(/^/, "").replace(/\r\n/g, "\n");
|
|
37
|
+
const fmMatch = normalized.match(FRONTMATTER_RE);
|
|
38
|
+
if (!fmMatch)
|
|
39
|
+
return {};
|
|
40
|
+
const block = fmMatch[1];
|
|
41
|
+
const nameMatch = block.match(NAME_LINE_RE);
|
|
42
|
+
const versionMatch = block.match(VERSION_LINE_RE);
|
|
43
|
+
return {
|
|
44
|
+
name: nameMatch ? unquote(nameMatch[1]) : undefined,
|
|
45
|
+
version: versionMatch ? unquote(versionMatch[1]) : undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return {};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Split a source identifier like "sw/ado-mapper" into namespace + skill, or
|
|
54
|
+
* return only the skill when no namespace is present.
|
|
55
|
+
*/
|
|
56
|
+
export function parseSourceIdent(source) {
|
|
57
|
+
const idx = source.indexOf("/");
|
|
58
|
+
if (idx === -1)
|
|
59
|
+
return { skill: source };
|
|
60
|
+
return { namespace: source.slice(0, idx), skill: source.slice(idx + 1) };
|
|
61
|
+
}
|
|
62
|
+
async function exists(path) {
|
|
63
|
+
try {
|
|
64
|
+
await fs.access(path);
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
async function dirExists(path) {
|
|
72
|
+
try {
|
|
73
|
+
const st = await fs.stat(path);
|
|
74
|
+
return st.isDirectory();
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function buildSource(location, skillDir, fallbackSkillName, pluginCtx) {
|
|
81
|
+
const skillMd = join(skillDir, "SKILL.md");
|
|
82
|
+
if (!(await exists(skillMd)))
|
|
83
|
+
return null;
|
|
84
|
+
const fm = await parseSkillMd(skillMd);
|
|
85
|
+
const fullName = fm.name ?? fallbackSkillName;
|
|
86
|
+
const slashIdx = fullName.indexOf("/");
|
|
87
|
+
const namespace = slashIdx >= 0 ? fullName.slice(0, slashIdx) : undefined;
|
|
88
|
+
let existingProvenance = null;
|
|
89
|
+
try {
|
|
90
|
+
existingProvenance = await readProvenance(skillDir);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
existingProvenance = null;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
location,
|
|
97
|
+
skillDir,
|
|
98
|
+
skillName: fullName,
|
|
99
|
+
namespace,
|
|
100
|
+
version: fm.version ?? "0.0.0",
|
|
101
|
+
plugin: pluginCtx,
|
|
102
|
+
existingProvenance,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function locateInProject(cwd, skill) {
|
|
106
|
+
const dir = join(cwd, ".claude", "skills", skill);
|
|
107
|
+
if (!(await dirExists(dir)))
|
|
108
|
+
return null;
|
|
109
|
+
return buildSource("project", dir, skill);
|
|
110
|
+
}
|
|
111
|
+
async function locateInPersonal(home, skill) {
|
|
112
|
+
const dir = join(home, ".claude", "skills", skill);
|
|
113
|
+
if (!(await dirExists(dir)))
|
|
114
|
+
return null;
|
|
115
|
+
return buildSource("personal", dir, skill);
|
|
116
|
+
}
|
|
117
|
+
async function locateInCache(home, skill, preferredNamespace) {
|
|
118
|
+
const cacheRoot = join(home, ".claude", "plugins", "cache");
|
|
119
|
+
if (!(await dirExists(cacheRoot)))
|
|
120
|
+
return [];
|
|
121
|
+
const matches = [];
|
|
122
|
+
let orgs;
|
|
123
|
+
try {
|
|
124
|
+
orgs = await fs.readdir(cacheRoot);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
for (const org of orgs) {
|
|
130
|
+
const orgDir = join(cacheRoot, org);
|
|
131
|
+
if (!(await dirExists(orgDir)))
|
|
132
|
+
continue;
|
|
133
|
+
let plugins;
|
|
134
|
+
try {
|
|
135
|
+
plugins = await fs.readdir(orgDir);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
for (const pluginName of plugins) {
|
|
141
|
+
const pluginRoot = join(orgDir, pluginName);
|
|
142
|
+
if (!(await dirExists(pluginRoot)))
|
|
143
|
+
continue;
|
|
144
|
+
let versions;
|
|
145
|
+
try {
|
|
146
|
+
versions = await fs.readdir(pluginRoot);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
for (const version of versions) {
|
|
152
|
+
const skillDir = join(pluginRoot, version, "skills", skill);
|
|
153
|
+
if (!(await dirExists(skillDir)))
|
|
154
|
+
continue;
|
|
155
|
+
const built = await buildSource("cache", skillDir, skill, {
|
|
156
|
+
pluginNamespace: org,
|
|
157
|
+
pluginName,
|
|
158
|
+
pluginVersion: version,
|
|
159
|
+
pluginRoot: join(pluginRoot, version),
|
|
160
|
+
});
|
|
161
|
+
if (!built)
|
|
162
|
+
continue;
|
|
163
|
+
if (preferredNamespace && built.namespace && built.namespace !== preferredNamespace) {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
matches.push(built);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return matches;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Discover a skill across project / personal / cache. Returns every match in
|
|
174
|
+
* search order — the orchestrator handles disambiguation when there is more
|
|
175
|
+
* than one and `--source` was not explicitly provided.
|
|
176
|
+
*/
|
|
177
|
+
export async function locateSkill(source, opts) {
|
|
178
|
+
const { skill, namespace } = parseSourceIdent(source);
|
|
179
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
180
|
+
const matches = [];
|
|
181
|
+
const project = await locateInProject(cwd, skill);
|
|
182
|
+
if (project && (!namespace || project.namespace === namespace || !project.namespace)) {
|
|
183
|
+
matches.push(project);
|
|
184
|
+
}
|
|
185
|
+
const personal = await locateInPersonal(opts.home, skill);
|
|
186
|
+
if (personal && (!namespace || personal.namespace === namespace || !personal.namespace)) {
|
|
187
|
+
matches.push(personal);
|
|
188
|
+
}
|
|
189
|
+
const cache = await locateInCache(opts.home, skill, namespace);
|
|
190
|
+
matches.push(...cache);
|
|
191
|
+
return matches;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Enumerate every skill inside a cached plugin. Used by the whole-plugin
|
|
195
|
+
* clone path (T-010). Returns a list of SkillSource entries (one per skill).
|
|
196
|
+
*/
|
|
197
|
+
export async function enumeratePluginSkills(pluginName, opts) {
|
|
198
|
+
const cacheRoot = join(opts.home, ".claude", "plugins", "cache");
|
|
199
|
+
if (!(await dirExists(cacheRoot)))
|
|
200
|
+
return [];
|
|
201
|
+
const results = [];
|
|
202
|
+
let orgs;
|
|
203
|
+
try {
|
|
204
|
+
orgs = await fs.readdir(cacheRoot);
|
|
205
|
+
}
|
|
206
|
+
catch {
|
|
207
|
+
return [];
|
|
208
|
+
}
|
|
209
|
+
for (const org of orgs) {
|
|
210
|
+
const pluginRoot = join(cacheRoot, org, pluginName);
|
|
211
|
+
if (!(await dirExists(pluginRoot)))
|
|
212
|
+
continue;
|
|
213
|
+
let versions;
|
|
214
|
+
try {
|
|
215
|
+
versions = await fs.readdir(pluginRoot);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
for (const version of versions) {
|
|
221
|
+
const skillsDir = join(pluginRoot, version, "skills");
|
|
222
|
+
if (!(await dirExists(skillsDir)))
|
|
223
|
+
continue;
|
|
224
|
+
let skillEntries;
|
|
225
|
+
try {
|
|
226
|
+
skillEntries = await fs.readdir(skillsDir);
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
for (const skillEntry of skillEntries) {
|
|
232
|
+
const skillDir = join(skillsDir, skillEntry);
|
|
233
|
+
if (!(await dirExists(skillDir)))
|
|
234
|
+
continue;
|
|
235
|
+
const built = await buildSource("cache", skillDir, basename(skillDir), {
|
|
236
|
+
pluginNamespace: org,
|
|
237
|
+
pluginName,
|
|
238
|
+
pluginVersion: version,
|
|
239
|
+
pluginRoot: join(pluginRoot, version),
|
|
240
|
+
});
|
|
241
|
+
if (built)
|
|
242
|
+
results.push(built);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return results;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=skill-locator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-locator.js","sourceRoot":"","sources":["../../src/clone/skill-locator.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+BAA+B;AAC/B,8EAA8E;AAC9E,iFAAiF;AACjF,+EAA+E;AAC/E,iFAAiF;AACjF,EAAE;AACF,gBAAgB;AAChB,yDAAyD;AACzD,0DAA0D;AAC1D,iGAAiG;AACjG,EAAE;AACF,uCAAuC;AACvC,yCAAyC;AACzC,gFAAgF;AAChF,EAAE;AACF,wCAAwC;AACxC,8EAA8E;AAE9E,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI3C,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAe7D,MAAM,cAAc,GAAG,uBAAuB,CAAC;AAC/C,MAAM,YAAY,GAAG,qBAAqB,CAAC;AAC3C,MAAM,eAAe,GAAG,wBAAwB,CAAC;AAEjD,SAAS,OAAO,CAAC,KAAa;IAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IACE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAClD,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,WAAmB;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACpD,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAChE,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;QACjD,IAAI,CAAC,OAAO;YAAE,OAAO,EAAE,CAAC;QACxB,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACzB,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,YAAY,GAAG,KAAK,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;QAClD,OAAO;YACL,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;YACnD,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;SAC7D,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAc;IAC7C,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,GAAG,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IACzC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;AAC3E,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,IAAY;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,IAAY;IACnC,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,OAAO,EAAE,CAAC,WAAW,EAAE,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,QAA6B,EAC7B,QAAgB,EAChB,iBAAyB,EACzB,SAAiC;IAEjC,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3C,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAE1C,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,MAAM,QAAQ,GAAG,EAAE,CAAC,IAAI,IAAI,iBAAiB,CAAC;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,QAAQ,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE1E,IAAI,kBAAkB,GAAsB,IAAI,CAAC;IACjD,IAAI,CAAC;QACH,kBAAkB,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED,OAAO;QACL,QAAQ;QACR,QAAQ;QACR,SAAS,EAAE,QAAQ;QACnB,SAAS;QACT,OAAO,EAAE,EAAE,CAAC,OAAO,IAAI,OAAO;QAC9B,MAAM,EAAE,SAAS;QACjB,kBAAkB;KACnB,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,eAAe,CAC5B,GAAW,EACX,KAAa;IAEb,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,WAAW,CAAC,SAAS,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAC5C,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,IAAY,EACZ,KAAa;IAEb,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,WAAW,CAAC,UAAU,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;AAC7C,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,IAAY,EACZ,KAAa,EACb,kBAA2B;IAE3B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC5D,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAE7C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,IAAI,IAAc,CAAC;IACnB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;YAAE,SAAS;QAEzC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,KAAK,MAAM,UAAU,IAAI,OAAO,EAAE,CAAC;YACjC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;YAC5C,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;gBAAE,SAAS;YAE7C,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAC1C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;gBAC5D,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;oBAAE,SAAS;gBAE3C,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE;oBACxD,eAAe,EAAE,GAAG;oBACpB,UAAU;oBACV,aAAa,EAAE,OAAO;oBACtB,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;iBACtC,CAAC,CAAC;gBACH,IAAI,CAAC,KAAK;oBAAE,SAAS;gBAErB,IAAI,kBAAkB,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,KAAK,kBAAkB,EAAE,CAAC;oBACpF,SAAS;gBACX,CAAC;gBAED,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,IAAmB;IAEnB,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IAEtC,MAAM,OAAO,GAAkB,EAAE,CAAC;IAElC,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAClD,IAAI,OAAO,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrF,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC1D,IAAI,QAAQ,IAAI,CAAC,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC;IAC/D,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC;IAEvB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB,EAClB,IAAmB;IAEnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACjE,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAE7C,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,IAAI,IAAc,CAAC;IACnB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC;QACpD,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,UAAU,CAAC,CAAC;YAAE,SAAS;QAE7C,IAAI,QAAkB,CAAC;QACvB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QAED,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;YACtD,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,CAAC;gBAAE,SAAS;YAE5C,IAAI,YAAsB,CAAC;YAC3B,IAAI,CAAC;gBACH,YAAY,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS;YACX,CAAC;YAED,KAAK,MAAM,UAAU,IAAI,YAAY,EAAE,CAAC;gBACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;gBAC7C,IAAI,CAAC,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;oBAAE,SAAS;gBAE3C,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE;oBACrE,eAAe,EAAE,GAAG;oBACpB,UAAU;oBACV,aAAa,EAAE,OAAO;oBACtB,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,OAAO,CAAC;iBACtC,CAAC,CAAC;gBACH,IAAI,KAAK;oBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACjC,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { basename } from "node:path";
|
|
2
|
+
export interface CopyResult {
|
|
3
|
+
/** Absolute path of the `.tmp` staging directory. Caller renames into place. */
|
|
4
|
+
stagingDir: string;
|
|
5
|
+
/** Number of files written under `stagingDir`. */
|
|
6
|
+
filesCopied: number;
|
|
7
|
+
/** Final destination path (where `stagingDir` should be renamed to). */
|
|
8
|
+
finalDir: string;
|
|
9
|
+
}
|
|
10
|
+
export interface PluginCopyResult extends CopyResult {
|
|
11
|
+
/** Absolute path of the `.tmp` staged plugin manifest (sibling of the live manifest). */
|
|
12
|
+
manifestTmpPath: string;
|
|
13
|
+
/** Absolute path of the live plugin manifest (final rename target). */
|
|
14
|
+
manifestFinalPath: string;
|
|
15
|
+
}
|
|
16
|
+
/** Compute the `.tmp` sibling of a final destination path. */
|
|
17
|
+
export declare function tmpSibling(finalPath: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Best-effort cleanup of a `.tmp` path. Mirrors the rollback shape used by
|
|
20
|
+
* src/commands/add.ts:rollbackInstall — swallows per-call errors so a partial
|
|
21
|
+
* filesystem state doesn't suppress the underlying diagnostic the orchestrator
|
|
22
|
+
* is about to surface to the user.
|
|
23
|
+
*/
|
|
24
|
+
export declare function bestEffortRm(path: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Copy a source skill into a fresh standalone target dir, staged at
|
|
27
|
+
* `<finalDir>.tmp`. The orchestrator is responsible for the atomic
|
|
28
|
+
* rename and any pre-checks for collisions / `--force`.
|
|
29
|
+
*/
|
|
30
|
+
export declare function writeStandalone(args: {
|
|
31
|
+
sourceSkillDir: string;
|
|
32
|
+
finalDir: string;
|
|
33
|
+
}): Promise<CopyResult>;
|
|
34
|
+
/**
|
|
35
|
+
* Copy a source skill into an existing user-owned plugin's skills/ directory
|
|
36
|
+
* AND stage an updated `plugin.json` at `<plugin.json>.tmp` so the
|
|
37
|
+
* orchestrator can rename both in sequence (two-phase commit).
|
|
38
|
+
*
|
|
39
|
+
* Pre-flight: detects malformed plugin.json BEFORE any copy is staged
|
|
40
|
+
* (AC-US2-03). Caller aborts on the thrown error; no skill files are written.
|
|
41
|
+
*/
|
|
42
|
+
export declare function writeToPlugin(args: {
|
|
43
|
+
sourceSkillDir: string;
|
|
44
|
+
pluginRoot: string;
|
|
45
|
+
newSkillName: string;
|
|
46
|
+
}): Promise<PluginCopyResult>;
|
|
47
|
+
/**
|
|
48
|
+
* Scaffold a fresh new plugin at `<pluginRoot>` containing
|
|
49
|
+
* `.claude-plugin/plugin.json` (with the requested name) plus
|
|
50
|
+
* `skills/<skill>/` subtree containing the cloned skill.
|
|
51
|
+
*
|
|
52
|
+
* The whole plugin tree is staged at `<pluginRoot>.tmp` and atomically
|
|
53
|
+
* renamed by the caller — there is no two-phase commit because the manifest
|
|
54
|
+
* and the skill files live under a common root (one `rename` is enough).
|
|
55
|
+
*/
|
|
56
|
+
export declare function writeNewPlugin(args: {
|
|
57
|
+
sourceSkillDir: string;
|
|
58
|
+
pluginRoot: string;
|
|
59
|
+
pluginName: string;
|
|
60
|
+
newSkillName: string;
|
|
61
|
+
/** Optional plugin description; defaults to a generic forked-skills line. */
|
|
62
|
+
description?: string;
|
|
63
|
+
/** Optional plugin author; recorded in plugin.json. */
|
|
64
|
+
author?: string;
|
|
65
|
+
}): Promise<CopyResult>;
|
|
66
|
+
/**
|
|
67
|
+
* The `bareSkillName` helper extracts the unqualified skill name from a
|
|
68
|
+
* fully-qualified name like `anton/ado-mapper` → `ado-mapper`. Used by the
|
|
69
|
+
* orchestrator and by callers that need the directory-safe segment.
|
|
70
|
+
*/
|
|
71
|
+
export declare function bareSkillName(fullyQualified: string): string;
|
|
72
|
+
/** Re-export for callers that want to validate basenames. */
|
|
73
|
+
export { basename };
|