@dealdeploy/skl 0.4.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/add-tui.test.ts +338 -0
- package/add-tui.ts +269 -0
- package/add.ts +81 -328
- package/index.ts +112 -976
- package/lib.test.ts +470 -40
- package/lib.ts +240 -37
- package/package.json +1 -1
- package/skills-lock.json +10 -0
- package/tui.test.ts +565 -0
- package/tui.ts +612 -0
- package/update.ts +90 -90
package/update.ts
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const localDirs: [string, string][] = [];
|
|
16
|
-
const agentsDir = join(process.cwd(), ".agents/skills");
|
|
17
|
-
if (existsSync(agentsDir)) localDirs.push([agentsDir, ".agents/skills"]);
|
|
18
|
-
|
|
19
|
-
const claudeDir = join(process.cwd(), ".claude/skills");
|
|
20
|
-
if (existsSync(claudeDir)) localDirs.push([claudeDir, ".claude/skills"]);
|
|
21
|
-
|
|
22
|
-
if (localDirs.length === 0) {
|
|
23
|
-
console.log("No local skill directories found.");
|
|
1
|
+
import { rmSync, mkdirSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import {
|
|
4
|
+
readLock, writeLock, catalogDir, downloadSkillFiles,
|
|
5
|
+
groupByRepo, planUpdates, type TreeEntry,
|
|
6
|
+
} from "./lib.ts";
|
|
7
|
+
|
|
8
|
+
const lock = readLock();
|
|
9
|
+
const byRepo = groupByRepo(lock);
|
|
10
|
+
|
|
11
|
+
if (byRepo.size === 0) {
|
|
12
|
+
console.log("No remote skills to update.");
|
|
24
13
|
process.exit(0);
|
|
25
14
|
}
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
16
|
+
// Get GitHub token
|
|
17
|
+
let token = "";
|
|
18
|
+
try {
|
|
19
|
+
const proc = Bun.spawn(["gh", "auth", "token"], { stdout: "pipe", stderr: "pipe" });
|
|
20
|
+
token = (await new Response(proc.stdout).text()).trim();
|
|
21
|
+
await proc.exited;
|
|
22
|
+
} catch {}
|
|
23
|
+
|
|
24
|
+
const headers: Record<string, string> = {
|
|
25
|
+
Accept: "application/vnd.github+json",
|
|
26
|
+
};
|
|
27
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
28
|
+
|
|
29
|
+
let totalUpdated = 0;
|
|
30
|
+
let totalUpToDate = 0;
|
|
31
|
+
let totalErrors = 0;
|
|
32
|
+
const CATALOG = catalogDir();
|
|
33
|
+
|
|
34
|
+
for (const [repo, skills] of byRepo) {
|
|
35
|
+
process.stdout.write(`Checking ${repo}...`);
|
|
36
|
+
|
|
37
|
+
let branch: string;
|
|
38
|
+
try {
|
|
39
|
+
const repoResp = await fetch(`https://api.github.com/repos/${repo}`, { headers });
|
|
40
|
+
if (!repoResp.ok) {
|
|
41
|
+
console.log(` failed (${repoResp.status})`);
|
|
42
|
+
totalErrors += skills.length;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const repoData = (await repoResp.json()) as { default_branch: string };
|
|
46
|
+
branch = repoData.default_branch;
|
|
47
|
+
} catch (e: any) {
|
|
48
|
+
console.log(` failed (${e.message})`);
|
|
49
|
+
totalErrors += skills.length;
|
|
50
|
+
continue;
|
|
40
51
|
}
|
|
41
|
-
}
|
|
42
52
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
const buf = new Uint8Array(100);
|
|
54
|
-
const n = readSync(0, buf);
|
|
55
|
-
const answer = new TextDecoder().decode(buf.subarray(0, n)).trim().toLowerCase();
|
|
56
|
-
|
|
57
|
-
if (answer === "y" || answer === "yes") {
|
|
58
|
-
for (const s of symlinks) {
|
|
59
|
-
const localPath = join(s.dir, s.name);
|
|
60
|
-
unlinkSync(localPath);
|
|
61
|
-
cpSync(join(LIBRARY, s.name), localPath, { recursive: true });
|
|
62
|
-
console.log(` converted ${s.label}/${s.name}`);
|
|
53
|
+
let tree: TreeEntry[];
|
|
54
|
+
try {
|
|
55
|
+
const treeResp = await fetch(
|
|
56
|
+
`https://api.github.com/repos/${repo}/git/trees/${branch}?recursive=1`,
|
|
57
|
+
{ headers },
|
|
58
|
+
);
|
|
59
|
+
if (!treeResp.ok) {
|
|
60
|
+
console.log(` failed (${treeResp.status})`);
|
|
61
|
+
totalErrors += skills.length;
|
|
62
|
+
continue;
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
const treeData = (await treeResp.json()) as { tree: TreeEntry[] };
|
|
65
|
+
tree = treeData.tree;
|
|
66
|
+
} catch (e: any) {
|
|
67
|
+
console.log(` failed (${e.message})`);
|
|
68
|
+
totalErrors += skills.length;
|
|
69
|
+
continue;
|
|
66
70
|
}
|
|
67
|
-
}
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
if (copies.length > 0) {
|
|
71
|
-
console.log(`\nUpdating ${copies.length} local copies from library...`);
|
|
72
|
-
for (const c of copies) {
|
|
73
|
-
const localPath = join(c.dir, c.name);
|
|
74
|
-
rmSync(localPath, { recursive: true, force: true });
|
|
75
|
-
cpSync(join(LIBRARY, c.name), localPath, { recursive: true });
|
|
76
|
-
console.log(` updated ${c.label}/${c.name}`);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
72
|
+
console.log("");
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
74
|
+
const plan = planUpdates(skills, tree);
|
|
75
|
+
|
|
76
|
+
totalUpToDate += plan.upToDate.length;
|
|
77
|
+
totalErrors += plan.notFound.length;
|
|
83
78
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
console.log("\nFound skills in this repo not in your library:");
|
|
87
|
-
for (const o of notInLibrary) {
|
|
88
|
-
console.log(` ${o.dir.replace(homedir(), "~")}/${o.name}`);
|
|
79
|
+
for (const name of plan.notFound) {
|
|
80
|
+
console.log(` ${name}: not found in remote tree (skipped)`);
|
|
89
81
|
}
|
|
90
|
-
process.stdout.write(`\nCopy to ${LIBRARY.replace(homedir(), "~")}? [y/N] `);
|
|
91
82
|
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
83
|
+
for (const skill of plan.updated) {
|
|
84
|
+
const skillDir = join(CATALOG, skill.name);
|
|
85
|
+
rmSync(skillDir, { recursive: true, force: true });
|
|
86
|
+
mkdirSync(skillDir, { recursive: true });
|
|
95
87
|
|
|
96
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
} else {
|
|
103
|
-
console.log("Skipping.");
|
|
88
|
+
process.stdout.write(` ${skill.name}...`);
|
|
89
|
+
const fileCount = await downloadSkillFiles(repo, branch, skill.skillPath, skillDir, tree);
|
|
90
|
+
|
|
91
|
+
lock.skills[skill.name]!.treeSHA = skill.newSHA;
|
|
92
|
+
console.log(` updated (${fileCount} files)`);
|
|
93
|
+
totalUpdated++;
|
|
104
94
|
}
|
|
105
95
|
}
|
|
96
|
+
|
|
97
|
+
if (totalUpdated > 0) {
|
|
98
|
+
writeLock(lock);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const parts: string[] = [];
|
|
102
|
+
if (totalUpdated > 0) parts.push(`Updated ${totalUpdated} skill(s)`);
|
|
103
|
+
if (totalUpToDate > 0) parts.push(`${totalUpToDate} already up to date`);
|
|
104
|
+
if (totalErrors > 0) parts.push(`${totalErrors} error(s)`);
|
|
105
|
+
console.log(`\n${parts.join(", ")}`);
|