thachvd-kit 1.0.36 → 1.0.37

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.
@@ -0,0 +1,149 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ const NATIVE_SKILLS = [
5
+ 'using-git-worktrees',
6
+ 'subagent-driven-development',
7
+ 'finishing-a-development-branch'
8
+ ];
9
+
10
+ const NATIVE_SUPPORT_FILES = [
11
+ path.join('requesting-code-review', 'code-reviewer.md')
12
+ ];
13
+
14
+ const NATIVE_SKILL_SURFACES = [
15
+ { id: 'agents', relativeDir: path.join('.agents', 'skills') },
16
+ { id: 'claude', relativeDir: path.join('.claude', 'skills') }
17
+ ];
18
+
19
+ const nativeSkillsSourceDir = path.resolve(__dirname, '..', 'skills');
20
+
21
+ function sourcePath(relativePath) {
22
+ return path.join(nativeSkillsSourceDir, relativePath);
23
+ }
24
+
25
+ function skillSourceDir(name) {
26
+ return sourcePath(name);
27
+ }
28
+
29
+ function collectFiles(directory, relative = '') {
30
+ const files = [];
31
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
32
+ const entryRelative = path.join(relative, entry.name);
33
+ const entryPath = path.join(directory, entry.name);
34
+ if (entry.isDirectory()) files.push(...collectFiles(entryPath, entryRelative));
35
+ else if (entry.isFile()) files.push(entryRelative);
36
+ }
37
+ return files;
38
+ }
39
+
40
+ function ownedFiles() {
41
+ return [
42
+ ...NATIVE_SKILLS.flatMap(name => collectFiles(skillSourceDir(name), name)),
43
+ ...NATIVE_SUPPORT_FILES
44
+ ];
45
+ }
46
+
47
+ function ownedSkillFiles(name) {
48
+ return collectFiles(skillSourceDir(name), name);
49
+ }
50
+
51
+ function targetPath(targetDir, surface, relativePath) {
52
+ return path.join(targetDir, surface.relativeDir, relativePath);
53
+ }
54
+
55
+ function checkNativeSkills(targetDir) {
56
+ const surfaces = {};
57
+ const skills = {};
58
+
59
+ for (const surface of NATIVE_SKILL_SURFACES) {
60
+ const missingFiles = ownedFiles().filter(relativePath => !fs.existsSync(targetPath(targetDir, surface, relativePath)));
61
+ const installed = [];
62
+ const missing = [];
63
+ for (const name of NATIVE_SKILLS) {
64
+ (ownedSkillFiles(name).every(relativePath => fs.existsSync(targetPath(targetDir, surface, relativePath)))
65
+ ? installed
66
+ : missing).push(name);
67
+ }
68
+ const supportInstalled = NATIVE_SUPPORT_FILES.filter(relativePath => !missingFiles.includes(relativePath));
69
+ const supportMissing = NATIVE_SUPPORT_FILES.filter(relativePath => missingFiles.includes(relativePath));
70
+ surfaces[surface.id] = {
71
+ installed,
72
+ missing,
73
+ total: NATIVE_SKILLS.length,
74
+ missingFiles,
75
+ support: {
76
+ installed: supportInstalled,
77
+ missing: supportMissing,
78
+ total: NATIVE_SUPPORT_FILES.length
79
+ }
80
+ };
81
+ }
82
+
83
+ for (const name of NATIVE_SKILLS) {
84
+ skills[name] = {};
85
+ for (const surface of NATIVE_SKILL_SURFACES) {
86
+ skills[name][surface.id] = ownedSkillFiles(name).every(relativePath => fs.existsSync(targetPath(targetDir, surface, relativePath)));
87
+ }
88
+ }
89
+
90
+ const installed = NATIVE_SKILLS.filter(name => NATIVE_SKILL_SURFACES.every(surface => skills[name][surface.id]));
91
+ const missing = NATIVE_SKILLS.filter(name => !installed.includes(name));
92
+ const missingFiles = Object.fromEntries(NATIVE_SKILL_SURFACES.map(surface => [surface.id, surfaces[surface.id].missingFiles]));
93
+ return {
94
+ installed,
95
+ missing,
96
+ total: NATIVE_SKILLS.length,
97
+ allInstalled: missingFiles.agents.length === 0 && missingFiles.claude.length === 0,
98
+ surfaces,
99
+ skills,
100
+ missingFiles
101
+ };
102
+ }
103
+
104
+ function copyFile(source, destination) {
105
+ fs.mkdirSync(path.dirname(destination), { recursive: true });
106
+ fs.copyFileSync(source, destination);
107
+ }
108
+
109
+ function installNativeSkills(targetDir, options = {}) {
110
+ const dryRun = options.dryRun === true;
111
+ const operations = [];
112
+ for (const surface of NATIVE_SKILL_SURFACES) {
113
+ for (const relativePath of ownedFiles()) {
114
+ const source = sourcePath(relativePath);
115
+ const destination = targetPath(targetDir, surface, relativePath);
116
+ operations.push({ surface: surface.id, relativePath, source, destination });
117
+ if (!dryRun) copyFile(source, destination);
118
+ }
119
+ }
120
+ return {
121
+ ok: true,
122
+ dryRun,
123
+ operations,
124
+ results: NATIVE_SKILLS.map(name => ({ name, ok: true, dryRun })),
125
+ message: dryRun
126
+ ? `Dry run: would copy ${NATIVE_SKILLS.length} native skills to .agents/skills and .claude/skills`
127
+ : `installed ${NATIVE_SKILLS.length} thachvd-kit native skills to .agents/skills and .claude/skills`
128
+ };
129
+ }
130
+
131
+ function updateNativeSkills(targetDir, options = {}) {
132
+ const result = installNativeSkills(targetDir, options);
133
+ return {
134
+ ...result,
135
+ message: result.dryRun
136
+ ? `Dry run: would refresh ${NATIVE_SKILLS.length} native skills from bundled copies`
137
+ : `updated ${NATIVE_SKILLS.length} thachvd-kit native skills from bundled copies`
138
+ };
139
+ }
140
+
141
+ module.exports = {
142
+ NATIVE_SKILLS,
143
+ NATIVE_SUPPORT_FILES,
144
+ NATIVE_SKILL_SURFACES,
145
+ nativeSkillsSourceDir,
146
+ checkNativeSkills,
147
+ installNativeSkills,
148
+ updateNativeSkills
149
+ };