@ghl-ai/aw 0.1.57 → 0.1.58
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/link.mjs +69 -3
- package/package.json +1 -1
package/link.mjs
CHANGED
|
@@ -11,11 +11,29 @@ function forceSymlink(target, linkPath) {
|
|
|
11
11
|
symlinkSync(target, linkPath);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
function linkNestedSkillRoot(target, linkPath, { silent }) {
|
|
15
|
+
try {
|
|
16
|
+
forceSymlink(target, linkPath);
|
|
17
|
+
return true;
|
|
18
|
+
} catch (error) {
|
|
19
|
+
if (!silent) {
|
|
20
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
21
|
+
throw new Error(`Could not link nested skill ${linkPath} -> ${target}: ${message}`);
|
|
22
|
+
}
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
14
27
|
const IDE_DIRS = ['.claude', '.cursor', '.codex'];
|
|
15
28
|
// Per-file symlink types
|
|
16
29
|
const FILE_TYPES = ['agents'];
|
|
17
30
|
const ALL_KNOWN_TYPES = new Set([...FILE_TYPES, 'skills', 'commands', 'evals', 'references', 'docs']);
|
|
18
31
|
|
|
32
|
+
function realHomeDir() {
|
|
33
|
+
const HOME = homedir();
|
|
34
|
+
try { return realpathSync(HOME); } catch { return HOME; }
|
|
35
|
+
}
|
|
36
|
+
|
|
19
37
|
/**
|
|
20
38
|
* List namespace directories inside .aw_registry/ (skip dotfiles).
|
|
21
39
|
*/
|
|
@@ -36,6 +54,32 @@ function listDirs(dir) {
|
|
|
36
54
|
.map(d => d.name);
|
|
37
55
|
}
|
|
38
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Recursively find directories below a skills/ folder that are real skill roots.
|
|
59
|
+
* A real skill root is a directory containing SKILL.md. Once found, do not
|
|
60
|
+
* descend further so bundled references/scripts inside that skill are preserved.
|
|
61
|
+
*/
|
|
62
|
+
function findSkillRootDirs(skillsDir) {
|
|
63
|
+
const results = [];
|
|
64
|
+
function walk(dir, segments) {
|
|
65
|
+
if (!existsSync(dir)) return;
|
|
66
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
67
|
+
if (!entry.isDirectory() || entry.name.startsWith('.')) continue;
|
|
68
|
+
|
|
69
|
+
const childDir = join(dir, entry.name);
|
|
70
|
+
const childSegments = [...segments, entry.name];
|
|
71
|
+
if (existsSync(join(childDir, 'SKILL.md'))) {
|
|
72
|
+
results.push({ skillDirPath: childDir, segments: childSegments });
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
walk(childDir, childSegments);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
walk(skillsDir, []);
|
|
80
|
+
return results;
|
|
81
|
+
}
|
|
82
|
+
|
|
39
83
|
/**
|
|
40
84
|
* Recursively find directories named `typeName` within `nsDir`,
|
|
41
85
|
* skipping other known type directories to avoid false matches.
|
|
@@ -77,7 +121,7 @@ function cleanIdeSymlinks(cwd) {
|
|
|
77
121
|
cleanSymlinksRecursive(ideDir);
|
|
78
122
|
}
|
|
79
123
|
// Also clean .agents/skills/ (global only — Codex reads from ~/.agents/skills/)
|
|
80
|
-
const HOME =
|
|
124
|
+
const HOME = realHomeDir();
|
|
81
125
|
if (cwd === HOME) {
|
|
82
126
|
const agentsSkillsDir = join(cwd, '.agents', 'skills');
|
|
83
127
|
if (existsSync(agentsSkillsDir)) cleanSymlinksRecursive(agentsSkillsDir);
|
|
@@ -140,7 +184,8 @@ export function linkWorkspace(cwd, awDirOverride = null, { silent = false } = {}
|
|
|
140
184
|
// where $HOME may be /var/... but process.cwd() resolves to /private/var/...
|
|
141
185
|
try { cwd = realpathSync(cwd); } catch { /* use as-is */ }
|
|
142
186
|
|
|
143
|
-
const
|
|
187
|
+
const HOME = realHomeDir();
|
|
188
|
+
const GLOBAL_AW_DIR = join(HOME, '.aw_registry');
|
|
144
189
|
let awDir = awDirOverride || getLocalRegistryDir(cwd, GLOBAL_AW_DIR);
|
|
145
190
|
try { awDir = realpathSync(awDir); } catch { /* use as-is if it doesn't exist */ }
|
|
146
191
|
if (!existsSync(awDir)) return 0;
|
|
@@ -185,6 +230,19 @@ export function linkWorkspace(cwd, awDirOverride = null, { silent = false } = {}
|
|
|
185
230
|
try { forceSymlink(relTarget, linkPath); created++; } catch { /* best effort */ }
|
|
186
231
|
}
|
|
187
232
|
}
|
|
233
|
+
|
|
234
|
+
for (const { skillDirPath, segments: skillSegments } of findSkillRootDirs(skillsDir)) {
|
|
235
|
+
if (skillSegments.length <= 1) continue;
|
|
236
|
+
const flat = [ns, ...segments, ...skillSegments].join('-');
|
|
237
|
+
|
|
238
|
+
for (const ide of IDE_DIRS) {
|
|
239
|
+
const linkDir = join(cwd, ide, 'skills');
|
|
240
|
+
mkdirSync(linkDir, { recursive: true });
|
|
241
|
+
const linkPath = join(linkDir, flat);
|
|
242
|
+
const relTarget = relative(linkDir, skillDirPath);
|
|
243
|
+
if (linkNestedSkillRoot(relTarget, linkPath, { silent })) created++;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
188
246
|
}
|
|
189
247
|
}
|
|
190
248
|
|
|
@@ -246,7 +304,7 @@ export function linkWorkspace(cwd, awDirOverride = null, { silent = false } = {}
|
|
|
246
304
|
}
|
|
247
305
|
|
|
248
306
|
// Codex per-skill symlinks: ~/.agents/skills/<name> (global only)
|
|
249
|
-
if (cwd ===
|
|
307
|
+
if (cwd === HOME) {
|
|
250
308
|
const agentsSkillsDir = join(cwd, '.agents/skills');
|
|
251
309
|
for (const ns of namespaces) {
|
|
252
310
|
for (const { typeDirPath: skillsDir, segments } of findNestedTypeDirs(join(awDir, ns), 'skills')) {
|
|
@@ -258,6 +316,14 @@ export function linkWorkspace(cwd, awDirOverride = null, { silent = false } = {}
|
|
|
258
316
|
const relTarget = relative(agentsSkillsDir, targetPath);
|
|
259
317
|
try { forceSymlink(relTarget, linkPath); created++; } catch { /* best effort */ }
|
|
260
318
|
}
|
|
319
|
+
|
|
320
|
+
for (const { skillDirPath, segments: skillSegments } of findSkillRootDirs(skillsDir)) {
|
|
321
|
+
if (skillSegments.length <= 1) continue;
|
|
322
|
+
const flat = [ns, ...segments, ...skillSegments].join('-');
|
|
323
|
+
const linkPath = join(agentsSkillsDir, flat);
|
|
324
|
+
const relTarget = relative(agentsSkillsDir, skillDirPath);
|
|
325
|
+
if (linkNestedSkillRoot(relTarget, linkPath, { silent })) created++;
|
|
326
|
+
}
|
|
261
327
|
}
|
|
262
328
|
}
|
|
263
329
|
|