@rbbtsn0w/adg 0.2.1 → 0.3.0-beta.2
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/README.md +6 -0
- package/dist/bin/adg.js +121 -65
- package/dist/src/adapters/antigravity.js +18 -0
- package/dist/src/adapters/index.js +20 -2
- package/dist/src/agents/antigravity.js +185 -0
- package/dist/src/agents/index.js +3 -1
- package/dist/src/agents/registry.js +12 -0
- package/dist/src/commands/install.js +3 -2
- package/dist/src/commands/update.js +6 -3
- package/dist/src/package.js +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -361,6 +361,12 @@ Debugging tips:
|
|
|
361
361
|
- GitHub clone/sparse logic is injectable (`gitRunner`) and covered offline by
|
|
362
362
|
the test suite; live network clones are exercised by `import owner/repo`.
|
|
363
363
|
|
|
364
|
+
## Contributing
|
|
365
|
+
|
|
366
|
+
All feature/fix pull requests target the **`beta`** integration branch; `main`
|
|
367
|
+
is reserved for stable releases. See [CONTRIBUTING.md](CONTRIBUTING.md) and
|
|
368
|
+
[docs/branching-and-release.md](docs/branching-and-release.md).
|
|
369
|
+
|
|
364
370
|
## License
|
|
365
371
|
|
|
366
372
|
MIT
|
package/dist/bin/adg.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { parseArgs } from "node:util";
|
|
3
|
+
import pc from "picocolors";
|
|
3
4
|
import { spawnSync } from "node:child_process";
|
|
4
5
|
import { readFileSync, realpathSync } from "node:fs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
5
7
|
import { dirname, join, resolve } from "node:path";
|
|
6
8
|
import { fileURLToPath } from "node:url";
|
|
7
9
|
import { checkForUpdate, formatUpdateNotice } from "../src/update-check.js";
|
|
@@ -21,9 +23,24 @@ import { selectTargetsInteractive } from "../src/commands/select-agents.js";
|
|
|
21
23
|
import { selectPluginsInteractive } from "../src/commands/select-plugins.js";
|
|
22
24
|
import { selectScopeInteractive } from "../src/commands/select-scope.js";
|
|
23
25
|
import { confirmFullInstall, selectComponentsInteractive } from "../src/commands/select-components.js";
|
|
24
|
-
import { globalPluginsDir, projectPluginsDir } from "../src/paths.js";
|
|
26
|
+
import { globalPluginsDir, installedPluginDir, projectPluginsDir } from "../src/paths.js";
|
|
25
27
|
import { COMPONENT_TYPES } from "../src/types.js";
|
|
26
|
-
import { getAgent } from "../src/agents/index.js";
|
|
28
|
+
import { agentsForComponents, getAgent } from "../src/agents/index.js";
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Semantic colors, mirroring `adg skills list` so output reads the same across
|
|
31
|
+
// commands: cyan = primary identifiers (plugins, agents, sources), dim =
|
|
32
|
+
// secondary metadata (paths, hashes, sub-details), green = success, yellow =
|
|
33
|
+
// notes/warnings, red = errors, bold = section titles. picocolors auto-disables
|
|
34
|
+
// on non-TTY / NO_COLOR, so piped output and tests stay plain.
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
const ui = {
|
|
37
|
+
title: (s) => pc.bold(s),
|
|
38
|
+
name: (s) => pc.cyan(s),
|
|
39
|
+
meta: (s) => pc.dim(s),
|
|
40
|
+
ok: (s) => pc.green(s),
|
|
41
|
+
warn: (s) => pc.yellow(s),
|
|
42
|
+
err: (s) => pc.red(s),
|
|
43
|
+
};
|
|
27
44
|
const FLAGS = {
|
|
28
45
|
// Short flags are first-letter aliases. Where several long flags share a
|
|
29
46
|
// first letter, the highest-frequency one wins the short and the rest stay
|
|
@@ -32,7 +49,7 @@ const FLAGS = {
|
|
|
32
49
|
dir: { type: "string", short: "d", hint: "<dir>", help: "install into an explicit directory" },
|
|
33
50
|
global: { type: "boolean", short: "g", help: "use ~/.agents/plugins (across all projects)" },
|
|
34
51
|
project: { type: "boolean", help: "use <repo>/.agents/plugins (default)" },
|
|
35
|
-
target: { type: "string", short: "t", hint: "claude|codex|all", help: "runtime(s) to adapt for" },
|
|
52
|
+
target: { type: "string", short: "t", hint: "claude|codex|antigravity|all", help: "runtime(s) to adapt for" },
|
|
36
53
|
all: { type: "boolean", short: "a", help: "select all available plugins" },
|
|
37
54
|
plugin: { type: "string", short: "p", multiple: true, hint: "<name>", help: "select a specific plugin (repeatable)" },
|
|
38
55
|
"no-deps": { type: "boolean", short: "n", help: "don't install dependencies" },
|
|
@@ -120,7 +137,7 @@ const PLUGIN_COMMANDS = {
|
|
|
120
137
|
},
|
|
121
138
|
link: {
|
|
122
139
|
summary: "link installed plugins into a runtime",
|
|
123
|
-
synopsis: "adg plugins link --target claude|codex",
|
|
140
|
+
synopsis: "adg plugins link --target claude|codex|antigravity",
|
|
124
141
|
flags: ["target", ...SCOPE],
|
|
125
142
|
},
|
|
126
143
|
migrate: {
|
|
@@ -208,7 +225,7 @@ function wantsHelp(args) {
|
|
|
208
225
|
return args.includes("-h") || args.includes("--help");
|
|
209
226
|
}
|
|
210
227
|
function fail(msg) {
|
|
211
|
-
console.error(
|
|
228
|
+
console.error(`${ui.err("error:")} ${msg}\n`);
|
|
212
229
|
console.error(TOP_USAGE);
|
|
213
230
|
process.exit(1);
|
|
214
231
|
}
|
|
@@ -231,17 +248,25 @@ function reportAgents(agents, verb) {
|
|
|
231
248
|
for (const r of agents ?? []) {
|
|
232
249
|
const name = getAgent(r.agent)?.displayName ?? r.agent;
|
|
233
250
|
if (r.affected.length > 0)
|
|
234
|
-
console.log(`${verb} in ${name}: ${r.affected.join(", ")}`);
|
|
251
|
+
console.log(`${ui.ok(verb)} in ${ui.name(name)}: ${r.affected.join(", ")}`);
|
|
235
252
|
else if (r.skipped)
|
|
236
|
-
console.log(`note: \`${r.agent}\` CLI not found — run \`adg plugins link --target ${r.agent}\` after installing it.`);
|
|
253
|
+
console.log(ui.warn(`note: \`${r.agent}\` CLI not found — run \`adg plugins link --target ${r.agent}\` after installing it.`));
|
|
237
254
|
}
|
|
238
255
|
}
|
|
256
|
+
/** Friendly `--target` aliases mapped onto canonical adapter target ids. */
|
|
257
|
+
const TARGET_ALIASES = {
|
|
258
|
+
anthropic: "claude",
|
|
259
|
+
openai: "codex",
|
|
260
|
+
agy: "antigravity",
|
|
261
|
+
gemini: "antigravity",
|
|
262
|
+
};
|
|
239
263
|
function resolveTargets(target) {
|
|
240
264
|
if (!target || target === "all")
|
|
241
265
|
return [...ADAPTER_TARGETS];
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
266
|
+
const t = TARGET_ALIASES[target] ?? target;
|
|
267
|
+
if (ADAPTER_TARGETS.includes(t))
|
|
268
|
+
return [t];
|
|
269
|
+
fail(`invalid --target "${target}" (expected ${[...ADAPTER_TARGETS, "all"].join("|")})`);
|
|
245
270
|
}
|
|
246
271
|
/** Parse a `--only skills,commands` list into validated component types. */
|
|
247
272
|
function resolveComponents(only) {
|
|
@@ -264,7 +289,7 @@ function parseVerb(name, flags, rest) {
|
|
|
264
289
|
return { values: values, positionals };
|
|
265
290
|
}
|
|
266
291
|
catch (err) {
|
|
267
|
-
console.error(
|
|
292
|
+
console.error(`${ui.err("error:")} ${err instanceof Error ? err.message : String(err)}\n`);
|
|
268
293
|
console.error(renderVerbHelp(name));
|
|
269
294
|
process.exit(1);
|
|
270
295
|
}
|
|
@@ -290,12 +315,21 @@ function formatColumns(items, opts = {}) {
|
|
|
290
315
|
}
|
|
291
316
|
return lines.join("\n");
|
|
292
317
|
}
|
|
318
|
+
/** Abbreviate the home-directory prefix of an absolute path to `~` (POSIX `/` or Windows `\`). */
|
|
319
|
+
function abbrevHome(p) {
|
|
320
|
+
const home = homedir();
|
|
321
|
+
if (p === home)
|
|
322
|
+
return "~";
|
|
323
|
+
if (p.startsWith(home + "/") || p.startsWith(home + "\\"))
|
|
324
|
+
return "~" + p.slice(home.length);
|
|
325
|
+
return p;
|
|
326
|
+
}
|
|
293
327
|
/** Print a plugin's components, each expanded to its member names (verbose view). */
|
|
294
328
|
function printContents(contents, headerIndent) {
|
|
295
329
|
const entries = Object.entries(contents ?? {}).filter(([, names]) => names.length > 0);
|
|
296
330
|
for (const [type, names] of entries) {
|
|
297
331
|
const maxColWidth = Math.max(1, ...names.map((n) => n.length));
|
|
298
|
-
console.log(`${" ".repeat(headerIndent)}${type} (${names.length}):`);
|
|
332
|
+
console.log(`${" ".repeat(headerIndent)}${ui.name(type)} ${ui.meta(`(${names.length}):`)}`);
|
|
299
333
|
console.log(formatColumns(names, { indent: headerIndent + 2, maxColWidth }));
|
|
300
334
|
}
|
|
301
335
|
}
|
|
@@ -308,7 +342,7 @@ async function runPlugins(rawVerb, rest) {
|
|
|
308
342
|
const verb = PLUGIN_ALIASES[rawVerb] ?? rawVerb;
|
|
309
343
|
const cmd = PLUGIN_COMMANDS[verb];
|
|
310
344
|
if (!cmd) {
|
|
311
|
-
console.error(
|
|
345
|
+
console.error(`${ui.err("error:")} unknown plugins subcommand: ${rawVerb}\n`);
|
|
312
346
|
console.error(renderPluginsHelp());
|
|
313
347
|
process.exit(1);
|
|
314
348
|
}
|
|
@@ -330,16 +364,16 @@ async function runPlugins(rawVerb, rest) {
|
|
|
330
364
|
fail(`invalid --type "${values.type}" (expected plugin|marketplace|all)`);
|
|
331
365
|
}
|
|
332
366
|
const res = initScaffold({ name, dir, type, description: values.description, author: values.author, skill: values.skill?.[0] });
|
|
333
|
-
console.log(`created ${type} at ${res.pluginDir}`);
|
|
367
|
+
console.log(`${ui.ok(`created ${type}`)} at ${ui.name(res.pluginDir)}`);
|
|
334
368
|
for (const f of res.created)
|
|
335
|
-
console.log(` + ${f}`);
|
|
369
|
+
console.log(ui.meta(` + ${f}`));
|
|
336
370
|
return;
|
|
337
371
|
}
|
|
338
372
|
case "adapt": {
|
|
339
373
|
const { values, positionals } = parseVerb(verb, cmd.flags, rest);
|
|
340
374
|
const pluginDir = resolve(positionals[0] ?? process.cwd());
|
|
341
375
|
for (const r of adaptPlugin(pluginDir, resolveTargets(values.target))) {
|
|
342
|
-
console.log(
|
|
376
|
+
console.log(`${ui.ok("adapted")} ${ui.name(r.target)} ${ui.meta(`-> ${r.file}`)}`);
|
|
343
377
|
}
|
|
344
378
|
return;
|
|
345
379
|
}
|
|
@@ -348,12 +382,12 @@ async function runPlugins(rawVerb, rest) {
|
|
|
348
382
|
const pluginDir = resolve(positionals[0] ?? process.cwd());
|
|
349
383
|
const res = validatePlugin(pluginDir);
|
|
350
384
|
if (res.ok) {
|
|
351
|
-
console.log(
|
|
385
|
+
console.log(`${ui.ok("ok:")} ${ui.name(pluginDir)} is a valid ADG plugin`);
|
|
352
386
|
}
|
|
353
387
|
else {
|
|
354
|
-
console.error(
|
|
388
|
+
console.error(`${ui.err("invalid:")} ${ui.name(pluginDir)}`);
|
|
355
389
|
for (const i of res.issues)
|
|
356
|
-
console.error(` - ${i}`);
|
|
390
|
+
console.error(ui.warn(` - ${i}`));
|
|
357
391
|
process.exit(1);
|
|
358
392
|
}
|
|
359
393
|
return;
|
|
@@ -404,14 +438,14 @@ async function runPlugins(rawVerb, rest) {
|
|
|
404
438
|
scope: global ? "user" : "project",
|
|
405
439
|
});
|
|
406
440
|
for (const name of converted)
|
|
407
|
-
console.log(`converted native manifest -> .agents/.plugin.json: ${name}`);
|
|
441
|
+
console.log(ui.meta(`converted native manifest -> .agents/.plugin.json: ${name}`));
|
|
408
442
|
if (order.length > 1)
|
|
409
|
-
console.log(`install order: ${order.join(" -> ")}`);
|
|
443
|
+
console.log(ui.meta(`install order: ${order.join(" -> ")}`));
|
|
410
444
|
for (const res of installed) {
|
|
411
|
-
console.log(
|
|
412
|
-
console.log(` folderHash: ${res.folderHash}`);
|
|
445
|
+
console.log(`${ui.ok("added")} ${ui.name(res.name)} ${ui.meta(`-> ${res.installedTo}`)}`);
|
|
446
|
+
console.log(ui.meta(` folderHash: ${res.folderHash}`));
|
|
413
447
|
for (const f of res.adapted)
|
|
414
|
-
console.log(` adapted: ${f}`);
|
|
448
|
+
console.log(ui.meta(` adapted: ${f}`));
|
|
415
449
|
}
|
|
416
450
|
reportAgents(agents, "enabled");
|
|
417
451
|
return;
|
|
@@ -430,22 +464,23 @@ async function runPlugins(rawVerb, rest) {
|
|
|
430
464
|
pluginsDir: resolveScopeDir(values),
|
|
431
465
|
description: values.description,
|
|
432
466
|
});
|
|
433
|
-
console.log(
|
|
467
|
+
console.log(`${ui.ok("imported skills into")} ${ui.name(res.name)} ${ui.meta(`-> ${res.installedTo}`)}`);
|
|
434
468
|
return;
|
|
435
469
|
}
|
|
436
470
|
case "link": {
|
|
437
471
|
const { values } = parseVerb(verb, cmd.flags, rest);
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
472
|
+
if (values.target === undefined || values.target === "all") {
|
|
473
|
+
fail(`plugins link requires a single --target (${ADAPTER_TARGETS.join("|")})`);
|
|
474
|
+
}
|
|
475
|
+
const target = resolveTargets(values.target)[0]; // validates + maps aliases (agy → antigravity); always non-empty
|
|
441
476
|
const res = linkPlugins({ pluginsDir: resolveScopeDir(values), target, global: Boolean(values.global) });
|
|
442
477
|
for (const a of res.actions) {
|
|
443
|
-
console.log(
|
|
478
|
+
console.log(`${ui.ok("linked")} ${ui.name(a.name)} ${ui.meta(`[${res.target}]`)}${a.linkedTo ? ui.meta(` -> ${a.linkedTo}`) : ""}`);
|
|
444
479
|
for (const f of a.adapted)
|
|
445
|
-
console.log(` adapted: ${f}`);
|
|
480
|
+
console.log(ui.meta(` adapted: ${f}`));
|
|
446
481
|
}
|
|
447
482
|
if (res.cliSkipped) {
|
|
448
|
-
console.log(`note: \`${target}\` CLI not found — manifests were generated, but nothing was enabled in ${target}.`);
|
|
483
|
+
console.log(ui.warn(`note: \`${target}\` CLI not found — manifests were generated, but nothing was enabled in ${target}.`));
|
|
449
484
|
}
|
|
450
485
|
return;
|
|
451
486
|
}
|
|
@@ -456,9 +491,9 @@ async function runPlugins(rawVerb, rest) {
|
|
|
456
491
|
scope: scopeOf(values),
|
|
457
492
|
});
|
|
458
493
|
for (const r of results)
|
|
459
|
-
console.log(`${r.changed ? "updated" : "unchanged"} ${r.name}@${r.version}`);
|
|
494
|
+
console.log(`${r.changed ? ui.ok("updated") : ui.meta("unchanged")} ${ui.name(`${r.name}@${r.version}`)}`);
|
|
460
495
|
for (const m of missing)
|
|
461
|
-
console.error(` ! missing directory for locked plugin: ${m}`);
|
|
496
|
+
console.error(ui.warn(` ! missing directory for locked plugin: ${m}`));
|
|
462
497
|
reportAgents(agents, "re-synced");
|
|
463
498
|
return;
|
|
464
499
|
}
|
|
@@ -475,17 +510,17 @@ async function runPlugins(rawVerb, rest) {
|
|
|
475
510
|
scope: scopeOf(values),
|
|
476
511
|
});
|
|
477
512
|
if (res.removedDir)
|
|
478
|
-
console.log(
|
|
513
|
+
console.log(`${ui.ok("removed")} ${ui.name(res.name)} ${ui.meta(`-> ${res.removedDir}`)}`);
|
|
479
514
|
else
|
|
480
|
-
console.log(
|
|
515
|
+
console.log(`${ui.ok("removed")} ${ui.name(res.name)} ${ui.meta("(no directory on disk)")}`);
|
|
481
516
|
for (const link of res.unlinked)
|
|
482
|
-
console.log(` unlinked: ${link}`);
|
|
517
|
+
console.log(ui.meta(` unlinked: ${link}`));
|
|
483
518
|
for (const r of res.agents ?? []) {
|
|
484
519
|
if (r.affected.length > 0)
|
|
485
|
-
console.log(` disabled in ${getAgent(r.agent)?.displayName ?? r.agent}`);
|
|
520
|
+
console.log(ui.meta(` disabled in ${getAgent(r.agent)?.displayName ?? r.agent}`));
|
|
486
521
|
}
|
|
487
522
|
if (!res.removedFromLock && !res.removedDir) {
|
|
488
|
-
console.log(` ${res.name} was not recorded in the lock`);
|
|
523
|
+
console.log(ui.warn(` ${res.name} was not recorded in the lock`));
|
|
489
524
|
}
|
|
490
525
|
return;
|
|
491
526
|
}
|
|
@@ -494,21 +529,42 @@ async function runPlugins(rawVerb, rest) {
|
|
|
494
529
|
const pluginsDir = resolveScopeDir(values);
|
|
495
530
|
const plugins = listPlugins(pluginsDir);
|
|
496
531
|
if (plugins.length === 0) {
|
|
497
|
-
console.log(`no plugins recorded in ${pluginsDir}`);
|
|
532
|
+
console.log(ui.meta(`no plugins recorded in ${pluginsDir}`));
|
|
498
533
|
return;
|
|
499
534
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
535
|
+
// Pre-compute each plugin's display row so the name/path columns can be
|
|
536
|
+
// aligned across rows (à la `adg skills list`). The `Agents:` column is
|
|
537
|
+
// derived from the exposed component types — which agents can adapt it.
|
|
538
|
+
const PATH_MAX = 44;
|
|
539
|
+
const rows = plugins.map((p) => {
|
|
540
|
+
const exposed = Object.entries(p.contents ?? {}).filter(([, names]) => names.length > 0);
|
|
541
|
+
const types = exposed.map(([type]) => type);
|
|
542
|
+
const agents = agentsForComponents(types).map((a) => a.displayName);
|
|
543
|
+
return {
|
|
544
|
+
p,
|
|
545
|
+
label: `${p.name}@${p.version}`,
|
|
546
|
+
path: abbrevHome(installedPluginDir(pluginsDir, p.name, p.origin)),
|
|
547
|
+
agents: agents.length > 0 ? agents.join(", ") : "—",
|
|
548
|
+
counts: exposed.map(([type, names]) => `${type}: ${names.length}`),
|
|
549
|
+
};
|
|
550
|
+
});
|
|
551
|
+
const nameW = Math.max(...rows.map((r) => r.label.length));
|
|
552
|
+
const pathW = Math.min(PATH_MAX, Math.max(...rows.map((r) => r.path.length)));
|
|
553
|
+
const ellip = (s, w) => (s.length > w ? "…" + s.slice(s.length - w + 1) : s);
|
|
554
|
+
// Color mirrors `adg skills list`: cyan name, dim path / dim "Agents:"
|
|
555
|
+
// label with the agent names left bright, and the provenance/counts line
|
|
556
|
+
// fully dimmed as secondary metadata. Widths are measured on the uncolored
|
|
557
|
+
// strings (above), so wrapping the padded text keeps columns aligned.
|
|
558
|
+
// picocolors auto-disables on non-TTY / NO_COLOR, so pipes stay plain.
|
|
559
|
+
for (const r of rows) {
|
|
560
|
+
const partial = r.p.selection ? " (partial)" : "";
|
|
561
|
+
const name = ui.name(r.label.padEnd(nameW));
|
|
562
|
+
const path = ui.meta(ellip(r.path, pathW).padEnd(pathW));
|
|
563
|
+
console.log(`${name} ${path} ${ui.meta("Agents:")} ${r.agents}`);
|
|
564
|
+
const provenance = `[${r.p.origin.type}] ${r.p.folderHash.slice(0, 19)}${partial}`;
|
|
565
|
+
console.log(ui.meta(` ${[provenance, ...r.counts].join(" ")}`));
|
|
566
|
+
if (values.verbose)
|
|
567
|
+
printContents(r.p.contents, 4);
|
|
512
568
|
}
|
|
513
569
|
return;
|
|
514
570
|
}
|
|
@@ -516,11 +572,11 @@ async function runPlugins(rawVerb, rest) {
|
|
|
516
572
|
const { values } = parseVerb(verb, cmd.flags, rest);
|
|
517
573
|
const res = migrateLayout(resolveScopeDir(values));
|
|
518
574
|
for (const m of res.moved)
|
|
519
|
-
console.log(
|
|
575
|
+
console.log(`${ui.ok("moved")} ${ui.name(m.name)}: ${ui.meta(`${m.from} -> ${m.to}`)}`);
|
|
520
576
|
for (const m of res.missing)
|
|
521
|
-
console.error(` ! missing directory for locked plugin: ${m}`);
|
|
577
|
+
console.error(ui.warn(` ! missing directory for locked plugin: ${m}`));
|
|
522
578
|
if (res.moved.length === 0)
|
|
523
|
-
console.log(`nothing to migrate (${res.unchanged.length} already in place)`);
|
|
579
|
+
console.log(ui.meta(`nothing to migrate (${res.unchanged.length} already in place)`));
|
|
524
580
|
return;
|
|
525
581
|
}
|
|
526
582
|
case "marketplace":
|
|
@@ -537,7 +593,7 @@ Commands:
|
|
|
537
593
|
adg plugins marketplace list [--verbose] [--global | --project | --dir <dir>]
|
|
538
594
|
Group installed plugins by source. --verbose expands each plugin to its
|
|
539
595
|
components (skills, agents, commands, …).
|
|
540
|
-
adg plugins marketplace upgrade [<source>] [--all] [--target claude|codex|all] [--global | --project | --dir <dir>]
|
|
596
|
+
adg plugins marketplace upgrade [<source>] [--all] [--target claude|codex|antigravity|all] [--global | --project | --dir <dir>]
|
|
541
597
|
Re-fetch a source and update its installed plugins (--all also installs
|
|
542
598
|
anything new it now offers). No <source> upgrades every remote source.
|
|
543
599
|
adg plugins marketplace remove <source> [--force] [--global | --project | --dir <dir>]
|
|
@@ -563,7 +619,7 @@ async function runMarketplace(args) {
|
|
|
563
619
|
const dir = resolveScopeDir(values);
|
|
564
620
|
const groups = marketplaceList({ pluginsDir: dir });
|
|
565
621
|
if (groups.length === 0) {
|
|
566
|
-
console.log("No plugins installed.");
|
|
622
|
+
console.log(ui.meta("No plugins installed."));
|
|
567
623
|
return;
|
|
568
624
|
}
|
|
569
625
|
// Verbose: drill each plugin down to its components (reuses `plugins list -v`).
|
|
@@ -571,12 +627,12 @@ async function runMarketplace(args) {
|
|
|
571
627
|
for (const g of groups) {
|
|
572
628
|
const ref = g.ref ? `@${g.ref}` : "";
|
|
573
629
|
const n = g.installed.length;
|
|
574
|
-
const tag = g.remote ? "" : " (local — re-run add to update)";
|
|
575
|
-
console.log(`${g.source}${ref} (${n} plugin${n !== 1 ? "s" : ""})${tag}`);
|
|
630
|
+
const tag = g.remote ? "" : ui.warn(" (local — re-run add to update)");
|
|
631
|
+
console.log(`${ui.name(`${g.source}${ref}`)} ${ui.meta(`(${n} plugin${n !== 1 ? "s" : ""})`)}${tag}`);
|
|
576
632
|
if (byName) {
|
|
577
633
|
for (const name of g.installed) {
|
|
578
634
|
const p = byName.get(name);
|
|
579
|
-
console.log(` ${name}${p?.selection ? " (partial)" : ""}`);
|
|
635
|
+
console.log(` ${ui.name(name)}${p?.selection ? ui.meta(" (partial)") : ""}`);
|
|
580
636
|
printContents(p?.contents, 4);
|
|
581
637
|
}
|
|
582
638
|
}
|
|
@@ -599,11 +655,11 @@ async function runMarketplace(args) {
|
|
|
599
655
|
});
|
|
600
656
|
for (const r of results) {
|
|
601
657
|
const conv = r.converted.length ? ` (${r.converted.length} converted from native)` : "";
|
|
602
|
-
console.log(
|
|
658
|
+
console.log(`${ui.ok("upgraded")} ${ui.name(r.source)}: ${r.updated.length} plugin(s)${ui.meta(conv)}`);
|
|
603
659
|
for (const p of r.updated)
|
|
604
|
-
console.log(` ${p.name}
|
|
660
|
+
console.log(` ${ui.name(p.name)} ${ui.meta(`-> ${p.installedTo}`)}`);
|
|
605
661
|
if (r.available.length > 0) {
|
|
606
|
-
console.log(` ${r.available.length} more available (use --all): ${r.available.join(", ")}`);
|
|
662
|
+
console.log(ui.meta(` ${r.available.length} more available (use --all): ${r.available.join(", ")}`));
|
|
607
663
|
}
|
|
608
664
|
}
|
|
609
665
|
return;
|
|
@@ -622,11 +678,11 @@ async function runMarketplace(args) {
|
|
|
622
678
|
force: values.force,
|
|
623
679
|
deactivate: true,
|
|
624
680
|
});
|
|
625
|
-
console.log(
|
|
681
|
+
console.log(`${ui.ok("removed")} ${res.removed.length} plugin(s) from ${ui.name(res.source)}: ${res.removed.join(", ")}`);
|
|
626
682
|
return;
|
|
627
683
|
}
|
|
628
684
|
default: {
|
|
629
|
-
console.error(
|
|
685
|
+
console.error(`${ui.err("error:")} unknown marketplace subcommand: ${sub}\n`);
|
|
630
686
|
console.error(MARKETPLACE_USAGE);
|
|
631
687
|
process.exit(1);
|
|
632
688
|
}
|
|
@@ -729,7 +785,7 @@ function isInvokedDirectly() {
|
|
|
729
785
|
}
|
|
730
786
|
if (isInvokedDirectly()) {
|
|
731
787
|
main(process.argv.slice(2)).catch((err) => {
|
|
732
|
-
console.error(
|
|
788
|
+
console.error(`${ui.err("error:")} ${err instanceof Error ? err.message : String(err)}`);
|
|
733
789
|
process.exit(1);
|
|
734
790
|
});
|
|
735
791
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
/** Projection subdirectory that holds the self-contained agy plugin root. */
|
|
3
|
+
export const ANTIGRAVITY_PROJECTION_DIR = ".antigravity-plugin";
|
|
4
|
+
/**
|
|
5
|
+
* Generate an Antigravity (`agy`) plugin.json from an ADG manifest.
|
|
6
|
+
*
|
|
7
|
+
* Antigravity's manifest is minimal: it reads only `name` from a `plugin.json`
|
|
8
|
+
* and discovers components by convention (sibling `skills/`, `agents/`,
|
|
9
|
+
* `commands/`, `hooks/` directories plus a `mcp_config.json`) — all resolved
|
|
10
|
+
* relative to the directory handed to `agy plugin install`, with no manifest
|
|
11
|
+
* path indirection. We therefore project a self-contained agy plugin root under
|
|
12
|
+
* `.antigravity-plugin/`: this pure transform emits its `plugin.json`, while the
|
|
13
|
+
* agent materializes the rest (mcp_config.json + symlinked component dirs), so a
|
|
14
|
+
* partial-install `selection` is not expressible for this target.
|
|
15
|
+
*/
|
|
16
|
+
export function toAntigravityManifest(_pluginDir, manifest, _selection) {
|
|
17
|
+
return { defaultPath: join(ANTIGRAVITY_PROJECTION_DIR, "plugin.json"), manifest: { name: manifest.name } };
|
|
18
|
+
}
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { toAnthropicManifest } from "./anthropic.js";
|
|
2
2
|
import { toCodexManifest } from "./openai.js";
|
|
3
|
+
import { toAntigravityManifest } from "./antigravity.js";
|
|
3
4
|
export const ADAPTERS = {
|
|
4
5
|
claude: toAnthropicManifest,
|
|
5
6
|
anthropic: toAnthropicManifest,
|
|
6
7
|
codex: toCodexManifest,
|
|
7
8
|
openai: toCodexManifest,
|
|
9
|
+
antigravity: toAntigravityManifest,
|
|
10
|
+
agy: toAntigravityManifest,
|
|
11
|
+
gemini: toAntigravityManifest,
|
|
8
12
|
};
|
|
9
|
-
export const ADAPTER_TARGETS = ["claude", "codex"];
|
|
10
|
-
|
|
13
|
+
export const ADAPTER_TARGETS = ["claude", "codex", "antigravity"];
|
|
14
|
+
/**
|
|
15
|
+
* Component categories each adapter target can actually express, mirroring what
|
|
16
|
+
* the adapters emit: the Claude manifest carries skills/agents/commands/hooks/mcp
|
|
17
|
+
* (`toAnthropicManifest`), while Codex only consumes skills (`toCodexManifest`).
|
|
18
|
+
* Antigravity (`agy`) discovers the same superset as Claude via convention
|
|
19
|
+
* (skills/agents/commands/hooks dirs + mcp_config.json). `apps` is emitted by
|
|
20
|
+
* none, so it maps to no target. Used to derive which agents a plugin is
|
|
21
|
+
* adaptable to from its exposed component types.
|
|
22
|
+
*/
|
|
23
|
+
export const ADAPTER_COMPONENTS = {
|
|
24
|
+
claude: ["skills", "agents", "commands", "hooks", "mcp"],
|
|
25
|
+
codex: ["skills"],
|
|
26
|
+
antigravity: ["skills", "agents", "commands", "hooks", "mcp"],
|
|
27
|
+
};
|
|
28
|
+
export { toAnthropicManifest, toCodexManifest, toAntigravityManifest };
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { cpSync, existsSync, rmSync, statSync, symlinkSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join, relative } from "node:path";
|
|
5
|
+
import { ensureDir, writeJson } from "../fsutil.js";
|
|
6
|
+
import { readManifest } from "../manifest.js";
|
|
7
|
+
import { resolveSkillEntries } from "../skills.js";
|
|
8
|
+
import { isExposed } from "../components.js";
|
|
9
|
+
import { installedPluginDir, lockPath } from "../paths.js";
|
|
10
|
+
import { readLock } from "../lock.js";
|
|
11
|
+
import { ANTIGRAVITY_PROJECTION_DIR } from "../adapters/antigravity.js";
|
|
12
|
+
/**
|
|
13
|
+
* Antigravity (`agy`) agent.
|
|
14
|
+
*
|
|
15
|
+
* Antigravity discovers a plugin by convention relative to the directory handed
|
|
16
|
+
* to `agy plugin install` — `plugin.json` plus sibling `skills/`, `agents/`,
|
|
17
|
+
* `commands/`, `hooks/` dirs and a `mcp_config.json`, with no manifest path
|
|
18
|
+
* indirection. We therefore project a self-contained agy plugin root under
|
|
19
|
+
* `<store>/.antigravity-plugin/`: generated `plugin.json` + `mcp_config.json`
|
|
20
|
+
* (the ADG `mcp/.mcp.json` shape is exactly agy's, so it passes through) and
|
|
21
|
+
* *symlinks* to the real component dirs one level up, so nothing is duplicated
|
|
22
|
+
* on disk. agy follows these symlinks; where the platform forbids them (e.g.
|
|
23
|
+
* Windows without privilege) we fall back to a copy. We then drive
|
|
24
|
+
* `agy plugin install/uninstall` (which owns `~/.gemini/antigravity-cli`).
|
|
25
|
+
*/
|
|
26
|
+
const ID = "antigravity";
|
|
27
|
+
/**
|
|
28
|
+
* Single-directory component fields: agy reads each as a sibling dir named by
|
|
29
|
+
* convention. `skills` is handled separately because it can be a path-list and
|
|
30
|
+
* supports per-skill subsetting.
|
|
31
|
+
*/
|
|
32
|
+
const DIR_FIELDS = ["agents", "commands", "hooks"];
|
|
33
|
+
function geminiHome(env) {
|
|
34
|
+
return env.GEMINI_HOME?.trim() || join(homedir(), ".gemini");
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* agy's config/store home: `<GEMINI_HOME>/antigravity-cli` (defaulting to
|
|
38
|
+
* `~/.gemini/antigravity-cli`). Exported so the resolver itself is testable
|
|
39
|
+
* without depending on the host filesystem state.
|
|
40
|
+
*/
|
|
41
|
+
export function antigravityHome(env = process.env) {
|
|
42
|
+
return join(geminiHome(env), "antigravity-cli");
|
|
43
|
+
}
|
|
44
|
+
function available() {
|
|
45
|
+
// `--help` is rejected by `install` (it parses it as a target), so probe the
|
|
46
|
+
// plugin command group with its own `help` subcommand instead.
|
|
47
|
+
return spawnSync("agy", ["plugin", "help"], { stdio: "ignore" }).status === 0;
|
|
48
|
+
}
|
|
49
|
+
function run(args) {
|
|
50
|
+
const r = spawnSync("agy", args, { encoding: "utf8" });
|
|
51
|
+
const ok = r.status === 0;
|
|
52
|
+
// Surface the CLI's own diagnostics on failure instead of swallowing them.
|
|
53
|
+
if (!ok && r.stderr)
|
|
54
|
+
console.error(r.stderr.trim());
|
|
55
|
+
return { ok, out: `${r.stdout ?? ""}${r.stderr ?? ""}` };
|
|
56
|
+
}
|
|
57
|
+
/** Resolve a plugin's on-disk store directory and selection from the lock's provenance. */
|
|
58
|
+
function pluginStore(pluginsDir, name) {
|
|
59
|
+
const entry = readLock(lockPath(pluginsDir)).plugins[name];
|
|
60
|
+
if (!entry)
|
|
61
|
+
return undefined;
|
|
62
|
+
const dir = installedPluginDir(pluginsDir, name, entry.origin);
|
|
63
|
+
return existsSync(dir) ? { dir, selection: entry.selection } : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** First on-disk top segment of a declared component path (e.g. "./agents/" -> "agents"). */
|
|
66
|
+
function componentSegment(value) {
|
|
67
|
+
const first = Array.isArray(value) ? value[0] : value;
|
|
68
|
+
if (typeof first !== "string")
|
|
69
|
+
return undefined;
|
|
70
|
+
const seg = first.replace(/^\.?[/\\]/, "").split(/[/\\]/)[0];
|
|
71
|
+
return seg || undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Symlink `linkPath` at `absTarget` (target stored relative so the projection
|
|
75
|
+
* survives the whole plugin dir being moved), copying instead where symlinks are
|
|
76
|
+
* unavailable (e.g. Windows without privilege). Idempotent.
|
|
77
|
+
*/
|
|
78
|
+
function linkOrCopy(linkPath, absTarget) {
|
|
79
|
+
rmSync(linkPath, { recursive: true, force: true });
|
|
80
|
+
ensureDir(dirname(linkPath));
|
|
81
|
+
try {
|
|
82
|
+
symlinkSync(relative(dirname(linkPath), absTarget), linkPath, "dir");
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
cpSync(absTarget, linkPath, { recursive: true });
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Build the agy-native projection under `<dir>/.antigravity-plugin/`: a
|
|
90
|
+
* `plugin.json` (name only), a `mcp_config.json` copied verbatim from the
|
|
91
|
+
* manifest's mcp file when present, and relative symlinks (copy fallback) to the
|
|
92
|
+
* declared component dirs named for agy's convention.
|
|
93
|
+
*
|
|
94
|
+
* An optional `selection` (the plugin's partial install) narrows what is
|
|
95
|
+
* projected: component categories outside it are dropped, and `skills` is pinned
|
|
96
|
+
* to the selected subset. `skills` is also projected per-skill into a real
|
|
97
|
+
* `skills/` dir, so a path-list spanning multiple roots is fully honored rather
|
|
98
|
+
* than collapsing to its first root. Idempotent; safe to re-run.
|
|
99
|
+
*/
|
|
100
|
+
export function writeAntigravityProjection(dir, selection) {
|
|
101
|
+
const manifest = readManifest(dir);
|
|
102
|
+
const stage = join(dir, ANTIGRAVITY_PROJECTION_DIR);
|
|
103
|
+
ensureDir(stage);
|
|
104
|
+
writeJson(join(stage, "plugin.json"), { name: manifest.name });
|
|
105
|
+
const mcpConfig = join(stage, "mcp_config.json");
|
|
106
|
+
rmSync(mcpConfig, { force: true });
|
|
107
|
+
if (manifest.mcp && isExposed(selection, "mcp")) {
|
|
108
|
+
const mcpFile = join(dir, manifest.mcp);
|
|
109
|
+
// The ADG mcp file shape is exactly agy's `mcp_config.json`, so copy it
|
|
110
|
+
// verbatim — preserving formatting and avoiding a parse/re-serialize round-trip.
|
|
111
|
+
if (existsSync(mcpFile))
|
|
112
|
+
cpSync(mcpFile, mcpConfig);
|
|
113
|
+
}
|
|
114
|
+
const skillsDir = join(stage, "skills");
|
|
115
|
+
rmSync(skillsDir, { recursive: true, force: true });
|
|
116
|
+
if (manifest.skills !== undefined && isExposed(selection, "skills")) {
|
|
117
|
+
const pick = selection?.skills;
|
|
118
|
+
for (const e of resolveSkillEntries(dir, manifest)) {
|
|
119
|
+
if (pick && !pick.includes(e.name))
|
|
120
|
+
continue;
|
|
121
|
+
if (!e.skillMd)
|
|
122
|
+
continue;
|
|
123
|
+
const srcSkillDir = dirname(e.skillMd);
|
|
124
|
+
if (existsSync(srcSkillDir) && statSync(srcSkillDir).isDirectory()) {
|
|
125
|
+
linkOrCopy(join(skillsDir, e.name), srcSkillDir);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const field of DIR_FIELDS) {
|
|
130
|
+
const link = join(stage, field);
|
|
131
|
+
rmSync(link, { recursive: true, force: true });
|
|
132
|
+
if (!isExposed(selection, field))
|
|
133
|
+
continue;
|
|
134
|
+
const seg = componentSegment(manifest[field]);
|
|
135
|
+
if (!seg)
|
|
136
|
+
continue;
|
|
137
|
+
const srcDir = join(dir, seg);
|
|
138
|
+
// agy reads the component by its convention name (`field`); point that at
|
|
139
|
+
// the real source dir so a non-conventional source name still resolves.
|
|
140
|
+
if (existsSync(srcDir))
|
|
141
|
+
linkOrCopy(link, srcDir);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
export const antigravityAgent = {
|
|
145
|
+
id: ID,
|
|
146
|
+
displayName: "Antigravity",
|
|
147
|
+
adaptTarget: "antigravity",
|
|
148
|
+
detect: (env = process.env) => existsSync(antigravityHome(env)),
|
|
149
|
+
available,
|
|
150
|
+
activate(ctx) {
|
|
151
|
+
if (!available())
|
|
152
|
+
return { agent: ID, affected: [], skipped: true };
|
|
153
|
+
const affected = [];
|
|
154
|
+
for (const p of ctx.plugins) {
|
|
155
|
+
// Isolate each plugin: a malformed manifest or a filesystem error must not
|
|
156
|
+
// abort activation of the remaining (valid) plugins.
|
|
157
|
+
try {
|
|
158
|
+
const store = pluginStore(ctx.pluginsDir, p);
|
|
159
|
+
if (!store)
|
|
160
|
+
continue;
|
|
161
|
+
writeAntigravityProjection(store.dir, store.selection);
|
|
162
|
+
if (run(["plugin", "install", join(store.dir, ANTIGRAVITY_PROJECTION_DIR)]).ok)
|
|
163
|
+
affected.push(p);
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
console.error(`failed to enable "${p}" in Antigravity:`, err);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return { agent: ID, affected, skipped: false };
|
|
170
|
+
},
|
|
171
|
+
deactivate(ctx) {
|
|
172
|
+
if (!available())
|
|
173
|
+
return { agent: ID, affected: [], skipped: true };
|
|
174
|
+
const affected = [];
|
|
175
|
+
for (const p of ctx.plugins) {
|
|
176
|
+
if (run(["plugin", "uninstall", p]).ok)
|
|
177
|
+
affected.push(p);
|
|
178
|
+
}
|
|
179
|
+
return { agent: ID, affected, skipped: false };
|
|
180
|
+
},
|
|
181
|
+
// `agy plugin install` re-imports the source dir, so re-running it is the refresh.
|
|
182
|
+
refresh(ctx) {
|
|
183
|
+
return antigravityAgent.activate(ctx);
|
|
184
|
+
},
|
|
185
|
+
};
|
package/dist/src/agents/index.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { registerAgent } from "./registry.js";
|
|
2
2
|
import { claudeAgent } from "./claude.js";
|
|
3
3
|
import { codexAgent } from "./codex.js";
|
|
4
|
+
import { antigravityAgent } from "./antigravity.js";
|
|
4
5
|
// Built-in agents register on import. Third-party agents can `registerAgent()`
|
|
5
6
|
// their own implementation (stage 2: discover from config without core edits).
|
|
6
7
|
registerAgent(claudeAgent);
|
|
7
8
|
registerAgent(codexAgent);
|
|
9
|
+
registerAgent(antigravityAgent);
|
|
8
10
|
export * from "./types.js";
|
|
9
|
-
export { registerAgent, getAgent, allAgents, detectedAgents, resolveAgents } from "./registry.js";
|
|
11
|
+
export { registerAgent, getAgent, allAgents, detectedAgents, resolveAgents, agentsForComponents } from "./registry.js";
|
|
10
12
|
export { writeClaudeCatalog } from "./claude.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ADAPTER_COMPONENTS } from "../adapters/index.js";
|
|
1
2
|
/**
|
|
2
3
|
* The agent registry — the "factory": construction/lookup only. Orchestration
|
|
3
4
|
* (looping, dependency order, store writes) stays in the command layer.
|
|
@@ -16,6 +17,17 @@ export function allAgents() {
|
|
|
16
17
|
export function detectedAgents(env) {
|
|
17
18
|
return allAgents().filter((a) => a.detect(env));
|
|
18
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Registered agents whose adapter can express at least one of the given exposed
|
|
22
|
+
* component types — i.e. the agents a plugin is adaptable to. An empty `types`
|
|
23
|
+
* (no manifest / nothing exposed) can't be proven incompatible, so all agents
|
|
24
|
+
* are returned.
|
|
25
|
+
*/
|
|
26
|
+
export function agentsForComponents(types) {
|
|
27
|
+
if (types.length === 0)
|
|
28
|
+
return allAgents();
|
|
29
|
+
return allAgents().filter((a) => (ADAPTER_COMPONENTS[a.adaptTarget] ?? []).some((c) => types.includes(c)));
|
|
30
|
+
}
|
|
19
31
|
/** Agents matching the given ids, or every registered agent when none are given. */
|
|
20
32
|
export function resolveAgents(targets) {
|
|
21
33
|
if (!targets)
|
|
@@ -6,7 +6,7 @@ import { fromNativeManifest } from "../adapters/reverse.js";
|
|
|
6
6
|
import { adaptPlugin } from "./adapt.js";
|
|
7
7
|
import { copyPluginDir, writeJson } from "../fsutil.js";
|
|
8
8
|
import { folderHash } from "../hash.js";
|
|
9
|
-
import { packageFilter } from "../package.js";
|
|
9
|
+
import { packageFilter, PROJECTION_DIRS } from "../package.js";
|
|
10
10
|
import { lockPath, marketplacePath, marketplaceSourcePath, pluginDir } from "../paths.js";
|
|
11
11
|
import { readLock, upsertEntry, writeLock } from "../lock.js";
|
|
12
12
|
import { ADG_MANIFEST_PATH, readManifest } from "../manifest.js";
|
|
@@ -17,7 +17,8 @@ import { sameSource, COMPONENT_TYPES } from "../types.js";
|
|
|
17
17
|
import { pluginContents, presentComponents } from "../components.js";
|
|
18
18
|
import { skillDescriptionLoader } from "../skills.js";
|
|
19
19
|
import { resolveAgents } from "../agents/index.js";
|
|
20
|
-
|
|
20
|
+
// Generated runtime projections never count toward a plugin's content hash.
|
|
21
|
+
const HASH_IGNORE = PROJECTION_DIRS;
|
|
21
22
|
function toPosix(p) {
|
|
22
23
|
return p.split("\\").join("/");
|
|
23
24
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { folderHash } from "../hash.js";
|
|
3
|
-
import { packageFilter } from "../package.js";
|
|
3
|
+
import { packageFilter, PROJECTION_DIRS } from "../package.js";
|
|
4
4
|
import { lockPath, installedPluginDir } from "../paths.js";
|
|
5
5
|
import { readLock, writeLock } from "../lock.js";
|
|
6
6
|
import { readManifest } from "../manifest.js";
|
|
7
7
|
import { adaptPlugin } from "./adapt.js";
|
|
8
|
+
import { ADAPTER_TARGETS } from "../adapters/index.js";
|
|
8
9
|
import { resolveAgents } from "../agents/index.js";
|
|
9
10
|
/**
|
|
10
11
|
* Re-scan installed plugins in a plugins directory, refreshing each lock
|
|
@@ -29,14 +30,16 @@ export function updateLock(pluginsDir, now = new Date().toISOString(), opts = {}
|
|
|
29
30
|
continue;
|
|
30
31
|
}
|
|
31
32
|
const manifest = readManifest(dir);
|
|
32
|
-
const hash = folderHash(dir,
|
|
33
|
+
const hash = folderHash(dir, PROJECTION_DIRS, packageFilter(manifest, { includeProjections: false }));
|
|
33
34
|
const changed = hash !== entry.folderHash || manifest.version !== entry.version;
|
|
34
35
|
if (changed) {
|
|
35
36
|
entry.folderHash = hash;
|
|
36
37
|
entry.version = manifest.version;
|
|
37
38
|
entry.updatedAt = now;
|
|
38
39
|
// Regenerate runtime manifests from the updated source, honoring selection.
|
|
39
|
-
|
|
40
|
+
// Covers every registered adapter target (claude/codex/antigravity) so a
|
|
41
|
+
// projection can't go stale after an update.
|
|
42
|
+
adaptPlugin(dir, [...ADAPTER_TARGETS], entry.selection);
|
|
40
43
|
changedNames.push(name);
|
|
41
44
|
}
|
|
42
45
|
results.push({ name, changed, version: manifest.version, folderHash: hash });
|
package/dist/src/package.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
/** Top-level metadata files always shipped with a plugin, matched case-insensitively. */
|
|
12
12
|
const META_RE = /^(README|LICEN[CS]E|CHANGELOG|NOTICE)(\..+)?$/i;
|
|
13
13
|
/** Generated runtime projections — shipped, but excluded from the content hash. */
|
|
14
|
-
export const PROJECTION_DIRS = [".claude-plugin", ".codex-plugin"];
|
|
14
|
+
export const PROJECTION_DIRS = [".claude-plugin", ".codex-plugin", ".antigravity-plugin"];
|
|
15
15
|
/** Extract the first path segment of a manifest component value (e.g. "./skills/" -> "skills"). */
|
|
16
16
|
function topSegment(p) {
|
|
17
17
|
return p.replace(/^\.?[/\\]/, "").split(/[/\\]/)[0] ?? "";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rbbtsn0w/adg",
|
|
3
|
-
"version": "0.2
|
|
3
|
+
"version": "0.3.0-beta.2",
|
|
4
4
|
"description": "Agent Directory Group (ADG) toolkit — two domains: plugins and skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"scripts": {
|
|
25
25
|
"adg": "node ./bin/adg.ts",
|
|
26
|
-
"build": "
|
|
26
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.build.json --noCheck && node -e \"require('fs').chmodSync('dist/bin/adg.js',0o755)\"",
|
|
27
27
|
"test": "node --test 'test/**/*.test.ts'",
|
|
28
28
|
"typecheck": "tsc --noEmit",
|
|
29
29
|
"prepare": "npm run typecheck",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"@semantic-release/npm": "^13.1.5",
|
|
53
53
|
"@semantic-release/release-notes-generator": "^14.1.1",
|
|
54
54
|
"@types/node": "^22.0.0",
|
|
55
|
+
"conventional-changelog-conventionalcommits": "^8.0.0",
|
|
55
56
|
"semantic-release": "^25.0.5",
|
|
56
57
|
"typescript": "^5.6.0"
|
|
57
58
|
}
|