ghostrail 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +20 -1
  2. package/dist/cli/commands.d.ts +40 -0
  3. package/dist/cli/commands.d.ts.map +1 -1
  4. package/dist/cli/commands.js +145 -0
  5. package/dist/cli/commands.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +7 -1
  8. package/dist/cli.js.map +1 -1
  9. package/dist/commands/help.d.ts.map +1 -1
  10. package/dist/commands/help.js +11 -0
  11. package/dist/commands/help.js.map +1 -1
  12. package/dist/skill/install.d.ts +56 -0
  13. package/dist/skill/install.d.ts.map +1 -0
  14. package/dist/skill/install.js +93 -0
  15. package/dist/skill/install.js.map +1 -0
  16. package/dist/vendor/skilltend/apply.d.ts +25 -0
  17. package/dist/vendor/skilltend/apply.d.ts.map +1 -0
  18. package/dist/vendor/skilltend/apply.js +85 -0
  19. package/dist/vendor/skilltend/apply.js.map +1 -0
  20. package/dist/vendor/skilltend/detect.d.ts +35 -0
  21. package/dist/vendor/skilltend/detect.d.ts.map +1 -0
  22. package/dist/vendor/skilltend/detect.js +187 -0
  23. package/dist/vendor/skilltend/detect.js.map +1 -0
  24. package/dist/vendor/skilltend/frontmatter.d.ts +5 -0
  25. package/dist/vendor/skilltend/frontmatter.d.ts.map +1 -0
  26. package/dist/vendor/skilltend/frontmatter.js +59 -0
  27. package/dist/vendor/skilltend/frontmatter.js.map +1 -0
  28. package/dist/vendor/skilltend/fsFacade.d.ts +24 -0
  29. package/dist/vendor/skilltend/fsFacade.d.ts.map +1 -0
  30. package/dist/vendor/skilltend/fsFacade.js +68 -0
  31. package/dist/vendor/skilltend/fsFacade.js.map +1 -0
  32. package/dist/vendor/skilltend/paths.d.ts +28 -0
  33. package/dist/vendor/skilltend/paths.d.ts.map +1 -0
  34. package/dist/vendor/skilltend/paths.js +24 -0
  35. package/dist/vendor/skilltend/paths.js.map +1 -0
  36. package/dist/vendor/skilltend/plan.d.ts +46 -0
  37. package/dist/vendor/skilltend/plan.d.ts.map +1 -0
  38. package/dist/vendor/skilltend/plan.js +79 -0
  39. package/dist/vendor/skilltend/plan.js.map +1 -0
  40. package/dist/vendor/skilltend/registry.d.ts +56 -0
  41. package/dist/vendor/skilltend/registry.d.ts.map +1 -0
  42. package/dist/vendor/skilltend/registry.js +129 -0
  43. package/dist/vendor/skilltend/registry.js.map +1 -0
  44. package/package.json +2 -2
  45. package/skill/ghostrail/SKILL.md +145 -0
@@ -0,0 +1,25 @@
1
+ import type { FsFacade } from "./fsFacade.js";
2
+ import { type SkillTarget } from "./paths.js";
3
+ import { type TargetPlan } from "./plan.js";
4
+ import type { SkillIdentity } from "./registry.js";
5
+ /** Inspect each target and decide what installing `content` would do. Read-only. */
6
+ export declare function planTargets(targets: readonly SkillTarget[], content: string, skill: SkillIdentity, fs: FsFacade, force?: boolean): Promise<TargetPlan[]>;
7
+ /** What `applyPlans` actually did, for the caller to report. */
8
+ export interface ApplyResult {
9
+ created: string[];
10
+ updated: string[];
11
+ unchanged: string[];
12
+ /** Conflicts are never written; they are returned for the caller to explain. */
13
+ conflicts: TargetPlan[];
14
+ }
15
+ /**
16
+ * Write the plans. `create` and `update` are applied; `unchanged` is a no-op
17
+ * (which is what makes re-running safe); `conflict` is refused and reported, so
18
+ * a foreign file is never clobbered without `--force`.
19
+ */
20
+ export declare function applyPlans(plans: readonly TargetPlan[], content: string, fs: FsFacade): Promise<ApplyResult>;
21
+ /** Remove the skill from each directory. Returns the paths actually removed. */
22
+ export declare function removeSkill(skillsDirs: readonly string[], skill: SkillIdentity, fs: FsFacade): Promise<string[]>;
23
+ /** True when nothing would change — the "already up to date" case for `--check`. */
24
+ export declare function isUpToDate(plans: readonly TargetPlan[]): boolean;
25
+ //# sourceMappingURL=apply.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../../src/vendor/skilltend/apply.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,KAAK,WAAW,EAAY,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,KAAK,UAAU,EAAsB,MAAM,WAAW,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,oFAAoF;AACpF,wBAAsB,WAAW,CAC/B,OAAO,EAAE,SAAS,WAAW,EAAE,EAC/B,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,QAAQ,EACZ,KAAK,UAAQ,GACZ,OAAO,CAAC,UAAU,EAAE,CAAC,CA2BvB;AAED,gEAAgE;AAChE,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gFAAgF;IAChF,SAAS,EAAE,UAAU,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,KAAK,EAAE,SAAS,UAAU,EAAE,EAC5B,OAAO,EAAE,MAAM,EACf,EAAE,EAAE,QAAQ,GACX,OAAO,CAAC,WAAW,CAAC,CA4BtB;AAED,gFAAgF;AAChF,wBAAsB,WAAW,CAC/B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,KAAK,EAAE,aAAa,EACpB,EAAE,EAAE,QAAQ,GACX,OAAO,CAAC,MAAM,EAAE,CAAC,CASnB;AAED,oFAAoF;AACpF,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAEhE"}
@@ -0,0 +1,85 @@
1
+ // Part of the future `skilltend` package. Not vendored from a14y: a14y keeps
2
+ // this orchestration inside its 786-line CLI `index.ts`, mixed with presentation.
3
+ // Here it is engine logic — build plans, then apply them — so the library decides
4
+ // *what* happens and the consuming product decides how to say it.
5
+ import path from "node:path";
6
+ import { parseSkillVersion } from "./frontmatter.js";
7
+ import { skillDir } from "./paths.js";
8
+ import { planFile, planLink } from "./plan.js";
9
+ /** Inspect each target and decide what installing `content` would do. Read-only. */
10
+ export async function planTargets(targets, content, skill, fs, force = false) {
11
+ const fetchedVersion = parseSkillVersion(content);
12
+ const plans = [];
13
+ for (const target of targets) {
14
+ if (target.kind === "link") {
15
+ const st = await fs.lstat(target.managedPath);
16
+ const existing = st === null
17
+ ? { kind: "absent" }
18
+ : st.isSymbolicLink
19
+ ? { kind: "symlink", linkTarget: await fs.readlink(target.managedPath) }
20
+ : { kind: "other" };
21
+ plans.push(planLink({ target, fetchedVersion, existing, force }));
22
+ continue;
23
+ }
24
+ // copy / canonical: a real SKILL.md file.
25
+ const current = await fs.readFile(target.managedPath);
26
+ // A symlink anywhere on the way would make us write through to someone
27
+ // else's file, so treat it as one.
28
+ const fileStat = await fs.lstat(target.managedPath);
29
+ const dirStat = await fs.lstat(path.dirname(target.managedPath));
30
+ const isSymlink = Boolean(fileStat?.isSymbolicLink) || Boolean(dirStat?.isSymbolicLink);
31
+ plans.push(planFile({ skill, target, fetched: content, current, isSymlink, force }));
32
+ }
33
+ return plans;
34
+ }
35
+ /**
36
+ * Write the plans. `create` and `update` are applied; `unchanged` is a no-op
37
+ * (which is what makes re-running safe); `conflict` is refused and reported, so
38
+ * a foreign file is never clobbered without `--force`.
39
+ */
40
+ export async function applyPlans(plans, content, fs) {
41
+ const result = { created: [], updated: [], unchanged: [], conflicts: [] };
42
+ for (const plan of plans) {
43
+ const { target, action } = plan;
44
+ if (action === "conflict") {
45
+ result.conflicts.push(plan);
46
+ continue;
47
+ }
48
+ if (action === "unchanged") {
49
+ result.unchanged.push(target.managedPath);
50
+ continue;
51
+ }
52
+ if (target.kind === "link") {
53
+ if (target.linkTo === undefined)
54
+ continue;
55
+ await fs.mkdirp(path.dirname(target.managedPath));
56
+ // Replace whatever is there; planLink already refused unless it was ours
57
+ // or the caller passed --force.
58
+ await fs.rm(target.managedPath);
59
+ await fs.symlink(target.linkTo, target.managedPath);
60
+ }
61
+ else {
62
+ await fs.mkdirp(path.dirname(target.managedPath));
63
+ await fs.writeFile(target.managedPath, content);
64
+ }
65
+ (action === "create" ? result.created : result.updated).push(target.managedPath);
66
+ }
67
+ return result;
68
+ }
69
+ /** Remove the skill from each directory. Returns the paths actually removed. */
70
+ export async function removeSkill(skillsDirs, skill, fs) {
71
+ const removed = [];
72
+ for (const dir of skillsDirs) {
73
+ const target = skillDir(dir, skill);
74
+ if ((await fs.lstat(target)) === null)
75
+ continue;
76
+ await fs.rm(target);
77
+ removed.push(target);
78
+ }
79
+ return removed;
80
+ }
81
+ /** True when nothing would change — the "already up to date" case for `--check`. */
82
+ export function isUpToDate(plans) {
83
+ return plans.length > 0 && plans.every((p) => p.action === "unchanged");
84
+ }
85
+ //# sourceMappingURL=apply.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../../src/vendor/skilltend/apply.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import type { FsFacade } from "./fsFacade.js";
2
+ import { type Scope, type SkillTarget } from "./paths.js";
3
+ import { type AgentEntry, type PathCtx, type SkillIdentity } from "./registry.js";
4
+ export type InstallMethod = "copy" | "link";
5
+ /** Build install targets for the given agents, scope, and method. */
6
+ export declare function buildTargets(agents: AgentEntry[], scope: Scope, ctx: PathCtx, skill: SkillIdentity, method?: InstallMethod): SkillTarget[];
7
+ export interface DetectMatch {
8
+ agent: AgentEntry;
9
+ /** The marker directory that matched (shown to the user). */
10
+ dir: string;
11
+ }
12
+ /** Detect configured agents along with the marker dir that matched. */
13
+ export declare function detectAgentMatches(ctx: PathCtx, fs: FsFacade): Promise<DetectMatch[]>;
14
+ /** Detect which registered agents are configured under the given scope. */
15
+ export declare function detectAgents(ctx: PathCtx, fs: FsFacade): Promise<AgentEntry[]>;
16
+ /** Targets for an explicit `--agent <name>` selection. Throws on unknown names. */
17
+ export declare function agentTargets(names: string[], scope: Scope, ctx: PathCtx, skill: SkillIdentity, method?: InstallMethod): SkillTarget[];
18
+ /** Single target for an explicit `--target <dir>` (bypasses scope + registry). */
19
+ export declare function explicitTarget(dir: string, ctx: PathCtx, skill: SkillIdentity): SkillTarget;
20
+ export interface RemovalTarget {
21
+ agents: string[];
22
+ label: string;
23
+ /** The skill directory or symlink to remove. */
24
+ path: string;
25
+ kind: "link" | "dir";
26
+ version: string | null;
27
+ }
28
+ /**
29
+ * Find every place the skill is installed under the given scope — the
30
+ * shared `.agents/skills` dir and each registered agent's skills dir — whether
31
+ * it's a real copy or a symlink. Foreign directories of the same name (not our skill) are
32
+ * ignored so uninstall never deletes someone else's files.
33
+ */
34
+ export declare function scanInstalled(ctx: PathCtx, scope: Scope, fs: FsFacade, skill: SkillIdentity): Promise<RemovalTarget[]>;
35
+ //# sourceMappingURL=detect.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/vendor/skilltend/detect.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,KAAK,KAAK,EAAE,KAAK,WAAW,EAA0C,MAAM,YAAY,CAAC;AAClG,OAAO,EAEL,KAAK,UAAU,EACf,KAAK,OAAO,EACZ,KAAK,aAAa,EAInB,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AA4F5C,qEAAqE;AACrE,wBAAgB,YAAY,CAC1B,MAAM,EAAE,UAAU,EAAE,EACpB,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,aAAa,EACpB,MAAM,GAAE,aAAsB,GAC7B,WAAW,EAAE,CAKf;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,UAAU,CAAC;IAClB,6DAA6D;IAC7D,GAAG,EAAE,MAAM,CAAC;CACb;AAED,uEAAuE;AACvE,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAW3F;AAED,2EAA2E;AAC3E,wBAAsB,YAAY,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAEpF;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAC1B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,KAAK,EACZ,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,aAAa,EACpB,MAAM,GAAE,aAAsB,GAC7B,WAAW,EAAE,CAWf;AAED,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,GAAG,WAAW,CAQ3F;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,QAAQ,EACZ,KAAK,EAAE,aAAa,GACnB,OAAO,CAAC,aAAa,EAAE,CAAC,CAgD1B"}
@@ -0,0 +1,187 @@
1
+ // Vendored from timothyjordan/a14y @ 07ef2bbb8593
2
+ // (packages/apps/cli/src/skills/detect.ts), Apache-2.0.
3
+ //
4
+ // This directory is the future `skilltend` package: a white-label engine for
5
+ // installing and maintaining ONE agent skill across coding agents. It contains
6
+ // no skills of its own and no product name — the caller supplies the skill's
7
+ // identity. Keep changes here minimal and mechanical so the eventual extraction
8
+ // to a standalone package stays a directory move (see TJ-1464).
9
+ import path from "node:path";
10
+ import { parseSkillName, parseSkillVersion } from "./frontmatter.js";
11
+ import { SkillsConfigError, skillDir, skillFile } from "./paths.js";
12
+ import { AGENT_REGISTRY, agentByName, localSkillsDir, sharedSkillsDir, } from "./registry.js";
13
+ function requireBase(ctx, scope) {
14
+ if (scope === "global" && !ctx.home) {
15
+ throw new SkillsConfigError("Could not determine your home directory. Pass --target <dir> or use --local.");
16
+ }
17
+ if (scope === "local" && !ctx.cwd) {
18
+ throw new SkillsConfigError("Could not determine the current directory.");
19
+ }
20
+ }
21
+ function agentSkillsDir(a, scope, ctx) {
22
+ return scope === "global" ? a.globalSkillsDir(ctx) : localSkillsDir(a, ctx);
23
+ }
24
+ /** Copy targets: a real SKILL.md in each agent's own skills dir (deduped). */
25
+ function buildCopyTargets(agents, scope, ctx, skill) {
26
+ const byPath = new Map();
27
+ for (const a of agents) {
28
+ const file = skillFile(agentSkillsDir(a, scope, ctx), skill);
29
+ const hit = byPath.get(file);
30
+ if (hit) {
31
+ hit.agents.push(a.name);
32
+ hit.labels.push(a.label);
33
+ }
34
+ else {
35
+ byPath.set(file, { agents: [a.name], labels: [a.label] });
36
+ }
37
+ }
38
+ return [...byPath.entries()].map(([managedPath, v]) => ({
39
+ kind: "copy",
40
+ agents: v.agents,
41
+ label: v.labels.join(" + "),
42
+ managedPath,
43
+ }));
44
+ }
45
+ /**
46
+ * Link targets: one canonical SKILL.md in the shared `.agents/skills` dir, plus
47
+ * a symlink from every other agent's skill dir to it. Agents whose skills dir
48
+ * *is* the shared dir are served by the canonical directly (no extra symlink).
49
+ */
50
+ function buildLinkTargets(agents, scope, ctx, skill) {
51
+ const shared = sharedSkillsDir(ctx, scope);
52
+ const canonicalDir = skillDir(shared, skill);
53
+ const canonicalFile = skillFile(shared, skill);
54
+ const direct = [];
55
+ const links = new Map();
56
+ for (const a of agents) {
57
+ const dir = agentSkillsDir(a, scope, ctx);
58
+ if (path.resolve(dir) === path.resolve(shared)) {
59
+ direct.push(a.label);
60
+ continue;
61
+ }
62
+ const linkPath = skillDir(dir, skill);
63
+ const hit = links.get(linkPath);
64
+ if (hit) {
65
+ hit.agents.push(a.name);
66
+ hit.labels.push(a.label);
67
+ }
68
+ else {
69
+ links.set(linkPath, { agents: [a.name], labels: [a.label] });
70
+ }
71
+ }
72
+ const canonical = {
73
+ kind: "canonical",
74
+ agents: ["shared"],
75
+ label: direct.length ? `Shared + ${direct.join(" + ")}` : "Shared (.agents/skills)",
76
+ managedPath: canonicalFile,
77
+ };
78
+ const linkTargets = [...links.entries()].map(([managedPath, v]) => ({
79
+ kind: "link",
80
+ agents: v.agents,
81
+ label: v.labels.join(" + "),
82
+ managedPath,
83
+ linkTo: canonicalDir,
84
+ }));
85
+ return [canonical, ...linkTargets];
86
+ }
87
+ /** Build install targets for the given agents, scope, and method. */
88
+ export function buildTargets(agents, scope, ctx, skill, method = "copy") {
89
+ requireBase(ctx, scope);
90
+ return method === "link"
91
+ ? buildLinkTargets(agents, scope, ctx, skill)
92
+ : buildCopyTargets(agents, scope, ctx, skill);
93
+ }
94
+ /** Detect configured agents along with the marker dir that matched. */
95
+ export async function detectAgentMatches(ctx, fs) {
96
+ const matches = [];
97
+ for (const a of AGENT_REGISTRY) {
98
+ for (const dir of a.detectDirs(ctx)) {
99
+ if (await fs.dirExists(dir)) {
100
+ matches.push({ agent: a, dir });
101
+ break;
102
+ }
103
+ }
104
+ }
105
+ return matches;
106
+ }
107
+ /** Detect which registered agents are configured under the given scope. */
108
+ export async function detectAgents(ctx, fs) {
109
+ return (await detectAgentMatches(ctx, fs)).map((m) => m.agent);
110
+ }
111
+ /** Targets for an explicit `--agent <name>` selection. Throws on unknown names. */
112
+ export function agentTargets(names, scope, ctx, skill, method = "copy") {
113
+ const agents = [];
114
+ for (const name of names) {
115
+ const entry = agentByName(name);
116
+ if (!entry) {
117
+ const known = AGENT_REGISTRY.map((a) => a.name).join(", ");
118
+ throw new SkillsConfigError(`Unknown agent "${name}". Known agents: ${known}.`);
119
+ }
120
+ if (!agents.includes(entry))
121
+ agents.push(entry);
122
+ }
123
+ return buildTargets(agents, scope, ctx, skill, method);
124
+ }
125
+ /** Single target for an explicit `--target <dir>` (bypasses scope + registry). */
126
+ export function explicitTarget(dir, ctx, skill) {
127
+ const skillsDir = path.resolve(ctx.cwd || ".", dir);
128
+ return {
129
+ kind: "copy",
130
+ agents: ["custom"],
131
+ label: `custom target (${dir})`,
132
+ managedPath: skillFile(skillsDir, skill),
133
+ };
134
+ }
135
+ /**
136
+ * Find every place the skill is installed under the given scope — the
137
+ * shared `.agents/skills` dir and each registered agent's skills dir — whether
138
+ * it's a real copy or a symlink. Foreign directories of the same name (not our skill) are
139
+ * ignored so uninstall never deletes someone else's files.
140
+ */
141
+ export async function scanInstalled(ctx, scope, fs, skill) {
142
+ requireBase(ctx, scope);
143
+ // Candidate skills dirs: the shared dir plus every agent's own dir.
144
+ const candidates = [
145
+ { skillsDir: sharedSkillsDir(ctx, scope), label: "Shared (.agents/skills)", agent: "shared" },
146
+ ...AGENT_REGISTRY.map((a) => ({
147
+ skillsDir: agentSkillsDir(a, scope, ctx),
148
+ label: a.label,
149
+ agent: a.name,
150
+ })),
151
+ ];
152
+ const byPath = new Map();
153
+ for (const c of candidates) {
154
+ const dir = skillDir(c.skillsDir, skill);
155
+ const seen = byPath.get(dir);
156
+ if (seen) {
157
+ seen.agents.push(c.agent);
158
+ seen.labels.push(c.label);
159
+ continue;
160
+ }
161
+ const st = await fs.lstat(dir);
162
+ if (!st)
163
+ continue;
164
+ if (st.isSymbolicLink) {
165
+ byPath.set(dir, { agents: [c.agent], labels: [c.label], kind: "link", version: null });
166
+ }
167
+ else if (st.isDirectory) {
168
+ const content = await fs.readFile(skillFile(c.skillsDir, skill));
169
+ if (content && parseSkillName(content) === skill.name) {
170
+ byPath.set(dir, {
171
+ agents: [c.agent],
172
+ labels: [c.label],
173
+ kind: "dir",
174
+ version: parseSkillVersion(content),
175
+ });
176
+ }
177
+ }
178
+ }
179
+ return [...byPath.entries()].map(([p, v]) => ({
180
+ agents: v.agents,
181
+ label: v.labels.join(" + "),
182
+ path: p,
183
+ kind: v.kind,
184
+ version: v.version,
185
+ }));
186
+ }
187
+ //# sourceMappingURL=detect.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect.js","sourceRoot":"","sources":["../../../src/vendor/skilltend/detect.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /** Top-level `name:` from the frontmatter, or null. */
2
+ export declare function parseSkillName(content: string): string | null;
3
+ /** `metadata.version` from the frontmatter, or null when absent/unparseable. */
4
+ export declare function parseSkillVersion(content: string): string | null;
5
+ //# sourceMappingURL=frontmatter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.d.ts","sourceRoot":"","sources":["../../../src/vendor/skilltend/frontmatter.ts"],"names":[],"mappings":"AA4BA,uDAAuD;AACvD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAK7D;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBhE"}
@@ -0,0 +1,59 @@
1
+ // Vendored from timothyjordan/a14y @ 07ef2bbb8593
2
+ // (packages/apps/cli/src/skills/frontmatter.ts), Apache-2.0.
3
+ //
4
+ // This directory is the future `skilltend` package: a white-label engine for
5
+ // installing and maintaining ONE agent skill across coding agents. It contains
6
+ // no skills of its own and no product name — the caller supplies the skill's
7
+ // identity. Keep changes here minimal and mechanical so the eventual extraction
8
+ // to a standalone package stays a directory move (see TJ-1464).
9
+ // Minimal, zero-dependency reads of the two SKILL.md frontmatter fields the
10
+ // installer cares about: the top-level `name` (to tell our own skill apart from
11
+ // a foreign file) and the nested `metadata.version` (to surface old -> new on an
12
+ // update). The frontmatter shape is fixed and simple, so a focused scan beats
13
+ // pulling a YAML parser into the published CLI bundle.
14
+ function extractFrontmatter(content) {
15
+ // Optional BOM, then a `---` fence, the body, then a closing `---` fence.
16
+ const match = /^\uFEFF?---\r?\n([\s\S]*?)\r?\n---/.exec(content);
17
+ return match?.[1] ?? null;
18
+ }
19
+ function stripQuotes(value) {
20
+ const t = value.trim();
21
+ if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) {
22
+ return t.slice(1, -1);
23
+ }
24
+ return t;
25
+ }
26
+ /** Top-level `name:` from the frontmatter, or null. */
27
+ export function parseSkillName(content) {
28
+ const fm = extractFrontmatter(content);
29
+ if (!fm)
30
+ return null;
31
+ const value = /^name:[ \t]*(.+?)[ \t]*$/m.exec(fm)?.[1];
32
+ return value === undefined ? null : stripQuotes(value);
33
+ }
34
+ /** `metadata.version` from the frontmatter, or null when absent/unparseable. */
35
+ export function parseSkillVersion(content) {
36
+ const fm = extractFrontmatter(content);
37
+ if (!fm)
38
+ return null;
39
+ const lines = fm.split(/\r?\n/);
40
+ let inMetadata = false;
41
+ for (const line of lines) {
42
+ if (/^metadata:[ \t]*$/.test(line)) {
43
+ inMetadata = true;
44
+ continue;
45
+ }
46
+ if (!inMetadata)
47
+ continue;
48
+ // A non-indented line ends the metadata block.
49
+ if (/^\S/.test(line)) {
50
+ inMetadata = false;
51
+ continue;
52
+ }
53
+ const value = /^[ \t]+version:[ \t]*(.+?)[ \t]*$/.exec(line)?.[1];
54
+ if (value !== undefined)
55
+ return stripQuotes(value);
56
+ }
57
+ return null;
58
+ }
59
+ //# sourceMappingURL=frontmatter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../../src/vendor/skilltend/frontmatter.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,6DAA6D;AAC7D,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAChF,gEAAgE;AAChE,4EAA4E;AAC5E,gFAAgF;AAChF,iFAAiF;AACjF,8EAA8E;AAC9E,uDAAuD;AAEvD,SAAS,kBAAkB,CAAC,OAAe;IACzC,0EAA0E;IAC1E,MAAM,KAAK,GAAG,oCAAoC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACjE,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AAC5B,CAAC;AAED,SAAS,WAAW,CAAC,KAAa;IAChC,MAAM,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACvB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QACrF,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,KAAK,GAAG,2BAA2B,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxD,OAAO,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,MAAM,EAAE,GAAG,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACvC,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,KAAK,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAChC,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,UAAU,GAAG,IAAI,CAAC;YAClB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,UAAU;YAAE,SAAS;QAC1B,+CAA+C;QAC/C,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,UAAU,GAAG,KAAK,CAAC;YACnB,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,mCAAmC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAClE,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Tiny filesystem seam so the orchestrator can run against an in-memory fake in
3
+ * unit tests. `readFile`/`lstat`/`readlink` return null on ENOENT instead of
4
+ * throwing so the caller treats "absent" as a value, not an exception.
5
+ */
6
+ export interface FsFacade {
7
+ readFile(path: string): Promise<string | null>;
8
+ writeFile(path: string, content: string): Promise<void>;
9
+ mkdirp(path: string): Promise<void>;
10
+ lstat(path: string): Promise<{
11
+ isSymbolicLink: boolean;
12
+ isDirectory: boolean;
13
+ } | null>;
14
+ /** Symlink target of `path`, or null when it is absent or not a symlink. */
15
+ readlink(path: string): Promise<string | null>;
16
+ /** Create a symlink at `linkPath` pointing to `target` (dir-type). */
17
+ symlink(target: string, linkPath: string): Promise<void>;
18
+ /** Remove a file, symlink, or directory tree. No-op when absent. */
19
+ rm(path: string): Promise<void>;
20
+ /** True when `path` exists and is a directory (used for agent auto-detect). */
21
+ dirExists(path: string): Promise<boolean>;
22
+ }
23
+ export declare const nodeFs: FsFacade;
24
+ //# sourceMappingURL=fsFacade.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsFacade.d.ts","sourceRoot":"","sources":["../../../src/vendor/skilltend/fsFacade.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,cAAc,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,OAAO,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IACvF,4EAA4E;IAC5E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,sEAAsE;IACtE,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,oEAAoE;IACpE,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,+EAA+E;IAC/E,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC3C;AAMD,eAAO,MAAM,MAAM,EAAE,QA+CpB,CAAC"}
@@ -0,0 +1,68 @@
1
+ // Vendored from timothyjordan/a14y @ 07ef2bbb8593
2
+ // (packages/apps/cli/src/skills/fsFacade.ts), Apache-2.0.
3
+ //
4
+ // This directory is the future `skilltend` package: a white-label engine for
5
+ // installing and maintaining ONE agent skill across coding agents. It contains
6
+ // no skills of its own and no product name — the caller supplies the skill's
7
+ // identity. Keep changes here minimal and mechanical so the eventual extraction
8
+ // to a standalone package stays a directory move (see TJ-1464).
9
+ import { promises as fs } from "node:fs";
10
+ function isEnoent(e) {
11
+ return e?.code === "ENOENT";
12
+ }
13
+ export const nodeFs = {
14
+ async readFile(p) {
15
+ try {
16
+ return await fs.readFile(p, "utf8");
17
+ }
18
+ catch (e) {
19
+ if (isEnoent(e))
20
+ return null;
21
+ throw e;
22
+ }
23
+ },
24
+ async writeFile(p, content) {
25
+ await fs.writeFile(p, content, "utf8");
26
+ },
27
+ async mkdirp(p) {
28
+ await fs.mkdir(p, { recursive: true });
29
+ },
30
+ async lstat(p) {
31
+ try {
32
+ const s = await fs.lstat(p);
33
+ return { isSymbolicLink: s.isSymbolicLink(), isDirectory: s.isDirectory() };
34
+ }
35
+ catch (e) {
36
+ if (isEnoent(e))
37
+ return null;
38
+ throw e;
39
+ }
40
+ },
41
+ async readlink(p) {
42
+ try {
43
+ return await fs.readlink(p);
44
+ }
45
+ catch (e) {
46
+ const code = e.code;
47
+ if (code === "ENOENT" || code === "EINVAL")
48
+ return null;
49
+ throw e;
50
+ }
51
+ },
52
+ async symlink(target, linkPath) {
53
+ await fs.symlink(target, linkPath, "dir");
54
+ },
55
+ async rm(p) {
56
+ await fs.rm(p, { recursive: true, force: true });
57
+ },
58
+ async dirExists(p) {
59
+ try {
60
+ const s = await fs.stat(p);
61
+ return s.isDirectory();
62
+ }
63
+ catch {
64
+ return false;
65
+ }
66
+ },
67
+ };
68
+ //# sourceMappingURL=fsFacade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsFacade.js","sourceRoot":"","sources":["../../../src/vendor/skilltend/fsFacade.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,0DAA0D;AAC1D,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAChF,gEAAgE;AAChE,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AAsBzC,SAAS,QAAQ,CAAC,CAAU;IAC1B,OAAQ,CAAuC,EAAE,IAAI,KAAK,QAAQ,CAAC;AACrE,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAa;IAC9B,KAAK,CAAC,QAAQ,CAAC,CAAC;QACd,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC7B,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO;QACxB,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IACD,KAAK,CAAC,MAAM,CAAC,CAAC;QACZ,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,KAAK,CAAC,KAAK,CAAC,CAAC;QACX,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5B,OAAO,EAAE,cAAc,EAAE,CAAC,CAAC,cAAc,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC9E,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,IAAI,QAAQ,CAAC,CAAC,CAAC;gBAAE,OAAO,IAAI,CAAC;YAC7B,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,KAAK,CAAC,QAAQ,CAAC,CAAC;QACd,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC9B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,GAAI,CAA2B,CAAC,IAAI,CAAC;YAC/C,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YACxD,MAAM,CAAC,CAAC;QACV,CAAC;IACH,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ;QAC5B,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,KAAK,CAAC,EAAE,CAAC,CAAC;QACR,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,CAAC;QACf,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC3B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QACzB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,28 @@
1
+ import type { SkillIdentity } from "./registry.js";
2
+ export type Scope = "global" | "local";
3
+ export declare class SkillsConfigError extends Error {
4
+ constructor(message: string);
5
+ }
6
+ export type TargetKind = "copy" | "canonical" | "link";
7
+ export interface SkillTarget {
8
+ /**
9
+ * - `copy`: a real SKILL.md written into the agent's own skills dir.
10
+ * - `canonical`: the single shared SKILL.md (`.agents/skills/<name>/SKILL.md`)
11
+ * used by the symlink install mode.
12
+ * - `link`: a symlink at an agent's skill dir pointing at the canonical dir.
13
+ */
14
+ kind: TargetKind;
15
+ /** Agent keys served by this target (>1 when they share a path). */
16
+ agents: string[];
17
+ /** Combined human label, e.g. "Cline + Zed". */
18
+ label: string;
19
+ /** copy/canonical: the SKILL.md file path. link: the symlink path. */
20
+ managedPath: string;
21
+ /** link only: absolute canonical skill directory the symlink points at. */
22
+ linkTo?: string;
23
+ }
24
+ /** `<skillsDir>/<name>/SKILL.md`. */
25
+ export declare function skillFile(skillsDir: string, skill: SkillIdentity): string;
26
+ /** `<skillsDir>/<name>`. */
27
+ export declare function skillDir(skillsDir: string, skill: SkillIdentity): string;
28
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/vendor/skilltend/paths.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvC,qBAAa,iBAAkB,SAAQ,KAAK;gBAC9B,OAAO,EAAE,MAAM;CAI5B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;AAEvD,MAAM,WAAW,WAAW;IAC1B;;;;;OAKG;IACH,IAAI,EAAE,UAAU,CAAC;IACjB,oEAAoE;IACpE,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,qCAAqC;AACrC,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAEzE;AAED,4BAA4B;AAC5B,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,CAExE"}
@@ -0,0 +1,24 @@
1
+ // Vendored from timothyjordan/a14y @ 07ef2bbb8593
2
+ // (packages/apps/cli/src/skills/paths.ts), Apache-2.0.
3
+ //
4
+ // This directory is the future `skilltend` package: a white-label engine for
5
+ // installing and maintaining ONE agent skill across coding agents. It contains
6
+ // no skills of its own and no product name — the caller supplies the skill's
7
+ // identity. Keep changes here minimal and mechanical so the eventual extraction
8
+ // to a standalone package stays a directory move (see TJ-1464).
9
+ import path from "node:path";
10
+ export class SkillsConfigError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "SkillsConfigError";
14
+ }
15
+ }
16
+ /** `<skillsDir>/<name>/SKILL.md`. */
17
+ export function skillFile(skillsDir, skill) {
18
+ return path.join(skillsDir, skill.name, skill.filename);
19
+ }
20
+ /** `<skillsDir>/<name>`. */
21
+ export function skillDir(skillsDir, skill) {
22
+ return path.join(skillsDir, skill.name);
23
+ }
24
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/vendor/skilltend/paths.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,uDAAuD;AACvD,EAAE;AACF,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,gFAAgF;AAChF,gEAAgE;AAChE,OAAO,IAAI,MAAM,WAAW,CAAC;AAK7B,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC1C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF;AAsBD,qCAAqC;AACrC,MAAM,UAAU,SAAS,CAAC,SAAiB,EAAE,KAAoB;IAC/D,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;AAC1D,CAAC;AAED,4BAA4B;AAC5B,MAAM,UAAU,QAAQ,CAAC,SAAiB,EAAE,KAAoB;IAC9D,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC"}