@ghl-ai/aw 0.1.50-beta.0 → 0.1.50-beta.1
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/commands/init.mjs +34 -26
- package/ecc.mjs +1 -1
- package/git.mjs +13 -0
- package/link.mjs +41 -31
- package/package.json +1 -1
package/commands/init.mjs
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
isValidClone,
|
|
41
41
|
fetchAndMerge,
|
|
42
42
|
addToSparseCheckout,
|
|
43
|
+
setSparseCheckout,
|
|
43
44
|
addProjectWorktree,
|
|
44
45
|
isWorktree,
|
|
45
46
|
includeToSparsePaths,
|
|
@@ -137,6 +138,27 @@ function getSkillInitSpecs(args) {
|
|
|
137
138
|
}
|
|
138
139
|
}
|
|
139
140
|
|
|
141
|
+
function skillInitSparsePaths(skillSpecs) {
|
|
142
|
+
const paths = new Set([
|
|
143
|
+
DOCS_SOURCE_DIR,
|
|
144
|
+
AW_DOCS_DIR,
|
|
145
|
+
RULES_SOURCE_DIR,
|
|
146
|
+
`${REGISTRY_DIR}/AW-PROTOCOL.md`,
|
|
147
|
+
`CODEOWNERS`,
|
|
148
|
+
]);
|
|
149
|
+
|
|
150
|
+
for (const spec of skillSpecs) {
|
|
151
|
+
paths.add(`${REGISTRY_DIR}/${spec.registryPath}`);
|
|
152
|
+
|
|
153
|
+
for (let i = 0; i <= spec.segments.length; i++) {
|
|
154
|
+
const scope = [spec.namespace, ...spec.segments.slice(0, i)].join('/');
|
|
155
|
+
paths.add(`${REGISTRY_DIR}/${scope}/references`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return [...paths];
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
// ── Ensure ~/.aw/.git/info/exclude has the whitelist block ─────────────
|
|
141
163
|
//
|
|
142
164
|
// Strategy: only .aw_registry/, .aw_rules/, content/, and .aw_docs/ are
|
|
@@ -360,24 +382,17 @@ export async function initCommand(args) {
|
|
|
360
382
|
if (isGitNative) {
|
|
361
383
|
const cfg = config.load(GLOBAL_AW_DIR);
|
|
362
384
|
|
|
363
|
-
const newSkillTargets = isSkillInit && cfg
|
|
364
|
-
? skillTargets.filter(target => !cfg.include.some(pattern => target === pattern || target.startsWith(pattern + '/')))
|
|
365
|
-
: [];
|
|
366
385
|
const isNewSubTeam = !isSkillInit && folderName && cfg && !cfg.include.includes(folderName);
|
|
367
386
|
|
|
368
387
|
if (isSkillInit) {
|
|
369
|
-
if (
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
]);
|
|
378
|
-
for (const target of newSkillTargets) config.addPattern(GLOBAL_AW_DIR, target);
|
|
379
|
-
} else if (!silent) {
|
|
380
|
-
fmt.logStep('Already initialized — syncing selected skills...');
|
|
388
|
+
if (!silent) fmt.logStep('Syncing selected skills...');
|
|
389
|
+
setSparseCheckout(AW_HOME, skillInitSparsePaths(skillSpecs));
|
|
390
|
+
if (cfg) {
|
|
391
|
+
config.save(GLOBAL_AW_DIR, {
|
|
392
|
+
...cfg,
|
|
393
|
+
namespace: skillNamespace || cfg.namespace || 'platform',
|
|
394
|
+
include: skillTargets,
|
|
395
|
+
});
|
|
381
396
|
}
|
|
382
397
|
} else if (isNewSubTeam) {
|
|
383
398
|
if (!silent) fmt.logStep(`Adding sub-team ${chalk.cyan(folderName)}...`);
|
|
@@ -470,7 +485,7 @@ export async function initCommand(args) {
|
|
|
470
485
|
: linkWorkspace(HOME, awDirForLinks, { silent: true });
|
|
471
486
|
const commands = isSkillInit ? 0 : generateCommands(HOME, { silent: true });
|
|
472
487
|
if (cwd !== HOME) installLocalCommitHook(cwd);
|
|
473
|
-
if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} ${isSkillInit ? '
|
|
488
|
+
if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} ${isSkillInit ? 'targeted symlinks' : 'symlinks'} · ${chalk.bold(commands)} commands`);
|
|
474
489
|
|
|
475
490
|
// Write hook manifest after all hook installation is complete
|
|
476
491
|
try { writeHookManifest({ eccVersion: AW_ECC_TAG, awVersion: VERSION }); } catch { /* best effort */ }
|
|
@@ -489,7 +504,7 @@ export async function initCommand(args) {
|
|
|
489
504
|
`⟁ ${isNewSubTeam ? `Sub-team ${chalk.cyan(folderName)} added` : 'Up to date'}`,
|
|
490
505
|
'',
|
|
491
506
|
` ${chalk.green('✓')} Registry synced`,
|
|
492
|
-
` ${chalk.green('✓')} IDE refreshed — ${chalk.bold(symlinks)} ${isSkillInit ? '
|
|
507
|
+
` ${chalk.green('✓')} IDE refreshed — ${chalk.bold(symlinks)} ${isSkillInit ? 'targeted symlinks' : 'symlinks'} · ${chalk.bold(commands)} commands`,
|
|
493
508
|
removedLegacyStartupFiles.length > 0
|
|
494
509
|
? ` ${chalk.green('✓')} Removed ${removedLegacyStartupFiles.length} legacy repo startup file${removedLegacyStartupFiles.length > 1 ? 's' : ''}`
|
|
495
510
|
: null,
|
|
@@ -524,14 +539,7 @@ export async function initCommand(args) {
|
|
|
524
539
|
|
|
525
540
|
// Determine sparse paths
|
|
526
541
|
const sparsePaths = isSkillInit
|
|
527
|
-
?
|
|
528
|
-
...skillTargets.map(target => `.aw_registry/${target}`),
|
|
529
|
-
DOCS_SOURCE_DIR,
|
|
530
|
-
AW_DOCS_DIR,
|
|
531
|
-
RULES_SOURCE_DIR,
|
|
532
|
-
`.aw_registry/AW-PROTOCOL.md`,
|
|
533
|
-
`CODEOWNERS`,
|
|
534
|
-
]
|
|
542
|
+
? skillInitSparsePaths(skillSpecs)
|
|
535
543
|
: [`.aw_registry/platform`, DOCS_SOURCE_DIR, AW_DOCS_DIR, RULES_SOURCE_DIR, `.aw_registry/AW-PROTOCOL.md`, `CODEOWNERS`];
|
|
536
544
|
if (!isSkillInit && folderName) {
|
|
537
545
|
sparsePaths.push(`.aw_registry/${folderName}`);
|
|
@@ -650,7 +658,7 @@ export async function initCommand(args) {
|
|
|
650
658
|
linkWorkspace(HOME, awDirForLinks, { silent: true }),
|
|
651
659
|
generateCommands(HOME, { silent: true }),
|
|
652
660
|
];
|
|
653
|
-
if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} ${isSkillInit ? '
|
|
661
|
+
if (!silent) fmt.logStep(`IDE wired — ${chalk.bold(symlinks)} ${isSkillInit ? 'targeted symlinks' : 'symlinks'} · ${chalk.bold(commands)} commands`);
|
|
654
662
|
|
|
655
663
|
// Write hook manifest after all hook installation is complete
|
|
656
664
|
try { writeHookManifest({ eccVersion: AW_ECC_TAG, awVersion: VERSION }); } catch { /* best effort */ }
|
package/ecc.mjs
CHANGED
|
@@ -12,7 +12,7 @@ import { applyStoredStartupPreferences } from "./startup.mjs";
|
|
|
12
12
|
|
|
13
13
|
const AW_ECC_REPO_SSH = "git@github.com:shreyansh-ghl/aw-ecc.git";
|
|
14
14
|
const AW_ECC_REPO_HTTPS = "https://github.com/shreyansh-ghl/aw-ecc.git";
|
|
15
|
-
export const AW_ECC_TAG = "v1.4.
|
|
15
|
+
export const AW_ECC_TAG = "v1.4.61";
|
|
16
16
|
|
|
17
17
|
const MARKETPLACE_NAME = "aw-marketplace";
|
|
18
18
|
const PLUGIN_KEY = `aw@${MARKETPLACE_NAME}`;
|
package/git.mjs
CHANGED
|
@@ -251,6 +251,19 @@ export function addToSparseCheckout(awHome, newPaths) {
|
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
/**
|
|
255
|
+
* Replace the current sparse checkout with an exact path set.
|
|
256
|
+
*/
|
|
257
|
+
export function setSparseCheckout(awHome, sparsePaths) {
|
|
258
|
+
try {
|
|
259
|
+
execSync('git sparse-checkout init --no-cone', { cwd: awHome, stdio: 'pipe' });
|
|
260
|
+
execSync(`git sparse-checkout set ${sparsePaths.map(p => `"${p}"`).join(' ')}`, { cwd: awHome, stdio: 'pipe' });
|
|
261
|
+
execSync(`git checkout ${REGISTRY_BASE_BRANCH}`, { cwd: awHome, stdio: 'pipe' });
|
|
262
|
+
} catch (e) {
|
|
263
|
+
throw new Error(`Failed to set sparse checkout: ${e.message}`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
254
267
|
/**
|
|
255
268
|
* Mirror the main clone's sparse-checkout paths into a project worktree.
|
|
256
269
|
* The worktree stays on its own branch — only the checked-out file set is updated.
|
package/link.mjs
CHANGED
|
@@ -160,11 +160,15 @@ function cleanSkillSymlinks(cwd) {
|
|
|
160
160
|
for (const ide of IDE_DIRS) {
|
|
161
161
|
const skillsDir = join(cwd, ide, 'skills');
|
|
162
162
|
if (existsSync(skillsDir)) cleanSymlinksRecursive(skillsDir);
|
|
163
|
+
const referencesDir = join(cwd, ide, 'references');
|
|
164
|
+
if (existsSync(referencesDir)) cleanSymlinksRecursive(referencesDir);
|
|
163
165
|
}
|
|
164
166
|
|
|
165
167
|
if (cwd === realHomeDir()) {
|
|
166
168
|
const agentsSkillsDir = join(cwd, '.agents', 'skills');
|
|
167
169
|
if (existsSync(agentsSkillsDir)) cleanSymlinksRecursive(agentsSkillsDir);
|
|
170
|
+
const agentsReferencesDir = join(cwd, '.agents', 'references');
|
|
171
|
+
if (existsSync(agentsReferencesDir)) cleanSymlinksRecursive(agentsReferencesDir);
|
|
168
172
|
}
|
|
169
173
|
}
|
|
170
174
|
|
|
@@ -196,6 +200,40 @@ function linkOneSkill(cwd, awDir, target) {
|
|
|
196
200
|
return created;
|
|
197
201
|
}
|
|
198
202
|
|
|
203
|
+
function linkReferenceFiles(cwd, awDir, namespaces = null) {
|
|
204
|
+
const allowedNamespaces = namespaces ? new Set(namespaces) : null;
|
|
205
|
+
const namespacesToLink = listNamespaceDirs(awDir)
|
|
206
|
+
.filter(ns => !allowedNamespaces || allowedNamespaces.has(ns));
|
|
207
|
+
let created = 0;
|
|
208
|
+
|
|
209
|
+
for (const ns of namespacesToLink) {
|
|
210
|
+
for (const { typeDirPath: referencesDir } of findNestedTypeDirs(join(awDir, ns), 'references')) {
|
|
211
|
+
for (const file of readdirSync(referencesDir).filter(f => !f.startsWith('.'))) {
|
|
212
|
+
const targetPath = join(referencesDir, file);
|
|
213
|
+
if (lstatSync(targetPath).isDirectory()) continue;
|
|
214
|
+
|
|
215
|
+
for (const ide of IDE_DIRS) {
|
|
216
|
+
const linkDir = join(cwd, ide, 'references');
|
|
217
|
+
mkdirSync(linkDir, { recursive: true });
|
|
218
|
+
const linkPath = join(linkDir, file);
|
|
219
|
+
const relTarget = relative(linkDir, targetPath);
|
|
220
|
+
try { forceSymlink(relTarget, linkPath); created++; } catch { /* best effort */ }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (cwd === realHomeDir()) {
|
|
224
|
+
const agentsReferencesDir = join(cwd, '.agents', 'references');
|
|
225
|
+
mkdirSync(agentsReferencesDir, { recursive: true });
|
|
226
|
+
const linkPath = join(agentsReferencesDir, file);
|
|
227
|
+
const relTarget = relative(agentsReferencesDir, targetPath);
|
|
228
|
+
try { forceSymlink(relTarget, linkPath); created++; } catch { /* best effort */ }
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return created;
|
|
235
|
+
}
|
|
236
|
+
|
|
199
237
|
/**
|
|
200
238
|
* Create/refresh symlinks for specific skills only.
|
|
201
239
|
*
|
|
@@ -228,9 +266,10 @@ export function linkSkills(cwd, skillTargets, awDirOverride = null, { silent = f
|
|
|
228
266
|
for (const target of targets) {
|
|
229
267
|
created += linkOneSkill(cwd, awDir, target);
|
|
230
268
|
}
|
|
269
|
+
created += linkReferenceFiles(cwd, awDir, targets.map(target => target.namespace));
|
|
231
270
|
|
|
232
271
|
if (created > 0 && !silent) {
|
|
233
|
-
fmt.logSuccess(`Linked ${created}
|
|
272
|
+
fmt.logSuccess(`Linked ${created} targeted symlink${created > 1 ? 's' : ''}`);
|
|
234
273
|
}
|
|
235
274
|
|
|
236
275
|
return created;
|
|
@@ -344,22 +383,7 @@ export function linkWorkspace(cwd, awDirOverride = null, { silent = false } = {}
|
|
|
344
383
|
|
|
345
384
|
// Shared references: flatten namespace references into each IDE's references/
|
|
346
385
|
// so links like ../../references/foo.md continue to work from flattened skill dirs.
|
|
347
|
-
|
|
348
|
-
for (const { typeDirPath: referencesDir } of findNestedTypeDirs(join(awDir, ns), 'references')) {
|
|
349
|
-
for (const file of readdirSync(referencesDir).filter(f => !f.startsWith('.'))) {
|
|
350
|
-
const targetPath = join(referencesDir, file);
|
|
351
|
-
if (lstatSync(targetPath).isDirectory()) continue;
|
|
352
|
-
|
|
353
|
-
for (const ide of IDE_DIRS) {
|
|
354
|
-
const linkDir = join(cwd, ide, 'references');
|
|
355
|
-
mkdirSync(linkDir, { recursive: true });
|
|
356
|
-
const linkPath = join(linkDir, file);
|
|
357
|
-
const relTarget = relative(linkDir, targetPath);
|
|
358
|
-
try { forceSymlink(relTarget, linkPath); created++; } catch { /* best effort */ }
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
}
|
|
386
|
+
created += linkReferenceFiles(cwd, awDir);
|
|
363
387
|
|
|
364
388
|
// Codex per-skill symlinks: ~/.agents/skills/<name> (global only)
|
|
365
389
|
if (cwd === realHomeDir()) {
|
|
@@ -376,20 +400,6 @@ export function linkWorkspace(cwd, awDirOverride = null, { silent = false } = {}
|
|
|
376
400
|
}
|
|
377
401
|
}
|
|
378
402
|
}
|
|
379
|
-
|
|
380
|
-
const agentsReferencesDir = join(cwd, '.agents', 'references');
|
|
381
|
-
for (const ns of namespaces) {
|
|
382
|
-
for (const { typeDirPath: referencesDir } of findNestedTypeDirs(join(awDir, ns), 'references')) {
|
|
383
|
-
mkdirSync(agentsReferencesDir, { recursive: true });
|
|
384
|
-
for (const file of readdirSync(referencesDir).filter(f => !f.startsWith('.'))) {
|
|
385
|
-
const targetPath = join(referencesDir, file);
|
|
386
|
-
if (lstatSync(targetPath).isDirectory()) continue;
|
|
387
|
-
const linkPath = join(agentsReferencesDir, file);
|
|
388
|
-
const relTarget = relative(agentsReferencesDir, targetPath);
|
|
389
|
-
try { forceSymlink(relTarget, linkPath); created++; } catch { /* best effort */ }
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
403
|
}
|
|
394
404
|
|
|
395
405
|
// Commands: per-file symlinks (recursive for nested domain dirs)
|