@ghl-ai/aw 0.1.58-beta.0 → 0.1.59
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/cli.mjs +2 -5
- package/commands/init.mjs +56 -13
- package/commands/integration.mjs +38 -77
- package/commands/integrations.mjs +84 -100
- package/commands/push.mjs +48 -20
- package/ecc.mjs +14 -3
- package/git.mjs +2 -0
- package/integrations/context-mode.mjs +312 -89
- package/integrations.mjs +153 -40
- package/package-manager.mjs +72 -0
- package/package.json +4 -3
- package/registry.mjs +27 -8
- package/update.mjs +29 -14
- package/integrations/index.mjs +0 -31
package/commands/push.mjs
CHANGED
|
@@ -662,6 +662,10 @@ async function publishProjectAwDocs(cwd, home, dryRun, scope = null) {
|
|
|
662
662
|
// Auto-generate a branch name from the files being pushed.
|
|
663
663
|
function generateBranchName(files, extraPaths = []) {
|
|
664
664
|
const shortId = Date.now().toString(36).slice(-5);
|
|
665
|
+
const branchSafe = (value) => String(value || '')
|
|
666
|
+
.replace(/\//g, '-')
|
|
667
|
+
.replace(/[^A-Za-z0-9._-]+/g, '-')
|
|
668
|
+
.replace(/^-+|-+$/g, '') || 'item';
|
|
665
669
|
|
|
666
670
|
if (files.length === 0 && extraPaths.length > 0) {
|
|
667
671
|
return `${managedBranchPrefix(extraPaths)}-${shortId}`;
|
|
@@ -675,8 +679,8 @@ function generateBranchName(files, extraPaths = []) {
|
|
|
675
679
|
|
|
676
680
|
if (files.length === 1) {
|
|
677
681
|
const f = files[0];
|
|
678
|
-
const nsSlug = f.namespace
|
|
679
|
-
return `${prefix}/${nsSlug}-${f.type}-${f.slug}-${shortId}`;
|
|
682
|
+
const nsSlug = branchSafe(f.namespace);
|
|
683
|
+
return `${prefix}/${nsSlug}-${f.type}-${branchSafe(f.slug)}-${shortId}`;
|
|
680
684
|
}
|
|
681
685
|
|
|
682
686
|
if (namespaces.length === 1) {
|
|
@@ -698,7 +702,7 @@ function singular(type, count) {
|
|
|
698
702
|
function parseCommitFiles(commits) {
|
|
699
703
|
const result = [];
|
|
700
704
|
for (const c of commits) {
|
|
701
|
-
const m = c.message.match(/registry:\s+(add|remove|sync)\s+(agents|skills|commands|evals)\/([\w
|
|
705
|
+
const m = c.message.match(/registry:\s+(add|remove|sync)\s+(agents|skills|commands|evals)\/([\w/-]+)\s+(?:to|from)\s+([\w/]+)/);
|
|
702
706
|
if (m) result.push({ verb: m[1], type: m[2], slug: m[3], namespace: m[4] });
|
|
703
707
|
}
|
|
704
708
|
return result;
|
|
@@ -900,13 +904,40 @@ function collectBatchFiles(folderAbsPath, registrySubDir) {
|
|
|
900
904
|
|
|
901
905
|
// ── Parse type/namespace/slug from a registry-relative path ──────────
|
|
902
906
|
|
|
903
|
-
function
|
|
907
|
+
function findSkillSlugParts(namespaceParts, skillParts, registrySubDir) {
|
|
908
|
+
if (skillParts.length === 0) return [];
|
|
909
|
+
|
|
910
|
+
if (registrySubDir) {
|
|
911
|
+
for (let i = skillParts.length; i > 0; i--) {
|
|
912
|
+
const candidate = join(registrySubDir, ...namespaceParts, 'skills', ...skillParts.slice(0, i));
|
|
913
|
+
if (existsSync(join(candidate, 'SKILL.md'))) return skillParts.slice(0, i);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
const skillMdIdx = skillParts.findIndex(part => part === 'SKILL' || part === 'SKILL.md');
|
|
918
|
+
if (skillMdIdx > 0) return skillParts.slice(0, skillMdIdx);
|
|
919
|
+
|
|
920
|
+
return [skillParts[0]];
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
function parseRegistryPath(relPath, registrySubDir = null) {
|
|
904
924
|
const parts = relPath.split('/');
|
|
905
925
|
for (let i = 0; i < parts.length; i++) {
|
|
906
926
|
if (PUSHABLE_TYPES.includes(parts[i]) && i + 1 < parts.length) {
|
|
927
|
+
const namespaceParts = parts.slice(0, i);
|
|
928
|
+
if (parts[i] === 'skills') {
|
|
929
|
+
const skillParts = parts.slice(i + 1).map(part => part.replace(/\.md$/, ''));
|
|
930
|
+
const slugParts = findSkillSlugParts(namespaceParts, skillParts, registrySubDir);
|
|
931
|
+
return {
|
|
932
|
+
type: parts[i],
|
|
933
|
+
namespace: namespaceParts.join('/'),
|
|
934
|
+
slug: slugParts.join('/'),
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
|
|
907
938
|
return {
|
|
908
939
|
type: parts[i],
|
|
909
|
-
namespace:
|
|
940
|
+
namespace: namespaceParts.join('/'),
|
|
910
941
|
slug: parts[i + 1].replace(/\.md$/, ''),
|
|
911
942
|
};
|
|
912
943
|
}
|
|
@@ -1198,7 +1229,7 @@ export async function pushCommand(args) {
|
|
|
1198
1229
|
|
|
1199
1230
|
if (staged.length > 0 || extraStaged.length > 0) {
|
|
1200
1231
|
const files = staged.map(f => {
|
|
1201
|
-
const meta = parseRegistryPath(f.registryPath);
|
|
1232
|
+
const meta = parseRegistryPath(f.registryPath, registrySubDir);
|
|
1202
1233
|
const parts = f.registryPath.split('/');
|
|
1203
1234
|
return {
|
|
1204
1235
|
absPath: join(awHome, f.path),
|
|
@@ -1264,7 +1295,7 @@ export async function pushCommand(args) {
|
|
|
1264
1295
|
|
|
1265
1296
|
const files = allEntries
|
|
1266
1297
|
.map(f => {
|
|
1267
|
-
const meta = parseRegistryPath(f.registryPath);
|
|
1298
|
+
const meta = parseRegistryPath(f.registryPath, registrySubDir);
|
|
1268
1299
|
const parts = f.registryPath.split('/');
|
|
1269
1300
|
return {
|
|
1270
1301
|
absPath: join(awHome, f.path),
|
|
@@ -1369,7 +1400,7 @@ export async function pushCommand(args) {
|
|
|
1369
1400
|
const deletedInFolder = folderChanges.deleted
|
|
1370
1401
|
.filter(e => !folderPrefix || e.registryPath.startsWith(folderPrefix))
|
|
1371
1402
|
.map(e => {
|
|
1372
|
-
const meta = parseRegistryPath(e.registryPath);
|
|
1403
|
+
const meta = parseRegistryPath(e.registryPath, registrySubDir);
|
|
1373
1404
|
const parts = e.registryPath.split('/');
|
|
1374
1405
|
return {
|
|
1375
1406
|
absPath: join(awHome, e.path),
|
|
@@ -1396,13 +1427,8 @@ export async function pushCommand(args) {
|
|
|
1396
1427
|
}
|
|
1397
1428
|
|
|
1398
1429
|
// Single file input
|
|
1399
|
-
const
|
|
1400
|
-
|
|
1401
|
-
for (let i = regParts.length - 1; i >= 0; i--) {
|
|
1402
|
-
if (PUSHABLE_TYPES.includes(regParts[i])) { typeIdx = i; break; }
|
|
1403
|
-
}
|
|
1404
|
-
|
|
1405
|
-
if (typeIdx === -1 || typeIdx + 1 >= regParts.length) {
|
|
1430
|
+
const meta = parseRegistryPath(resolved.registryPath, registrySubDir);
|
|
1431
|
+
if (!meta?.type || !meta.slug) {
|
|
1406
1432
|
fmt.cancel([
|
|
1407
1433
|
`Invalid push path: ${chalk.red(resolved.registryPath)}`,
|
|
1408
1434
|
'',
|
|
@@ -1416,14 +1442,16 @@ export async function pushCommand(args) {
|
|
|
1416
1442
|
return;
|
|
1417
1443
|
}
|
|
1418
1444
|
|
|
1419
|
-
const
|
|
1420
|
-
const
|
|
1421
|
-
const
|
|
1422
|
-
const namespacePath = namespaceParts.join('/');
|
|
1445
|
+
const parentDir = meta.type;
|
|
1446
|
+
const slug = meta.slug;
|
|
1447
|
+
const namespacePath = meta.namespace;
|
|
1423
1448
|
const isDir = !isDeletedFile && statSync(absPath).isDirectory();
|
|
1449
|
+
const registryPathWithExt = resolved.registryPath.endsWith('.md')
|
|
1450
|
+
? resolved.registryPath
|
|
1451
|
+
: `${resolved.registryPath}.md`;
|
|
1424
1452
|
const registryTarget = isDir
|
|
1425
1453
|
? `${REGISTRY_DIR}/${namespacePath}/${parentDir}/${slug}`
|
|
1426
|
-
: `${REGISTRY_DIR}/${
|
|
1454
|
+
: `${REGISTRY_DIR}/${registryPathWithExt}`;
|
|
1427
1455
|
|
|
1428
1456
|
// Check if the file actually has changes before trying to commit
|
|
1429
1457
|
const singleFileChanges = detectChanges(awHome, REGISTRY_DIR);
|
package/ecc.mjs
CHANGED
|
@@ -12,7 +12,12 @@ 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.63";
|
|
16
|
+
const REQUIRED_ECC_FILES = [
|
|
17
|
+
"package.json",
|
|
18
|
+
"scripts/install-apply.js",
|
|
19
|
+
"scripts/sync-ecc-to-codex.sh",
|
|
20
|
+
];
|
|
16
21
|
|
|
17
22
|
const MARKETPLACE_NAME = "aw-marketplace";
|
|
18
23
|
const PLUGIN_KEY = `aw@${MARKETPLACE_NAME}`;
|
|
@@ -85,11 +90,15 @@ async function cloneWithRefAsync(url, ref, dest) {
|
|
|
85
90
|
}
|
|
86
91
|
}
|
|
87
92
|
|
|
93
|
+
function hasRequiredEccFiles(dest) {
|
|
94
|
+
return REQUIRED_ECC_FILES.every((relPath) => existsSync(join(dest, relPath)));
|
|
95
|
+
}
|
|
96
|
+
|
|
88
97
|
async function cloneOrUpdateAsync(tag, dest) {
|
|
89
98
|
const overrideUrl = process.env.AW_ECC_CLONE_URL;
|
|
90
99
|
const overrideRef = process.env.AW_ECC_CLONE_REF?.trim();
|
|
91
100
|
|
|
92
|
-
if (existsSync(join(dest, ".git"))) {
|
|
101
|
+
if (existsSync(join(dest, ".git")) && hasRequiredEccFiles(dest)) {
|
|
93
102
|
try {
|
|
94
103
|
if (!overrideUrl && !overrideRef) {
|
|
95
104
|
await runA(`git -C ${dest} fetch --quiet --depth 1 origin tag ${tag}`);
|
|
@@ -102,6 +111,7 @@ async function cloneOrUpdateAsync(tag, dest) {
|
|
|
102
111
|
}
|
|
103
112
|
// Restore working tree — pruneStaleHooks may have deleted tracked files
|
|
104
113
|
await runA(`git -C ${dest} checkout -- .`);
|
|
114
|
+
if (!hasRequiredEccFiles(dest)) throw new Error("aw-ecc checkout is missing required files");
|
|
105
115
|
return;
|
|
106
116
|
} catch { /* fall through to fresh clone */ }
|
|
107
117
|
}
|
|
@@ -188,7 +198,7 @@ function cloneOrUpdate(tag, dest) {
|
|
|
188
198
|
// AW_ECC_CLONE_REF lets aw init install ECC from a non-default branch or tag.
|
|
189
199
|
const overrideRef = process.env.AW_ECC_CLONE_REF?.trim();
|
|
190
200
|
|
|
191
|
-
if (existsSync(join(dest, ".git"))) {
|
|
201
|
+
if (existsSync(join(dest, ".git")) && hasRequiredEccFiles(dest)) {
|
|
192
202
|
try {
|
|
193
203
|
if (!overrideUrl && !overrideRef) {
|
|
194
204
|
run(`git -C ${dest} fetch --quiet --depth 1 origin tag ${tag}`);
|
|
@@ -201,6 +211,7 @@ function cloneOrUpdate(tag, dest) {
|
|
|
201
211
|
}
|
|
202
212
|
// Restore working tree — pruneStaleHooks may have deleted tracked files
|
|
203
213
|
run(`git -C ${dest} checkout -- .`);
|
|
214
|
+
if (!hasRequiredEccFiles(dest)) throw new Error("aw-ecc checkout is missing required files");
|
|
204
215
|
return;
|
|
205
216
|
} catch { /* fall through to fresh clone */ }
|
|
206
217
|
}
|
package/git.mjs
CHANGED
|
@@ -453,6 +453,7 @@ export function detectChanges(awHome, registryDir) {
|
|
|
453
453
|
if (!line || line.length < 3) continue;
|
|
454
454
|
const xy = line.slice(0, 2);
|
|
455
455
|
const filePath = line.slice(3).trim();
|
|
456
|
+
if (filePath === `${registryDir}/.aw-upgrade.log`) continue;
|
|
456
457
|
const registryPath = filePath.startsWith(registryDir + '/') ? filePath.slice(registryDir.length + 1) : filePath;
|
|
457
458
|
const entry = { path: filePath, registryPath };
|
|
458
459
|
|
|
@@ -485,6 +486,7 @@ export function getStagedFiles(awHome, registryDir) {
|
|
|
485
486
|
if (!line) continue;
|
|
486
487
|
const [status, filePath] = line.split('\t');
|
|
487
488
|
if (!filePath?.startsWith(registryDir + '/')) continue;
|
|
489
|
+
if (filePath === `${registryDir}/.aw-upgrade.log`) continue;
|
|
488
490
|
result.push({
|
|
489
491
|
path: filePath,
|
|
490
492
|
registryPath: filePath.slice(registryDir.length + 1),
|