@take-out/cli 0.1.45 → 0.1.47
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 +4 -4
- package/dist/cjs/commands/skills.cjs +49 -191
- package/dist/cjs/commands/skills.js +41 -150
- package/dist/cjs/commands/skills.js.map +2 -2
- package/dist/esm/commands/skills.js +43 -157
- package/dist/esm/commands/skills.js.map +1 -1
- package/dist/esm/commands/skills.mjs +49 -191
- package/dist/esm/commands/skills.mjs.map +1 -1
- package/package.json +4 -4
- package/src/commands/skills.ts +65 -292
- package/types/commands/skills.d.ts.map +1 -1
|
@@ -4,97 +4,16 @@ import {
|
|
|
4
4
|
mkdirSync,
|
|
5
5
|
readdirSync,
|
|
6
6
|
readFileSync,
|
|
7
|
+
readlinkSync,
|
|
7
8
|
rmSync,
|
|
9
|
+
rmdirSync,
|
|
8
10
|
symlinkSync,
|
|
9
|
-
unlinkSync
|
|
10
|
-
writeFileSync
|
|
11
|
+
unlinkSync
|
|
11
12
|
} from "node:fs";
|
|
12
13
|
import { createRequire } from "node:module";
|
|
13
|
-
import { dirname, join, relative } from "node:path";
|
|
14
|
-
import { fileURLToPath } from "node:url";
|
|
14
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
15
15
|
import { defineCommand } from "citty";
|
|
16
16
|
import pc from "picocolors";
|
|
17
|
-
import {
|
|
18
|
-
discoverScripts,
|
|
19
|
-
getAllScriptMetadata,
|
|
20
|
-
getLocalScriptsDir
|
|
21
|
-
} from "../utils/script-utils";
|
|
22
|
-
const BUILTIN_COMMANDS = [
|
|
23
|
-
{ name: "onboard", description: "setup wizard for new projects" },
|
|
24
|
-
{ name: "docs", description: "view documentation" },
|
|
25
|
-
{ name: "env:setup", description: "setup environment variables" },
|
|
26
|
-
{ name: "run", description: "run scripts in parallel" },
|
|
27
|
-
{ name: "script", description: "manage and run scripts" },
|
|
28
|
-
{ name: "sync", description: "sync fork with upstream takeout" },
|
|
29
|
-
{ name: "changed", description: "show changes since last sync" },
|
|
30
|
-
{ name: "skills", description: "manage claude code skills" },
|
|
31
|
-
{ name: "completion", description: "shell completion setup" }
|
|
32
|
-
];
|
|
33
|
-
function findScriptsPackageRoot() {
|
|
34
|
-
try {
|
|
35
|
-
const resolved = import.meta.resolve("@take-out/scripts/package.json"), packageJsonPath = fileURLToPath(new URL(resolved));
|
|
36
|
-
return join(packageJsonPath, "..", "src");
|
|
37
|
-
} catch {
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
function buildSummaryDescription(localScripts, builtInScripts) {
|
|
42
|
-
const categories = /* @__PURE__ */ new Set(), keywords = /* @__PURE__ */ new Set();
|
|
43
|
-
for (const [name] of [...localScripts, ...builtInScripts])
|
|
44
|
-
keywords.add(name), name.includes("/") && categories.add(name.split("/")[0]);
|
|
45
|
-
for (const cmd of BUILTIN_COMMANDS)
|
|
46
|
-
keywords.add(cmd.name);
|
|
47
|
-
return `CLI scripts and commands reference for the tko (takeout) CLI. Use when the user asks to run scripts, manage the project, or needs to know what commands are available. tko, takeout, CLI, scripts, commands, bun tko, project tasks, automation, ${[...categories].sort().join(", ")}, ${[...keywords].sort().join(", ")}`.slice(0, 2048);
|
|
48
|
-
}
|
|
49
|
-
function buildSummaryContent(localScripts, builtInScripts, metadata) {
|
|
50
|
-
const description = buildSummaryDescription(localScripts, builtInScripts), lines = [];
|
|
51
|
-
lines.push("---"), lines.push("name: tko-scripts"), lines.push(`description: ${description}`), lines.push("---"), lines.push(""), lines.push("# tko CLI - scripts & commands"), lines.push(""), lines.push("run with `bun tko <command>` or `bun tko <script-name>`."), lines.push(""), lines.push("## built-in commands"), lines.push("");
|
|
52
|
-
for (const cmd of BUILTIN_COMMANDS)
|
|
53
|
-
lines.push(` ${cmd.name} - ${cmd.description}`);
|
|
54
|
-
lines.push("");
|
|
55
|
-
const formatSection = (title, scripts) => {
|
|
56
|
-
if (scripts.size === 0) return;
|
|
57
|
-
const categories = /* @__PURE__ */ new Map(), rootScripts = [];
|
|
58
|
-
for (const [name] of scripts)
|
|
59
|
-
if (name.includes("/")) {
|
|
60
|
-
const category = name.split("/")[0];
|
|
61
|
-
categories.has(category) || categories.set(category, []), categories.get(category).push(name);
|
|
62
|
-
} else
|
|
63
|
-
rootScripts.push(name);
|
|
64
|
-
lines.push(`## ${title}`), lines.push("");
|
|
65
|
-
for (const name of rootScripts) {
|
|
66
|
-
const meta = metadata.get(name), desc = meta?.description ? ` - ${meta.description}` : "", args = meta?.args?.length ? ` [${meta.args.join(", ")}]` : "";
|
|
67
|
-
lines.push(` ${name}${desc}${args}`);
|
|
68
|
-
}
|
|
69
|
-
for (const [category, categoryScripts] of categories) {
|
|
70
|
-
lines.push(""), lines.push(` ${category}/`);
|
|
71
|
-
for (const name of categoryScripts) {
|
|
72
|
-
const shortName = name.substring(category.length + 1), meta = metadata.get(name), desc = meta?.description ? ` - ${meta.description}` : "", args = meta?.args?.length ? ` [${meta.args.join(", ")}]` : "";
|
|
73
|
-
lines.push(` ${shortName}${desc}${args}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
lines.push("");
|
|
77
|
-
};
|
|
78
|
-
return formatSection("local scripts", localScripts), formatSection("built-in scripts", builtInScripts), lines.push("## usage"), lines.push(""), lines.push("```bash"), lines.push("bun tko <command> # run a built-in command"), lines.push("bun tko <script-name> # execute direct script"), lines.push(
|
|
79
|
-
"bun tko <group> <script> # execute nested script (e.g. bun tko aws health)"
|
|
80
|
-
), lines.push("bun tko run s1 s2 s3 # run multiple scripts in parallel"), lines.push("bun tko script new <path> # create a new script"), lines.push("```"), lines.push(""), lines.join(`
|
|
81
|
-
`);
|
|
82
|
-
}
|
|
83
|
-
async function generateSummary(cwd) {
|
|
84
|
-
const skillsDir = join(cwd, ".claude", "skills"), skillDir = join(skillsDir, "tko-scripts"), skillFile = join(skillDir, "SKILL.md"), localScripts = discoverScripts(getLocalScriptsDir()), builtInDir = findScriptsPackageRoot(), builtInScripts = builtInDir ? discoverScripts(builtInDir) : /* @__PURE__ */ new Map(), allScripts = new Map([...localScripts, ...builtInScripts]), metadata = await getAllScriptMetadata(allScripts), totalScripts = localScripts.size + builtInScripts.size;
|
|
85
|
-
console.info(
|
|
86
|
-
pc.dim(
|
|
87
|
-
`found ${totalScripts} scripts (${localScripts.size} local, ${builtInScripts.size} built-in) + ${BUILTIN_COMMANDS.length} commands`
|
|
88
|
-
)
|
|
89
|
-
);
|
|
90
|
-
const content = buildSummaryContent(localScripts, builtInScripts, metadata);
|
|
91
|
-
try {
|
|
92
|
-
if (readFileSync(skillFile, "utf-8") === content)
|
|
93
|
-
return console.info(` ${pc.dim("tko-scripts")} ${pc.dim("unchanged")}`), !1;
|
|
94
|
-
} catch {
|
|
95
|
-
}
|
|
96
|
-
return existsSync(skillDir) || mkdirSync(skillDir, { recursive: !0 }), writeFileSync(skillFile, content), console.info(` ${pc.green("\u2713")} tko-scripts`), !0;
|
|
97
|
-
}
|
|
98
17
|
const require2 = createRequire(import.meta.url);
|
|
99
18
|
let DOCS_DIR;
|
|
100
19
|
try {
|
|
@@ -117,33 +36,6 @@ function isDevOnly(content) {
|
|
|
117
36
|
const frontmatter = content.slice(3, endIndex);
|
|
118
37
|
return /\bdev:\s*true\b/.test(frontmatter);
|
|
119
38
|
}
|
|
120
|
-
function extractDocMeta(content) {
|
|
121
|
-
const lines = content.split(`
|
|
122
|
-
`);
|
|
123
|
-
let title = "", description = "", startLine = 0;
|
|
124
|
-
if (lines[0]?.trim() === "---") {
|
|
125
|
-
for (let i = 1; i < lines.length; i++)
|
|
126
|
-
if (lines[i]?.trim() === "---") {
|
|
127
|
-
startLine = i + 1;
|
|
128
|
-
break;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
for (let i = startLine; i < lines.length; i++) {
|
|
132
|
-
const trimmed = lines[i]?.trim() || "";
|
|
133
|
-
if (!title && trimmed.startsWith("# ")) {
|
|
134
|
-
title = trimmed.slice(2).trim();
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
if (title && trimmed && !trimmed.startsWith("#")) {
|
|
138
|
-
description = trimmed;
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return { title, description };
|
|
143
|
-
}
|
|
144
|
-
function toSkillName(name) {
|
|
145
|
-
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 64);
|
|
146
|
-
}
|
|
147
39
|
function collectAllDocs(cwd) {
|
|
148
40
|
const docs = [], seen = /* @__PURE__ */ new Set(), localDocsDir = join(cwd, "docs");
|
|
149
41
|
if (existsSync(localDocsDir)) {
|
|
@@ -163,24 +55,25 @@ function collectAllDocs(cwd) {
|
|
|
163
55
|
return docs;
|
|
164
56
|
}
|
|
165
57
|
async function generateDocSkills(cwd, clean) {
|
|
166
|
-
const skillsDir = join(cwd, ".claude", "skills"), docs = collectAllDocs(cwd);
|
|
167
|
-
if (docs.length === 0)
|
|
168
|
-
return console.info(pc.yellow("no documentation files found")), { symlinked: 0, generated: 0, unchanged: 0 };
|
|
169
|
-
if (console.info(pc.dim(`found ${docs.length} documentation files`)), clean && existsSync(skillsDir)) {
|
|
58
|
+
const skillsDir = join(cwd, ".claude", "skills"), docs = collectAllDocs(cwd), localDocsDir = join(cwd, "docs"), expectedSkillNames = /* @__PURE__ */ new Set();
|
|
59
|
+
if (docs.length === 0 ? console.info(pc.yellow("no documentation files found")) : console.info(pc.dim(`found ${docs.length} documentation files`)), clean && existsSync(skillsDir)) {
|
|
170
60
|
const existing = readdirSync(skillsDir);
|
|
171
61
|
for (const dir of existing)
|
|
172
62
|
dir.startsWith(SKILL_PREFIX) && rmSync(join(skillsDir, dir), { recursive: !0 });
|
|
173
63
|
}
|
|
174
64
|
existsSync(skillsDir) || mkdirSync(skillsDir, { recursive: !0 });
|
|
175
|
-
let symlinked = 0, generated = 0, unchanged = 0;
|
|
65
|
+
let symlinked = 0, generated = 0, unchanged = 0, removed = 0, skipped = 0;
|
|
176
66
|
const isDev = !!process.env.IS_TAMAGUI_DEV;
|
|
177
67
|
for (const doc of docs) {
|
|
178
68
|
const content = readFileSync(doc.path, "utf-8");
|
|
179
69
|
if (isDevOnly(content) && !isDev) continue;
|
|
180
|
-
|
|
70
|
+
const hasFrontmatter = hasSkillFrontmatter(content);
|
|
71
|
+
if (hasFrontmatter) {
|
|
181
72
|
const nameMatch = content.match(/^---\s*\nname:\s*([^\n]+)/m);
|
|
182
73
|
if (!nameMatch) continue;
|
|
183
|
-
const skillName = nameMatch[1].trim()
|
|
74
|
+
const skillName = nameMatch[1].trim();
|
|
75
|
+
expectedSkillNames.add(skillName);
|
|
76
|
+
const skillDir = join(skillsDir, skillName), skillFile = join(skillDir, "SKILL.md");
|
|
184
77
|
existsSync(skillDir) || mkdirSync(skillDir, { recursive: !0 });
|
|
185
78
|
const relativePath = relative(skillDir, doc.path);
|
|
186
79
|
let shouldCreate = !0;
|
|
@@ -194,44 +87,36 @@ async function generateDocSkills(cwd, clean) {
|
|
|
194
87
|
console.info(
|
|
195
88
|
` ${pc.green("\u27F7")} ${skillName} ${sourceLabel} ${pc.dim("(symlink)")}`
|
|
196
89
|
);
|
|
197
|
-
} else {
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const { title, description } = extractDocMeta(content), skillDescription = description ? `${title}. ${description}`.slice(0, 1024) : title.slice(0, 1024), skillContent = `---
|
|
201
|
-
name: ${skillName}
|
|
202
|
-
description: ${skillDescription}
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
${content}
|
|
206
|
-
`;
|
|
207
|
-
let shouldWrite = !0;
|
|
208
|
-
try {
|
|
209
|
-
lstatSync(skillFile).isSymbolicLink() ? unlinkSync(skillFile) : readFileSync(skillFile, "utf-8") === skillContent && (unchanged++, shouldWrite = !1);
|
|
210
|
-
} catch {
|
|
211
|
-
}
|
|
212
|
-
if (!shouldWrite) continue;
|
|
213
|
-
writeFileSync(skillFile, skillContent), generated++;
|
|
214
|
-
const sourceLabel = doc.source === "local" ? pc.blue("local") : pc.dim("package");
|
|
215
|
-
console.info(
|
|
216
|
-
` ${pc.green("\u2713")} ${skillName} ${sourceLabel} ${pc.dim("(generated)")}`
|
|
90
|
+
} else if (!hasFrontmatter) {
|
|
91
|
+
skipped++, console.info(
|
|
92
|
+
` ${pc.yellow("!")} skipped ${pc.dim(doc.name)} ${pc.dim("(missing skill frontmatter)")}`
|
|
217
93
|
);
|
|
94
|
+
continue;
|
|
218
95
|
}
|
|
219
96
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
97
|
+
for (const dir of readdirSync(skillsDir)) {
|
|
98
|
+
if (expectedSkillNames.has(dir)) continue;
|
|
99
|
+
const skillDir = join(skillsDir, dir), skillFile = join(skillDir, "SKILL.md");
|
|
100
|
+
if (dir.startsWith(SKILL_PREFIX)) {
|
|
101
|
+
rmSync(skillDir, { recursive: !0, force: !0 }), removed++, console.info(` ${pc.red("\u2715")} ${dir} ${pc.dim("(removed stale generated skill)")}`);
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
let shouldUnlink = !1;
|
|
105
|
+
try {
|
|
106
|
+
if (lstatSync(skillFile).isSymbolicLink()) {
|
|
107
|
+
const linkTarget = readlinkSync(skillFile), resolvedTarget = resolve(skillDir, linkTarget);
|
|
108
|
+
shouldUnlink = resolvedTarget.startsWith(`${localDocsDir}/`) || !!DOCS_DIR && resolvedTarget.startsWith(`${DOCS_DIR}/`);
|
|
109
|
+
}
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
shouldUnlink && (unlinkSync(skillFile), readdirSync(skillDir).length === 0 && rmdirSync(skillDir), removed++, console.info(` ${pc.red("\u2715")} ${dir} ${pc.dim("(removed stale symlink)")}`));
|
|
230
113
|
}
|
|
231
|
-
|
|
114
|
+
return { symlinked, generated, unchanged, removed, skipped };
|
|
115
|
+
}
|
|
116
|
+
const generateCommand = defineCommand({
|
|
232
117
|
meta: {
|
|
233
118
|
name: "generate",
|
|
234
|
-
description: "Generate
|
|
119
|
+
description: "Generate Claude Code skills from documentation"
|
|
235
120
|
},
|
|
236
121
|
args: {
|
|
237
122
|
clean: {
|
|
@@ -248,14 +133,16 @@ const scriptsCommand = defineCommand({
|
|
|
248
133
|
async run({ args }) {
|
|
249
134
|
const cwd = process.cwd(), skillsDir = join(cwd, ".claude", "skills");
|
|
250
135
|
console.info(), console.info(pc.bold(pc.cyan("Generate all skills"))), console.info();
|
|
251
|
-
let symlinked = 0, generated = 0, unchanged = 0;
|
|
136
|
+
let symlinked = 0, generated = 0, unchanged = 0, removed = 0, skipped = 0;
|
|
252
137
|
if (!args["skip-internal-docs"]) {
|
|
253
138
|
const docStats = await generateDocSkills(cwd, args.clean);
|
|
254
|
-
symlinked = docStats.symlinked, generated = docStats.generated, unchanged = docStats.unchanged, console.info();
|
|
139
|
+
symlinked = docStats.symlinked, generated = docStats.generated, unchanged = docStats.unchanged, removed = docStats.removed, skipped = docStats.skipped, console.info();
|
|
255
140
|
}
|
|
256
|
-
|
|
141
|
+
console.info(), console.info(pc.bold("summary:")), symlinked > 0 && console.info(` ${pc.green(`${symlinked} symlinked`)}`), generated > 0 && console.info(
|
|
257
142
|
` ${pc.yellow(`${generated} generated`)} ${pc.dim("(add frontmatter to enable symlink)")}`
|
|
258
|
-
),
|
|
143
|
+
), skipped > 0 && console.info(
|
|
144
|
+
` ${pc.yellow(`${skipped} skipped`)} ${pc.dim("(missing skill frontmatter)")}`
|
|
145
|
+
), unchanged > 0 && console.info(` ${pc.dim(`${unchanged} unchanged`)}`), removed > 0 && console.info(` ${pc.red(`${removed} removed`)}`), console.info(pc.dim(` skills in ${skillsDir}`)), console.info();
|
|
259
146
|
}
|
|
260
147
|
}), skillsCommand = defineCommand({
|
|
261
148
|
meta: {
|
|
@@ -263,8 +150,7 @@ const scriptsCommand = defineCommand({
|
|
|
263
150
|
description: "Manage Claude Code skills"
|
|
264
151
|
},
|
|
265
152
|
subCommands: {
|
|
266
|
-
generate: generateCommand
|
|
267
|
-
scripts: scriptsCommand
|
|
153
|
+
generate: generateCommand
|
|
268
154
|
}
|
|
269
155
|
});
|
|
270
156
|
export {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/commands/skills.ts"],
|
|
4
|
-
"mappings": "AAIA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": ["require"]
|
|
6
6
|
}
|
|
@@ -1,109 +1,8 @@
|
|
|
1
|
-
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, symlinkSync, unlinkSync
|
|
1
|
+
import { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, readlinkSync, rmSync, rmdirSync, symlinkSync, unlinkSync } from "node:fs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import { dirname, join, relative } from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
5
4
|
import { defineCommand } from "citty";
|
|
6
5
|
import pc from "picocolors";
|
|
7
|
-
import { discoverScripts, getAllScriptMetadata, getLocalScriptsDir } from "../utils/script-utils.mjs";
|
|
8
|
-
const BUILTIN_COMMANDS = [{
|
|
9
|
-
name: "onboard",
|
|
10
|
-
description: "setup wizard for new projects"
|
|
11
|
-
}, {
|
|
12
|
-
name: "docs",
|
|
13
|
-
description: "view documentation"
|
|
14
|
-
}, {
|
|
15
|
-
name: "env:setup",
|
|
16
|
-
description: "setup environment variables"
|
|
17
|
-
}, {
|
|
18
|
-
name: "run",
|
|
19
|
-
description: "run scripts in parallel"
|
|
20
|
-
}, {
|
|
21
|
-
name: "script",
|
|
22
|
-
description: "manage and run scripts"
|
|
23
|
-
}, {
|
|
24
|
-
name: "sync",
|
|
25
|
-
description: "sync fork with upstream takeout"
|
|
26
|
-
}, {
|
|
27
|
-
name: "changed",
|
|
28
|
-
description: "show changes since last sync"
|
|
29
|
-
}, {
|
|
30
|
-
name: "skills",
|
|
31
|
-
description: "manage claude code skills"
|
|
32
|
-
}, {
|
|
33
|
-
name: "completion",
|
|
34
|
-
description: "shell completion setup"
|
|
35
|
-
}];
|
|
36
|
-
function findScriptsPackageRoot() {
|
|
37
|
-
try {
|
|
38
|
-
const resolved = import.meta.resolve("@take-out/scripts/package.json"),
|
|
39
|
-
packageJsonPath = fileURLToPath(new URL(resolved));
|
|
40
|
-
return join(packageJsonPath, "..", "src");
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function buildSummaryDescription(localScripts, builtInScripts) {
|
|
46
|
-
const categories = /* @__PURE__ */new Set(),
|
|
47
|
-
keywords = /* @__PURE__ */new Set();
|
|
48
|
-
for (const [name] of [...localScripts, ...builtInScripts]) keywords.add(name), name.includes("/") && categories.add(name.split("/")[0]);
|
|
49
|
-
for (const cmd of BUILTIN_COMMANDS) keywords.add(cmd.name);
|
|
50
|
-
return `CLI scripts and commands reference for the tko (takeout) CLI. Use when the user asks to run scripts, manage the project, or needs to know what commands are available. tko, takeout, CLI, scripts, commands, bun tko, project tasks, automation, ${[...categories].sort().join(", ")}, ${[...keywords].sort().join(", ")}`.slice(0, 2048);
|
|
51
|
-
}
|
|
52
|
-
function buildSummaryContent(localScripts, builtInScripts, metadata) {
|
|
53
|
-
const description = buildSummaryDescription(localScripts, builtInScripts),
|
|
54
|
-
lines = [];
|
|
55
|
-
lines.push("---"), lines.push("name: tko-scripts"), lines.push(`description: ${description}`), lines.push("---"), lines.push(""), lines.push("# tko CLI - scripts & commands"), lines.push(""), lines.push("run with `bun tko <command>` or `bun tko <script-name>`."), lines.push(""), lines.push("## built-in commands"), lines.push("");
|
|
56
|
-
for (const cmd of BUILTIN_COMMANDS) lines.push(` ${cmd.name} - ${cmd.description}`);
|
|
57
|
-
lines.push("");
|
|
58
|
-
const formatSection = (title, scripts) => {
|
|
59
|
-
if (scripts.size === 0) return;
|
|
60
|
-
const categories = /* @__PURE__ */new Map(),
|
|
61
|
-
rootScripts = [];
|
|
62
|
-
for (const [name] of scripts) if (name.includes("/")) {
|
|
63
|
-
const category = name.split("/")[0];
|
|
64
|
-
categories.has(category) || categories.set(category, []), categories.get(category).push(name);
|
|
65
|
-
} else rootScripts.push(name);
|
|
66
|
-
lines.push(`## ${title}`), lines.push("");
|
|
67
|
-
for (const name of rootScripts) {
|
|
68
|
-
const meta = metadata.get(name),
|
|
69
|
-
desc = meta?.description ? ` - ${meta.description}` : "",
|
|
70
|
-
args = meta?.args?.length ? ` [${meta.args.join(", ")}]` : "";
|
|
71
|
-
lines.push(` ${name}${desc}${args}`);
|
|
72
|
-
}
|
|
73
|
-
for (const [category, categoryScripts] of categories) {
|
|
74
|
-
lines.push(""), lines.push(` ${category}/`);
|
|
75
|
-
for (const name of categoryScripts) {
|
|
76
|
-
const shortName = name.substring(category.length + 1),
|
|
77
|
-
meta = metadata.get(name),
|
|
78
|
-
desc = meta?.description ? ` - ${meta.description}` : "",
|
|
79
|
-
args = meta?.args?.length ? ` [${meta.args.join(", ")}]` : "";
|
|
80
|
-
lines.push(` ${shortName}${desc}${args}`);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
lines.push("");
|
|
84
|
-
};
|
|
85
|
-
return formatSection("local scripts", localScripts), formatSection("built-in scripts", builtInScripts), lines.push("## usage"), lines.push(""), lines.push("```bash"), lines.push("bun tko <command> # run a built-in command"), lines.push("bun tko <script-name> # execute direct script"), lines.push("bun tko <group> <script> # execute nested script (e.g. bun tko aws health)"), lines.push("bun tko run s1 s2 s3 # run multiple scripts in parallel"), lines.push("bun tko script new <path> # create a new script"), lines.push("```"), lines.push(""), lines.join(`
|
|
86
|
-
`);
|
|
87
|
-
}
|
|
88
|
-
async function generateSummary(cwd) {
|
|
89
|
-
const skillsDir = join(cwd, ".claude", "skills"),
|
|
90
|
-
skillDir = join(skillsDir, "tko-scripts"),
|
|
91
|
-
skillFile = join(skillDir, "SKILL.md"),
|
|
92
|
-
localScripts = discoverScripts(getLocalScriptsDir()),
|
|
93
|
-
builtInDir = findScriptsPackageRoot(),
|
|
94
|
-
builtInScripts = builtInDir ? discoverScripts(builtInDir) : /* @__PURE__ */new Map(),
|
|
95
|
-
allScripts = new Map([...localScripts, ...builtInScripts]),
|
|
96
|
-
metadata = await getAllScriptMetadata(allScripts),
|
|
97
|
-
totalScripts = localScripts.size + builtInScripts.size;
|
|
98
|
-
console.info(pc.dim(`found ${totalScripts} scripts (${localScripts.size} local, ${builtInScripts.size} built-in) + ${BUILTIN_COMMANDS.length} commands`));
|
|
99
|
-
const content = buildSummaryContent(localScripts, builtInScripts, metadata);
|
|
100
|
-
try {
|
|
101
|
-
if (readFileSync(skillFile, "utf-8") === content) return console.info(` ${pc.dim("tko-scripts")} ${pc.dim("unchanged")}`), !1;
|
|
102
|
-
} catch {}
|
|
103
|
-
return existsSync(skillDir) || mkdirSync(skillDir, {
|
|
104
|
-
recursive: !0
|
|
105
|
-
}), writeFileSync(skillFile, content), console.info(` ${pc.green("\u2713")} tko-scripts`), !0;
|
|
106
|
-
}
|
|
107
6
|
const require2 = createRequire(import.meta.url);
|
|
108
7
|
let DOCS_DIR;
|
|
109
8
|
try {
|
|
@@ -126,37 +25,6 @@ function isDevOnly(content) {
|
|
|
126
25
|
const frontmatter = content.slice(3, endIndex);
|
|
127
26
|
return /\bdev:\s*true\b/.test(frontmatter);
|
|
128
27
|
}
|
|
129
|
-
function extractDocMeta(content) {
|
|
130
|
-
const lines = content.split(`
|
|
131
|
-
`);
|
|
132
|
-
let title = "",
|
|
133
|
-
description = "",
|
|
134
|
-
startLine = 0;
|
|
135
|
-
if (lines[0]?.trim() === "---") {
|
|
136
|
-
for (let i = 1; i < lines.length; i++) if (lines[i]?.trim() === "---") {
|
|
137
|
-
startLine = i + 1;
|
|
138
|
-
break;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
for (let i = startLine; i < lines.length; i++) {
|
|
142
|
-
const trimmed = lines[i]?.trim() || "";
|
|
143
|
-
if (!title && trimmed.startsWith("# ")) {
|
|
144
|
-
title = trimmed.slice(2).trim();
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (title && trimmed && !trimmed.startsWith("#")) {
|
|
148
|
-
description = trimmed;
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return {
|
|
153
|
-
title,
|
|
154
|
-
description
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
function toSkillName(name) {
|
|
158
|
-
return name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 64);
|
|
159
|
-
}
|
|
160
28
|
function collectAllDocs(cwd) {
|
|
161
29
|
const docs = [],
|
|
162
30
|
seen = /* @__PURE__ */new Set(),
|
|
@@ -187,13 +55,10 @@ function collectAllDocs(cwd) {
|
|
|
187
55
|
}
|
|
188
56
|
async function generateDocSkills(cwd, clean) {
|
|
189
57
|
const skillsDir = join(cwd, ".claude", "skills"),
|
|
190
|
-
docs = collectAllDocs(cwd)
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
unchanged: 0
|
|
195
|
-
};
|
|
196
|
-
if (console.info(pc.dim(`found ${docs.length} documentation files`)), clean && existsSync(skillsDir)) {
|
|
58
|
+
docs = collectAllDocs(cwd),
|
|
59
|
+
localDocsDir = join(cwd, "docs"),
|
|
60
|
+
expectedSkillNames = /* @__PURE__ */new Set();
|
|
61
|
+
if (docs.length === 0 ? console.info(pc.yellow("no documentation files found")) : console.info(pc.dim(`found ${docs.length} documentation files`)), clean && existsSync(skillsDir)) {
|
|
197
62
|
const existing = readdirSync(skillsDir);
|
|
198
63
|
for (const dir of existing) dir.startsWith(SKILL_PREFIX) && rmSync(join(skillsDir, dir), {
|
|
199
64
|
recursive: !0
|
|
@@ -204,16 +69,20 @@ async function generateDocSkills(cwd, clean) {
|
|
|
204
69
|
});
|
|
205
70
|
let symlinked = 0,
|
|
206
71
|
generated = 0,
|
|
207
|
-
unchanged = 0
|
|
72
|
+
unchanged = 0,
|
|
73
|
+
removed = 0,
|
|
74
|
+
skipped = 0;
|
|
208
75
|
const isDev = !!process.env.IS_TAMAGUI_DEV;
|
|
209
76
|
for (const doc of docs) {
|
|
210
77
|
const content = readFileSync(doc.path, "utf-8");
|
|
211
78
|
if (isDevOnly(content) && !isDev) continue;
|
|
212
|
-
|
|
79
|
+
const hasFrontmatter = hasSkillFrontmatter(content);
|
|
80
|
+
if (hasFrontmatter) {
|
|
213
81
|
const nameMatch = content.match(/^---\s*\nname:\s*([^\n]+)/m);
|
|
214
82
|
if (!nameMatch) continue;
|
|
215
|
-
const skillName = nameMatch[1].trim()
|
|
216
|
-
|
|
83
|
+
const skillName = nameMatch[1].trim();
|
|
84
|
+
expectedSkillNames.add(skillName);
|
|
85
|
+
const skillDir = join(skillsDir, skillName),
|
|
217
86
|
skillFile = join(skillDir, "SKILL.md");
|
|
218
87
|
existsSync(skillDir) || mkdirSync(skillDir, {
|
|
219
88
|
recursive: !0
|
|
@@ -227,56 +96,44 @@ async function generateDocSkills(cwd, clean) {
|
|
|
227
96
|
symlinkSync(relativePath, skillFile), symlinked++;
|
|
228
97
|
const sourceLabel = doc.source === "local" ? pc.blue("local") : pc.dim("package");
|
|
229
98
|
console.info(` ${pc.green("\u27F7")} ${skillName} ${sourceLabel} ${pc.dim("(symlink)")}`);
|
|
230
|
-
} else {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
skillDir = join(skillsDir, skillName),
|
|
234
|
-
skillFile = join(skillDir, "SKILL.md");
|
|
235
|
-
existsSync(skillDir) || mkdirSync(skillDir, {
|
|
236
|
-
recursive: !0
|
|
237
|
-
});
|
|
238
|
-
const {
|
|
239
|
-
title,
|
|
240
|
-
description
|
|
241
|
-
} = extractDocMeta(content),
|
|
242
|
-
skillDescription = description ? `${title}. ${description}`.slice(0, 1024) : title.slice(0, 1024),
|
|
243
|
-
skillContent = `---
|
|
244
|
-
name: ${skillName}
|
|
245
|
-
description: ${skillDescription}
|
|
246
|
-
---
|
|
247
|
-
|
|
248
|
-
${content}
|
|
249
|
-
`;
|
|
250
|
-
let shouldWrite = !0;
|
|
251
|
-
try {
|
|
252
|
-
lstatSync(skillFile).isSymbolicLink() ? unlinkSync(skillFile) : readFileSync(skillFile, "utf-8") === skillContent && (unchanged++, shouldWrite = !1);
|
|
253
|
-
} catch {}
|
|
254
|
-
if (!shouldWrite) continue;
|
|
255
|
-
writeFileSync(skillFile, skillContent), generated++;
|
|
256
|
-
const sourceLabel = doc.source === "local" ? pc.blue("local") : pc.dim("package");
|
|
257
|
-
console.info(` ${pc.green("\u2713")} ${skillName} ${sourceLabel} ${pc.dim("(generated)")}`);
|
|
99
|
+
} else if (!hasFrontmatter) {
|
|
100
|
+
skipped++, console.info(` ${pc.yellow("!")} skipped ${pc.dim(doc.name)} ${pc.dim("(missing skill frontmatter)")}`);
|
|
101
|
+
continue;
|
|
258
102
|
}
|
|
259
103
|
}
|
|
104
|
+
for (const dir of readdirSync(skillsDir)) {
|
|
105
|
+
if (expectedSkillNames.has(dir)) continue;
|
|
106
|
+
const skillDir = join(skillsDir, dir),
|
|
107
|
+
skillFile = join(skillDir, "SKILL.md");
|
|
108
|
+
if (dir.startsWith(SKILL_PREFIX)) {
|
|
109
|
+
rmSync(skillDir, {
|
|
110
|
+
recursive: !0,
|
|
111
|
+
force: !0
|
|
112
|
+
}), removed++, console.info(` ${pc.red("\u2715")} ${dir} ${pc.dim("(removed stale generated skill)")}`);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
let shouldUnlink = !1;
|
|
116
|
+
try {
|
|
117
|
+
if (lstatSync(skillFile).isSymbolicLink()) {
|
|
118
|
+
const linkTarget = readlinkSync(skillFile),
|
|
119
|
+
resolvedTarget = resolve(skillDir, linkTarget);
|
|
120
|
+
shouldUnlink = resolvedTarget.startsWith(`${localDocsDir}/`) || !!DOCS_DIR && resolvedTarget.startsWith(`${DOCS_DIR}/`);
|
|
121
|
+
}
|
|
122
|
+
} catch {}
|
|
123
|
+
shouldUnlink && (unlinkSync(skillFile), readdirSync(skillDir).length === 0 && rmdirSync(skillDir), removed++, console.info(` ${pc.red("\u2715")} ${dir} ${pc.dim("(removed stale symlink)")}`));
|
|
124
|
+
}
|
|
260
125
|
return {
|
|
261
126
|
symlinked,
|
|
262
127
|
generated,
|
|
263
|
-
unchanged
|
|
128
|
+
unchanged,
|
|
129
|
+
removed,
|
|
130
|
+
skipped
|
|
264
131
|
};
|
|
265
132
|
}
|
|
266
|
-
const
|
|
267
|
-
meta: {
|
|
268
|
-
name: "scripts",
|
|
269
|
-
description: "Generate a skill summarizing all tko scripts and commands"
|
|
270
|
-
},
|
|
271
|
-
async run() {
|
|
272
|
-
const cwd = process.cwd();
|
|
273
|
-
console.info(), console.info(pc.bold(pc.cyan("Generate scripts skill"))), console.info(), await generateSummary(cwd), console.info();
|
|
274
|
-
}
|
|
275
|
-
}),
|
|
276
|
-
generateCommand = defineCommand({
|
|
133
|
+
const generateCommand = defineCommand({
|
|
277
134
|
meta: {
|
|
278
135
|
name: "generate",
|
|
279
|
-
description: "Generate
|
|
136
|
+
description: "Generate Claude Code skills from documentation"
|
|
280
137
|
},
|
|
281
138
|
args: {
|
|
282
139
|
clean: {
|
|
@@ -298,12 +155,14 @@ const scriptsCommand = defineCommand({
|
|
|
298
155
|
console.info(), console.info(pc.bold(pc.cyan("Generate all skills"))), console.info();
|
|
299
156
|
let symlinked = 0,
|
|
300
157
|
generated = 0,
|
|
301
|
-
unchanged = 0
|
|
158
|
+
unchanged = 0,
|
|
159
|
+
removed = 0,
|
|
160
|
+
skipped = 0;
|
|
302
161
|
if (!args["skip-internal-docs"]) {
|
|
303
162
|
const docStats = await generateDocSkills(cwd, args.clean);
|
|
304
|
-
symlinked = docStats.symlinked, generated = docStats.generated, unchanged = docStats.unchanged, console.info();
|
|
163
|
+
symlinked = docStats.symlinked, generated = docStats.generated, unchanged = docStats.unchanged, removed = docStats.removed, skipped = docStats.skipped, console.info();
|
|
305
164
|
}
|
|
306
|
-
|
|
165
|
+
console.info(), console.info(pc.bold("summary:")), symlinked > 0 && console.info(` ${pc.green(`${symlinked} symlinked`)}`), generated > 0 && console.info(` ${pc.yellow(`${generated} generated`)} ${pc.dim("(add frontmatter to enable symlink)")}`), skipped > 0 && console.info(` ${pc.yellow(`${skipped} skipped`)} ${pc.dim("(missing skill frontmatter)")}`), unchanged > 0 && console.info(` ${pc.dim(`${unchanged} unchanged`)}`), removed > 0 && console.info(` ${pc.red(`${removed} removed`)}`), console.info(pc.dim(` skills in ${skillsDir}`)), console.info();
|
|
307
166
|
}
|
|
308
167
|
}),
|
|
309
168
|
skillsCommand = defineCommand({
|
|
@@ -312,8 +171,7 @@ const scriptsCommand = defineCommand({
|
|
|
312
171
|
description: "Manage Claude Code skills"
|
|
313
172
|
},
|
|
314
173
|
subCommands: {
|
|
315
|
-
generate: generateCommand
|
|
316
|
-
scripts: scriptsCommand
|
|
174
|
+
generate: generateCommand
|
|
317
175
|
}
|
|
318
176
|
});
|
|
319
177
|
export { skillsCommand };
|