@agentproto/cli 0.1.0-alpha.8 → 0.1.0

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/dist/cli.mjs CHANGED
@@ -5,16 +5,18 @@ import { resolve, basename, join, dirname, isAbsolute, normalize, relative } fro
5
5
  import * as childProc from 'child_process';
6
6
  import { execFile, spawn } from 'child_process';
7
7
  import { promisify, parseArgs } from 'util';
8
- import { unlink, readFile, readdir, writeFile, mkdir, stat, chmod, mkdtemp, rm } from 'fs/promises';
8
+ import { unlink, readFile, chmod, readdir, writeFile, mkdir, stat, mkdtemp, rm, appendFile } from 'fs/promises';
9
9
  import { randomUUID, randomBytes, createHash } from 'crypto';
10
10
  import { createInterface } from 'readline/promises';
11
11
  import { stdout, stdin } from 'process';
12
+ import { createRequire } from 'module';
13
+ import { pathToFileURL } from 'url';
14
+ import { z } from 'zod';
12
15
  import { createAgentCliRuntime } from '@agentproto/driver-agent-cli';
16
+ import matter3 from 'gray-matter';
13
17
  import { wrapWebSocket, createTunnelServer } from '@agentproto/acp/tunnel';
14
18
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
19
  import '@modelcontextprotocol/sdk/server/stdio.js';
16
- import { z } from 'zod';
17
- import matter from 'gray-matter';
18
20
  import { EventEmitter } from 'events';
19
21
  import http, { createServer } from 'http';
20
22
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
@@ -114,7 +116,7 @@ __export(daemon_exports, {
114
116
  });
115
117
  async function runDaemon(args) {
116
118
  if (args.includes("--help") || args.includes("-h") || args.length === 0) {
117
- process.stdout.write(USAGE5);
119
+ process.stdout.write(USAGE6);
118
120
  return args.length === 0 ? 2 : 0;
119
121
  }
120
122
  if (platform() !== "darwin") {
@@ -128,9 +130,9 @@ async function runDaemon(args) {
128
130
  const rest = args.slice(1);
129
131
  switch (sub) {
130
132
  case "install":
131
- return runInstall2(rest);
133
+ return runInstall3(rest);
132
134
  case "uninstall":
133
- return runUninstall();
135
+ return runUninstall2();
134
136
  case "start":
135
137
  return runStart2();
136
138
  case "stop":
@@ -143,7 +145,7 @@ async function runDaemon(args) {
143
145
  process.stderr.write(
144
146
  `agentproto daemon: unknown sub-verb "${sub}".
145
147
 
146
- ${USAGE5}`
148
+ ${USAGE6}`
147
149
  );
148
150
  return 2;
149
151
  }
@@ -162,7 +164,7 @@ function paths() {
162
164
  ]
163
165
  };
164
166
  }
165
- async function runInstall2(args) {
167
+ async function runInstall3(args) {
166
168
  const { values } = parseArgs({
167
169
  args: [...args],
168
170
  allowPositionals: false,
@@ -226,7 +228,7 @@ ${boot.stderr}
226
228
  );
227
229
  return 0;
228
230
  }
229
- async function runUninstall() {
231
+ async function runUninstall2() {
230
232
  const p = paths();
231
233
  const target = `gui/${process.getuid?.() ?? 0}/${LABEL}`;
232
234
  const out = await launchctl(["bootout", target]);
@@ -387,7 +389,7 @@ function xmlEscape(s) {
387
389
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
388
390
  }
389
391
  function launchctl(args) {
390
- return new Promise((resolve7) => {
392
+ return new Promise((resolve9) => {
391
393
  const child = spawn("launchctl", args, { stdio: ["ignore", "pipe", "pipe"] });
392
394
  let stdout = "";
393
395
  let stderr = "";
@@ -395,9 +397,9 @@ function launchctl(args) {
395
397
  child.stderr?.setEncoding("utf8").on("data", (c) => stderr += c);
396
398
  child.on(
397
399
  "error",
398
- (err) => resolve7({ code: 127, stdout, stderr: err.message })
400
+ (err) => resolve9({ code: 127, stdout, stderr: err.message })
399
401
  );
400
- child.on("exit", (code) => resolve7({ code: code ?? 1, stdout, stderr }));
402
+ child.on("exit", (code) => resolve9({ code: code ?? 1, stdout, stderr }));
401
403
  });
402
404
  }
403
405
  function humaniseUptime(ms) {
@@ -410,12 +412,12 @@ function humaniseUptime(ms) {
410
412
  function indent(s, prefix) {
411
413
  return s.split("\n").map((l) => prefix + l).join("\n");
412
414
  }
413
- var LABEL, USAGE5;
415
+ var LABEL, USAGE6;
414
416
  var init_daemon = __esm({
415
417
  "src/commands/daemon.ts"() {
416
418
  init_config();
417
419
  LABEL = "sh.agentproto";
418
- USAGE5 = `agentproto daemon \u2014 run agentproto serve as a background service
420
+ USAGE6 = `agentproto daemon \u2014 run agentproto serve as a background service
419
421
 
420
422
  Usage:
421
423
  agentproto daemon install [--dry-run] register service + start it (macOS launchd today)
@@ -842,7 +844,7 @@ async function postForm(url, body) {
842
844
  return await res.json();
843
845
  }
844
846
  function sleep(ms) {
845
- return new Promise((resolve7) => setTimeout(resolve7, ms));
847
+ return new Promise((resolve9) => setTimeout(resolve9, ms));
846
848
  }
847
849
  function formatDuration(ms) {
848
850
  if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
@@ -853,16 +855,16 @@ function openBrowser(url) {
853
855
  const p = platform();
854
856
  const cmd = p === "darwin" ? "open" : p === "win32" ? "cmd" : "xdg-open";
855
857
  const args = p === "win32" ? ["/c", "start", url] : [url];
856
- return new Promise((resolve7) => {
858
+ return new Promise((resolve9) => {
857
859
  try {
858
860
  const child = spawn(cmd, args, { stdio: "ignore", detached: true });
859
- child.once("error", () => resolve7());
861
+ child.once("error", () => resolve9());
860
862
  child.once("spawn", () => {
861
863
  child.unref();
862
- resolve7();
864
+ resolve9();
863
865
  });
864
866
  } catch {
865
- resolve7();
867
+ resolve9();
866
868
  }
867
869
  });
868
870
  }
@@ -991,7 +993,7 @@ async function runEdit() {
991
993
  const cfg = await loadConfig();
992
994
  await saveConfig(cfg);
993
995
  const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
994
- return new Promise((resolve7) => {
996
+ return new Promise((resolve9) => {
995
997
  const child = spawn(editor, [CONFIG_FILE_PATH()], {
996
998
  stdio: "inherit"
997
999
  });
@@ -1000,9 +1002,9 @@ async function runEdit() {
1000
1002
  `agentproto config edit: failed to launch ${editor}: ${err.message}
1001
1003
  `
1002
1004
  );
1003
- resolve7(1);
1005
+ resolve9(1);
1004
1006
  });
1005
- child.on("exit", (code) => resolve7(code ?? 0));
1007
+ child.on("exit", (code) => resolve9(code ?? 0));
1006
1008
  });
1007
1009
  }
1008
1010
  function parseValue(raw) {
@@ -1099,8 +1101,8 @@ async function collectAgentprotoNamespaceRoots(start) {
1099
1101
  for (let depth = 0; depth < 16; depth++) {
1100
1102
  for (const candidate of candidatesAt(cur)) {
1101
1103
  try {
1102
- const stat2 = await promises.stat(candidate);
1103
- if (stat2.isDirectory()) roots.push(candidate);
1104
+ const stat5 = await promises.stat(candidate);
1105
+ if (stat5.isDirectory()) roots.push(candidate);
1104
1106
  } catch {
1105
1107
  }
1106
1108
  }
@@ -1283,10 +1285,10 @@ async function runExternalStep(step, ledger, head) {
1283
1285
  `);
1284
1286
  const opener = platform() === "darwin" ? "open" : platform() === "win32" ? "cmd" : "xdg-open";
1285
1287
  const args = platform() === "win32" ? ["/c", "start", step.url] : [step.url];
1286
- await new Promise((resolve7) => {
1288
+ await new Promise((resolve9) => {
1287
1289
  const child = spawn(opener, args, { stdio: "ignore", detached: true });
1288
- child.once("error", () => resolve7());
1289
- child.once("spawn", () => resolve7());
1290
+ child.once("error", () => resolve9());
1291
+ child.once("spawn", () => resolve9());
1290
1292
  });
1291
1293
  let value = "";
1292
1294
  if (step.callback?.param) {
@@ -1359,7 +1361,7 @@ async function promptString(question, opts) {
1359
1361
  process.stdin.setRawMode?.(true);
1360
1362
  let buf = "";
1361
1363
  process.stdout.write(prompt);
1362
- return new Promise((resolve7) => {
1364
+ return new Promise((resolve9) => {
1363
1365
  const onData = (chunk) => {
1364
1366
  for (const code of chunk) {
1365
1367
  if (code === 13 || code === 10) {
@@ -1367,7 +1369,7 @@ async function promptString(question, opts) {
1367
1369
  process.stdin.setRawMode?.(false);
1368
1370
  process.stdout.write("\n");
1369
1371
  rl.close();
1370
- resolve7(buf || opts.defaultValue || "");
1372
+ resolve9(buf || opts.defaultValue || "");
1371
1373
  return;
1372
1374
  }
1373
1375
  if (code === 3) {
@@ -1449,7 +1451,7 @@ async function resolveSelectOptions(options) {
1449
1451
  });
1450
1452
  }
1451
1453
  async function runShellCapturing(cmd, opts) {
1452
- return new Promise((resolve7) => {
1454
+ return new Promise((resolve9) => {
1453
1455
  const child = spawn("bash", ["-lc", cmd], {
1454
1456
  stdio: opts.interactive ? "inherit" : ["ignore", "pipe", "pipe"]
1455
1457
  });
@@ -1467,11 +1469,11 @@ async function runShellCapturing(cmd, opts) {
1467
1469
  }, opts.timeoutMs);
1468
1470
  child.once("error", () => {
1469
1471
  clearTimeout(timer);
1470
- resolve7({ exitCode: 127, stdout, stderr: stderr || "spawn error" });
1472
+ resolve9({ exitCode: 127, stdout, stderr: stderr || "spawn error" });
1471
1473
  });
1472
1474
  child.once("exit", (code) => {
1473
1475
  clearTimeout(timer);
1474
- resolve7({ exitCode: code ?? 0, stdout, stderr });
1476
+ resolve9({ exitCode: code ?? 0, stdout, stderr });
1475
1477
  });
1476
1478
  });
1477
1479
  }
@@ -1505,9 +1507,315 @@ async function saveLedger(path, ledger) {
1505
1507
  await chmod(path, 384).catch(() => {
1506
1508
  });
1507
1509
  }
1510
+ async function runInstallProfile(slug, args) {
1511
+ const { values } = parseArgs({
1512
+ args: [...args],
1513
+ allowPositionals: true,
1514
+ strict: true,
1515
+ options: {
1516
+ force: { type: "boolean", short: "f" },
1517
+ "dry-run": { type: "boolean" },
1518
+ "skip-setup": { type: "boolean" },
1519
+ cwd: { type: "string" },
1520
+ package: { type: "string" }
1521
+ }
1522
+ });
1523
+ if (!slug.startsWith("runtime-profile/")) {
1524
+ process.stderr.write(
1525
+ `agentproto install: expected slug starting with 'runtime-profile/', got '${slug}'.
1526
+ `
1527
+ );
1528
+ return 2;
1529
+ }
1530
+ const profileName = slug.slice("runtime-profile/".length);
1531
+ if (!/^[a-z][a-z0-9-]*$/.test(profileName)) {
1532
+ process.stderr.write(
1533
+ `agentproto install: invalid profile name '${profileName}'. Lower-kebab only.
1534
+ `
1535
+ );
1536
+ return 2;
1537
+ }
1538
+ let packageName;
1539
+ if (typeof values.package === "string" && values.package) {
1540
+ packageName = values.package;
1541
+ } else {
1542
+ const aliased = await readProfileAlias(profileName);
1543
+ packageName = aliased ?? `@agentproto/runtime-profile-${profileName}`;
1544
+ }
1545
+ let mod;
1546
+ try {
1547
+ mod = await import(packageName);
1548
+ } catch (err) {
1549
+ const cause = err instanceof Error ? err.message : String(err);
1550
+ process.stderr.write(
1551
+ `agentproto install: could not load profile package '${packageName}'. Install it first with: npm i -g ${packageName}
1552
+ cause: ${cause}
1553
+ `
1554
+ );
1555
+ return 1;
1556
+ }
1557
+ const filesDir = typeof mod.FILES_DIR === "string" ? mod.FILES_DIR : null;
1558
+ const loadProfileManifest = mod.loadProfileManifest;
1559
+ if (!filesDir || !loadProfileManifest) {
1560
+ process.stderr.write(
1561
+ `agentproto install: profile package '${packageName}' does not export FILES_DIR + loadProfileManifest.
1562
+ `
1563
+ );
1564
+ return 1;
1565
+ }
1566
+ const manifest = await loadProfileManifest();
1567
+ const cwd = values.cwd ? resolve(values.cwd) : process.cwd();
1568
+ const dryRun = values["dry-run"] === true;
1569
+ const force = values.force === true;
1570
+ process.stdout.write(
1571
+ `agentproto install ${slug} v${manifest.version} \u2192 ${cwd}
1572
+ ${manifest.description}
1573
+ `
1574
+ );
1575
+ const ledgerPath = ledgerPathFor2(profileName);
1576
+ const prevLedger = await loadLedger2(ledgerPath);
1577
+ const newLedger = {
1578
+ slug,
1579
+ version: manifest.version,
1580
+ installedAt: prevLedger?.installedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
1581
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
1582
+ files: []
1583
+ };
1584
+ let applied = 0;
1585
+ let skipped = 0;
1586
+ let failed = 0;
1587
+ for (const entry of manifest.files) {
1588
+ const src = resolve(filesDir, entry.src);
1589
+ const dest = resolve(cwd, entry.dest);
1590
+ const prev = prevLedger?.files.find((f) => f.dest === entry.dest) ?? null;
1591
+ try {
1592
+ const srcBuf = await readFile(src);
1593
+ const result = await applyStrategy({
1594
+ strategy: entry.strategy,
1595
+ srcBuf,
1596
+ dest,
1597
+ prev,
1598
+ force,
1599
+ dryRun
1600
+ });
1601
+ newLedger.files.push({
1602
+ dest: entry.dest,
1603
+ strategy: entry.strategy,
1604
+ hashAfter: result.hashAfter,
1605
+ appliedAt: result.wrote ? (/* @__PURE__ */ new Date()).toISOString() : prev?.appliedAt ?? (/* @__PURE__ */ new Date()).toISOString()
1606
+ });
1607
+ if (result.wrote) {
1608
+ applied += 1;
1609
+ process.stdout.write(` ${result.action.padEnd(10)} ${entry.dest}
1610
+ `);
1611
+ if (entry.executable && !dryRun) {
1612
+ await chmod(dest, 493);
1613
+ }
1614
+ } else {
1615
+ skipped += 1;
1616
+ process.stdout.write(` ${result.action.padEnd(10)} ${entry.dest}
1617
+ `);
1618
+ }
1619
+ } catch (err) {
1620
+ failed += 1;
1621
+ const msg = err instanceof Error ? err.message : String(err);
1622
+ process.stderr.write(` FAIL ${entry.dest} \u2014 ${msg}
1623
+ `);
1624
+ }
1625
+ }
1626
+ if (!dryRun) {
1627
+ await saveLedger2(ledgerPath, newLedger);
1628
+ }
1629
+ process.stdout.write(
1630
+ `agentproto install ${slug}: ${applied} applied, ${skipped} skipped, ${failed} failed${dryRun ? " (dry-run)" : ""}
1631
+ `
1632
+ );
1633
+ return failed === 0 ? 0 : 1;
1634
+ }
1635
+ async function applyStrategy(opts) {
1636
+ const { strategy, srcBuf, dest, prev, force, dryRun } = opts;
1637
+ const destExists = await fileExists(dest);
1638
+ if (strategy === "preserve") {
1639
+ if (destExists) {
1640
+ const currentHash = await hashFile(dest);
1641
+ return { wrote: false, action: "preserve", hashAfter: currentHash };
1642
+ }
1643
+ if (!dryRun) {
1644
+ await ensureDir(dirname(dest));
1645
+ await writeFile(dest, srcBuf);
1646
+ }
1647
+ return { wrote: true, action: "create", hashAfter: sha256(srcBuf) };
1648
+ }
1649
+ if (strategy === "overwrite") {
1650
+ const srcHash = sha256(srcBuf);
1651
+ if (destExists && !force) {
1652
+ const destHash = await hashFile(dest);
1653
+ if (destHash === srcHash) {
1654
+ return { wrote: false, action: "unchanged", hashAfter: destHash };
1655
+ }
1656
+ if (prev && prev.hashAfter !== destHash) {
1657
+ return {
1658
+ wrote: false,
1659
+ action: "user-edit",
1660
+ hashAfter: destHash
1661
+ };
1662
+ }
1663
+ }
1664
+ if (!dryRun) {
1665
+ await ensureDir(dirname(dest));
1666
+ await writeFile(dest, srcBuf);
1667
+ }
1668
+ return {
1669
+ wrote: true,
1670
+ action: destExists ? "update" : "create",
1671
+ hashAfter: srcHash
1672
+ };
1673
+ }
1674
+ if (strategy === "merge-json-deep") {
1675
+ const srcJson = parseJsonOrThrow(srcBuf.toString("utf8"), "src");
1676
+ let merged = srcJson;
1677
+ if (destExists) {
1678
+ const destRaw = await readFile(dest, "utf8");
1679
+ const destJson = parseJsonOrThrow(destRaw, "dest");
1680
+ merged = deepMerge(destJson, srcJson);
1681
+ }
1682
+ const out = `${JSON.stringify(merged, null, 2)}
1683
+ `;
1684
+ const outBuf = Buffer.from(out, "utf8");
1685
+ const outHash = sha256(outBuf);
1686
+ if (destExists) {
1687
+ const destHash = await hashFile(dest);
1688
+ if (destHash === outHash) {
1689
+ return { wrote: false, action: "unchanged", hashAfter: destHash };
1690
+ }
1691
+ }
1692
+ if (!dryRun) {
1693
+ await ensureDir(dirname(dest));
1694
+ await writeFile(dest, outBuf);
1695
+ }
1696
+ return {
1697
+ wrote: true,
1698
+ action: destExists ? "merge" : "create",
1699
+ hashAfter: outHash
1700
+ };
1701
+ }
1702
+ if (strategy === "append") {
1703
+ const srcText = srcBuf.toString("utf8");
1704
+ if (destExists) {
1705
+ const destText = await readFile(dest, "utf8");
1706
+ if (destText.includes(srcText)) {
1707
+ return {
1708
+ wrote: false,
1709
+ action: "unchanged",
1710
+ hashAfter: sha256(Buffer.from(destText, "utf8"))
1711
+ };
1712
+ }
1713
+ const out = `${destText.endsWith("\n") ? destText : `${destText}
1714
+ `}${srcText}`;
1715
+ const outBuf = Buffer.from(out, "utf8");
1716
+ if (!dryRun) {
1717
+ await ensureDir(dirname(dest));
1718
+ await writeFile(dest, outBuf);
1719
+ }
1720
+ return { wrote: true, action: "append", hashAfter: sha256(outBuf) };
1721
+ }
1722
+ if (!dryRun) {
1723
+ await ensureDir(dirname(dest));
1724
+ await writeFile(dest, srcBuf);
1725
+ }
1726
+ return { wrote: true, action: "create", hashAfter: sha256(srcBuf) };
1727
+ }
1728
+ throw new Error(`Unknown strategy: ${strategy}`);
1729
+ }
1730
+ function deepMerge(target, source) {
1731
+ if (target && source && typeof target === "object" && typeof source === "object" && !Array.isArray(target) && !Array.isArray(source)) {
1732
+ const out = { ...target };
1733
+ for (const [k, v] of Object.entries(source)) {
1734
+ out[k] = deepMerge(target[k], v);
1735
+ }
1736
+ return out;
1737
+ }
1738
+ if (Array.isArray(target) && Array.isArray(source)) {
1739
+ const seen = /* @__PURE__ */ new Set();
1740
+ const out = [];
1741
+ for (const item of [...target, ...source]) {
1742
+ const key = JSON.stringify(item);
1743
+ if (seen.has(key)) continue;
1744
+ seen.add(key);
1745
+ out.push(item);
1746
+ }
1747
+ return out;
1748
+ }
1749
+ return source ?? target;
1750
+ }
1751
+ function parseJsonOrThrow(raw, side) {
1752
+ try {
1753
+ return JSON.parse(raw);
1754
+ } catch (err) {
1755
+ const msg = err instanceof Error ? err.message : String(err);
1756
+ throw new Error(`merge-json-deep ${side} not valid JSON: ${msg}`);
1757
+ }
1758
+ }
1759
+ function sha256(buf) {
1760
+ return createHash("sha256").update(buf).digest("hex");
1761
+ }
1762
+ async function hashFile(path) {
1763
+ const buf = await readFile(path);
1764
+ return sha256(buf);
1765
+ }
1766
+ async function fileExists(path) {
1767
+ try {
1768
+ await stat(path);
1769
+ return true;
1770
+ } catch {
1771
+ return false;
1772
+ }
1773
+ }
1774
+ async function ensureDir(dir) {
1775
+ try {
1776
+ await stat(dir);
1777
+ } catch {
1778
+ await mkdir(dir, { recursive: true });
1779
+ }
1780
+ }
1781
+ function ledgerPathFor2(profileName) {
1782
+ return join(homedir(), ".agentproto", "profiles", `${profileName}.json`);
1783
+ }
1784
+ async function loadLedger2(path) {
1785
+ try {
1786
+ const raw = await readFile(path, "utf8");
1787
+ return JSON.parse(raw);
1788
+ } catch {
1789
+ return null;
1790
+ }
1791
+ }
1792
+ async function saveLedger2(path, ledger) {
1793
+ await ensureDir(dirname(path));
1794
+ await writeFile(path, `${JSON.stringify(ledger, null, 2)}
1795
+ `);
1796
+ }
1797
+ async function readProfileAlias(profileName) {
1798
+ const base = process.env["AGENTPROTO_HOME"] ?? join(homedir(), ".agentproto");
1799
+ const path = join(base, "config.json");
1800
+ try {
1801
+ const raw = await readFile(path, "utf8");
1802
+ const parsed = JSON.parse(raw);
1803
+ const aliased = parsed.profileAliases?.[profileName];
1804
+ return typeof aliased === "string" ? aliased : null;
1805
+ } catch {
1806
+ return null;
1807
+ }
1808
+ }
1508
1809
 
1509
1810
  // src/commands/install.ts
1510
1811
  async function runInstall(args) {
1812
+ const slugPeek = args.find((a) => !a.startsWith("-"));
1813
+ if (slugPeek?.startsWith("runtime-profile/")) {
1814
+ return runInstallProfile(
1815
+ slugPeek,
1816
+ args.filter((a) => a !== slugPeek)
1817
+ );
1818
+ }
1511
1819
  const { values, positionals } = parseArgs({
1512
1820
  args: [...args],
1513
1821
  allowPositionals: true,
@@ -1800,7 +2108,7 @@ async function runDownloadInstaller(opts) {
1800
2108
  }
1801
2109
  if (extractCode !== 0) return extractCode;
1802
2110
  const srcBin = join(extractDir, opts.extractBin);
1803
- const binDir = process.env["AGENTPROTO_BIN_DIR"] ?? join(homedir4(), ".local", "bin");
2111
+ const binDir = process.env["AGENTPROTO_BIN_DIR"] ?? join(homedir5(), ".local", "bin");
1804
2112
  await mkdir(binDir, { recursive: true });
1805
2113
  const destBin = join(binDir, opts.extractBin.split("/").pop());
1806
2114
  const cpCode = await spawnInherit("cp", ["-p", srcBin, destBin]);
@@ -1826,19 +2134,19 @@ async function runDownloadInstaller(opts) {
1826
2134
  });
1827
2135
  }
1828
2136
  }
1829
- function homedir4() {
2137
+ function homedir5() {
1830
2138
  return process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/";
1831
2139
  }
1832
2140
  function spawnInherit(cmd, argv) {
1833
- return new Promise((resolve7, reject) => {
2141
+ return new Promise((resolve9, reject) => {
1834
2142
  const child = spawn(cmd, argv, { stdio: "inherit" });
1835
2143
  child.once("error", reject);
1836
- child.once("exit", (code) => resolve7(code ?? 0));
2144
+ child.once("exit", (code) => resolve9(code ?? 0));
1837
2145
  });
1838
2146
  }
1839
2147
  async function runVersionCheck(check) {
1840
2148
  if (!check) return { ok: false, message: "no version_check declared" };
1841
- return new Promise((resolve7) => {
2149
+ return new Promise((resolve9) => {
1842
2150
  const child = spawn("bash", ["-lc", check.cmd], {
1843
2151
  stdio: ["ignore", "pipe", "ignore"]
1844
2152
  });
@@ -1846,154 +2154,1382 @@ async function runVersionCheck(check) {
1846
2154
  child.stdout.on("data", (c) => {
1847
2155
  buf += c.toString("utf8");
1848
2156
  });
1849
- child.once("error", () => resolve7({ ok: false, message: "check failed" }));
1850
- child.once("exit", (code) => {
1851
- if (code !== 0) {
1852
- resolve7({ ok: false, message: `check exited ${code}` });
1853
- return;
1854
- }
1855
- const re = new RegExp(check.parse);
1856
- const m = buf.match(re);
1857
- if (!m || !m[1]) {
1858
- resolve7({ ok: false, message: "could not parse version" });
2157
+ child.once("error", () => resolve9({ ok: false, message: "check failed" }));
2158
+ child.once("exit", (code) => {
2159
+ if (code !== 0) {
2160
+ resolve9({ ok: false, message: `check exited ${code}` });
2161
+ return;
2162
+ }
2163
+ const re = new RegExp(check.parse);
2164
+ const m = buf.match(re);
2165
+ if (!m || !m[1]) {
2166
+ resolve9({ ok: false, message: "could not parse version" });
2167
+ return;
2168
+ }
2169
+ resolve9({ ok: true, message: `version ${m[1]}` });
2170
+ });
2171
+ });
2172
+ }
2173
+ var PLUGIN_MANIFEST_SCHEMA = "agentproto/plugin/v1";
2174
+ var AdapterEntrySchema = z.object({
2175
+ /** The `kind` string the manifest's substrate/dispatcher/etc. block uses. */
2176
+ kind: z.string().min(1),
2177
+ /**
2178
+ * Path to the entry module, relative to the plugin package root.
2179
+ * Resolved via the plugin's `package.json#main`/`exports` (i.e. you
2180
+ * can use a subpath like `./dist/substrates.mjs` or an export name
2181
+ * like `.` if the plugin re-exports everything from its root).
2182
+ */
2183
+ entry: z.string().min(1),
2184
+ /** Named export inside `entry` — the factory function. */
2185
+ export: z.string().min(1),
2186
+ /** Free-form description; shown by `agentproto plugins show`. */
2187
+ description: z.string().optional()
2188
+ }).loose();
2189
+ var SubstrateEntrySchema = AdapterEntrySchema.extend({
2190
+ /**
2191
+ * Free-form capability tags. Not gated by the kernel yet, but
2192
+ * surfaced by `agentproto plugins show` so users can see what the
2193
+ * substrate claims to support (mentions, reactions, visibility, …).
2194
+ */
2195
+ capabilities: z.array(z.string()).optional()
2196
+ });
2197
+ var PluginManifestSchema = z.object({
2198
+ schema: z.literal(PLUGIN_MANIFEST_SCHEMA),
2199
+ substrates: z.array(SubstrateEntrySchema).default([]),
2200
+ dispatchers: z.array(AdapterEntrySchema).default([]),
2201
+ executors: z.array(AdapterEntrySchema).default([]),
2202
+ stateStores: z.array(AdapterEntrySchema).default([])
2203
+ }).loose();
2204
+
2205
+ // src/registry/runtime.ts
2206
+ var substrates = /* @__PURE__ */ new Map();
2207
+ var dispatchers = /* @__PURE__ */ new Map();
2208
+ var executors = /* @__PURE__ */ new Map();
2209
+ var stateStores = /* @__PURE__ */ new Map();
2210
+ function registerSubstrate(kind, factory) {
2211
+ substrates.set(kind, factory);
2212
+ }
2213
+ function registerDispatcher(kind, factory) {
2214
+ dispatchers.set(kind, factory);
2215
+ }
2216
+ function registerExecutor(kind, factory) {
2217
+ executors.set(kind, factory);
2218
+ }
2219
+ function registerStateStore(kind, factory) {
2220
+ stateStores.set(kind, factory);
2221
+ }
2222
+ function getSubstrateFactory(kind) {
2223
+ return substrates.get(kind);
2224
+ }
2225
+ function getDispatcherFactory(kind) {
2226
+ return dispatchers.get(kind);
2227
+ }
2228
+ function getExecutorFactory(kind) {
2229
+ return executors.get(kind);
2230
+ }
2231
+ function getStateStoreFactory(kind) {
2232
+ return stateStores.get(kind);
2233
+ }
2234
+ function listRegisteredKinds() {
2235
+ return {
2236
+ substrates: [...substrates.keys()],
2237
+ dispatchers: [...dispatchers.keys()],
2238
+ executors: [...executors.keys()],
2239
+ stateStores: [...stateStores.keys()]
2240
+ };
2241
+ }
2242
+
2243
+ // src/registry/manifest-loader.ts
2244
+ async function loadPluginFromManifest(pluginId) {
2245
+ const result = await readPluginManifest(pluginId);
2246
+ if (!result) return null;
2247
+ const { manifest, packageRoot } = result;
2248
+ for (const sub of manifest.substrates) {
2249
+ const factory = await importFactory(
2250
+ packageRoot,
2251
+ pluginId,
2252
+ sub.entry,
2253
+ sub.export
2254
+ );
2255
+ registerSubstrate(sub.kind, factory);
2256
+ }
2257
+ for (const dis of manifest.dispatchers) {
2258
+ const factory = await importFactory(
2259
+ packageRoot,
2260
+ pluginId,
2261
+ dis.entry,
2262
+ dis.export
2263
+ );
2264
+ registerDispatcher(dis.kind, factory);
2265
+ }
2266
+ for (const exe of manifest.executors) {
2267
+ const factory = await importFactory(
2268
+ packageRoot,
2269
+ pluginId,
2270
+ exe.entry,
2271
+ exe.export
2272
+ );
2273
+ registerExecutor(exe.kind, factory);
2274
+ }
2275
+ for (const st of manifest.stateStores) {
2276
+ const factory = await importFactory(
2277
+ packageRoot,
2278
+ pluginId,
2279
+ st.entry,
2280
+ st.export
2281
+ );
2282
+ registerStateStore(st.kind, factory);
2283
+ }
2284
+ return manifest;
2285
+ }
2286
+ async function readPluginManifest(pluginId) {
2287
+ const packageJsonPath = resolvePluginPackageJson(pluginId);
2288
+ if (!packageJsonPath) return null;
2289
+ const packageRoot = dirname(packageJsonPath);
2290
+ const standalonePath = join(packageRoot, "agentproto.json");
2291
+ const standalone = await readJsonIfExists(standalonePath);
2292
+ if (standalone !== void 0) {
2293
+ return {
2294
+ manifest: PluginManifestSchema.parse(standalone),
2295
+ packageRoot
2296
+ };
2297
+ }
2298
+ const pkgJson = await readJsonIfExists(packageJsonPath);
2299
+ if (pkgJson && typeof pkgJson === "object" && pkgJson.agentproto) {
2300
+ return {
2301
+ manifest: PluginManifestSchema.parse(pkgJson.agentproto),
2302
+ packageRoot
2303
+ };
2304
+ }
2305
+ return null;
2306
+ }
2307
+ async function importFactory(packageRoot, pluginId, entry, exportName) {
2308
+ const abs = entry.startsWith(".") ? join(packageRoot, entry) : entry;
2309
+ const url = entry.startsWith(".") ? pathToFileURL(abs).href : entry;
2310
+ const mod = await import(url);
2311
+ const exported = mod[exportName];
2312
+ if (typeof exported !== "function") {
2313
+ throw new Error(
2314
+ `agentproto plugin '${pluginId}': manifest entry '${entry}' has no callable export '${exportName}' (got ${typeof exported}).`
2315
+ );
2316
+ }
2317
+ return exported;
2318
+ }
2319
+ function resolvePluginPackageJson(pluginId) {
2320
+ const candidates = [
2321
+ import.meta.url,
2322
+ pathToFileURL(join(process.cwd(), "package.json")).href
2323
+ ];
2324
+ for (const root of candidates) {
2325
+ try {
2326
+ return createRequire(root).resolve(`${pluginId}/package.json`);
2327
+ } catch {
2328
+ }
2329
+ }
2330
+ return null;
2331
+ }
2332
+ async function readJsonIfExists(path) {
2333
+ try {
2334
+ const raw = await readFile(path, "utf8");
2335
+ return JSON.parse(raw);
2336
+ } catch (err) {
2337
+ if (err.code === "ENOENT") return void 0;
2338
+ throw err;
2339
+ }
2340
+ }
2341
+
2342
+ // src/commands/plugins.ts
2343
+ var USAGE3 = `agentproto plugins \u2014 manage runtime plugins
2344
+
2345
+ Usage:
2346
+ agentproto plugins list Show enabled plugins + adapters
2347
+ agentproto plugins show <pkg> Print a plugin's manifest
2348
+ agentproto plugins install <pkg> npm i -g + add to config
2349
+ agentproto plugins uninstall <pkg> Remove from config (+ npm rm)
2350
+ agentproto plugins enable <pkg> Add to config (assume installed)
2351
+ agentproto plugins disable <pkg> Remove from config (keep installed)
2352
+ agentproto plugins --help
2353
+
2354
+ Plugin list lives in ~/.agentproto/config.json under \`plugins[]\`.
2355
+ `;
2356
+ async function runPlugins(args) {
2357
+ const sub = args[0];
2358
+ const rest = args.slice(1);
2359
+ switch (sub) {
2360
+ case void 0:
2361
+ case "-h":
2362
+ case "--help":
2363
+ process.stdout.write(USAGE3);
2364
+ return 0;
2365
+ case "list":
2366
+ return runList(rest);
2367
+ case "show":
2368
+ return runShow2(rest);
2369
+ case "install":
2370
+ return runInstall2(rest);
2371
+ case "uninstall":
2372
+ return runUninstall(rest);
2373
+ case "enable":
2374
+ return runEnable(rest);
2375
+ case "disable":
2376
+ return runDisable(rest);
2377
+ default:
2378
+ process.stderr.write(
2379
+ `agentproto plugins: unknown subcommand '${sub}'.
2380
+
2381
+ ${USAGE3}`
2382
+ );
2383
+ return 2;
2384
+ }
2385
+ }
2386
+ async function runList(args) {
2387
+ const { values } = parseArgs({
2388
+ args: [...args],
2389
+ options: { json: { type: "boolean" } },
2390
+ strict: true
2391
+ });
2392
+ const cfg = await loadConfig2();
2393
+ const plugins = cfg.plugins ?? [];
2394
+ if (plugins.length === 0) {
2395
+ if (values.json) process.stdout.write("[]\n");
2396
+ else
2397
+ process.stdout.write(
2398
+ "agentproto plugins: no plugins enabled. Try `agentproto plugins install <pkg>`.\n"
2399
+ );
2400
+ return 0;
2401
+ }
2402
+ const entries = [];
2403
+ for (const id of plugins) {
2404
+ try {
2405
+ const result = await readPluginManifest(id);
2406
+ entries.push({ id, manifest: result?.manifest ?? null });
2407
+ } catch (err) {
2408
+ entries.push({
2409
+ id,
2410
+ manifest: null,
2411
+ error: err instanceof Error ? err.message : String(err)
2412
+ });
2413
+ }
2414
+ }
2415
+ if (values.json) {
2416
+ process.stdout.write(`${JSON.stringify(entries, null, 2)}
2417
+ `);
2418
+ return 0;
2419
+ }
2420
+ for (const e of entries) {
2421
+ process.stdout.write(`\u2022 ${e.id}
2422
+ `);
2423
+ if (e.error) {
2424
+ process.stdout.write(` error: ${e.error}
2425
+ `);
2426
+ continue;
2427
+ }
2428
+ if (!e.manifest) {
2429
+ process.stdout.write(` (no manifest \u2014 legacy side-effect plugin)
2430
+ `);
2431
+ continue;
2432
+ }
2433
+ printAdapterSummary("substrates", e.manifest.substrates);
2434
+ printAdapterSummary("dispatchers", e.manifest.dispatchers);
2435
+ printAdapterSummary("executors", e.manifest.executors);
2436
+ printAdapterSummary("state stores", e.manifest.stateStores);
2437
+ }
2438
+ return 0;
2439
+ }
2440
+ function printAdapterSummary(label, entries) {
2441
+ if (entries.length === 0) return;
2442
+ const kinds = entries.map((e) => e.kind).join(", ");
2443
+ process.stdout.write(` ${label}: ${kinds}
2444
+ `);
2445
+ }
2446
+ async function runShow2(args) {
2447
+ const { values, positionals } = parseArgs({
2448
+ args: [...args],
2449
+ allowPositionals: true,
2450
+ options: { json: { type: "boolean" } },
2451
+ strict: true
2452
+ });
2453
+ const pkg = positionals[0];
2454
+ if (!pkg) {
2455
+ process.stderr.write(
2456
+ "agentproto plugins show: missing <pkg>. Try: agentproto plugins show @guilde/agentproto-bridge\n"
2457
+ );
2458
+ return 2;
2459
+ }
2460
+ let result;
2461
+ try {
2462
+ result = await readPluginManifest(pkg);
2463
+ } catch (err) {
2464
+ process.stderr.write(
2465
+ `agentproto plugins show: ${err instanceof Error ? err.message : String(err)}
2466
+ `
2467
+ );
2468
+ return 1;
2469
+ }
2470
+ if (!result) {
2471
+ process.stderr.write(
2472
+ `agentproto plugins show: '${pkg}' is not installed (or doesn't declare an agentproto manifest).
2473
+ `
2474
+ );
2475
+ return 1;
2476
+ }
2477
+ if (values.json) {
2478
+ process.stdout.write(`${JSON.stringify(result.manifest, null, 2)}
2479
+ `);
2480
+ return 0;
2481
+ }
2482
+ const m = result.manifest;
2483
+ process.stdout.write(`${pkg}
2484
+ `);
2485
+ process.stdout.write(` schema: ${m.schema}
2486
+ `);
2487
+ printAdapterDetail("substrates", m.substrates);
2488
+ printAdapterDetail("dispatchers", m.dispatchers);
2489
+ printAdapterDetail("executors", m.executors);
2490
+ printAdapterDetail("state stores", m.stateStores);
2491
+ return 0;
2492
+ }
2493
+ function printAdapterDetail(label, entries) {
2494
+ if (entries.length === 0) return;
2495
+ process.stdout.write(` ${label}:
2496
+ `);
2497
+ for (const e of entries) {
2498
+ process.stdout.write(` \u2022 kind: ${e.kind}
2499
+ `);
2500
+ process.stdout.write(` entry: ${e.entry} \u2192 ${e.export}
2501
+ `);
2502
+ const caps = "capabilities" in e ? e.capabilities : void 0;
2503
+ if (Array.isArray(caps) && caps.length > 0) {
2504
+ process.stdout.write(` capabilities: ${caps.join(", ")}
2505
+ `);
2506
+ }
2507
+ if (e.description) {
2508
+ process.stdout.write(` ${e.description}
2509
+ `);
2510
+ }
2511
+ }
2512
+ }
2513
+ async function runInstall2(args) {
2514
+ const { values, positionals } = parseArgs({
2515
+ args: [...args],
2516
+ allowPositionals: true,
2517
+ options: {
2518
+ local: { type: "boolean" },
2519
+ "skip-npm": { type: "boolean" }
2520
+ },
2521
+ strict: true
2522
+ });
2523
+ const pkg = positionals[0];
2524
+ if (!pkg) {
2525
+ process.stderr.write("agentproto plugins install: missing <pkg>.\n");
2526
+ return 2;
2527
+ }
2528
+ if (!values["skip-npm"]) {
2529
+ const code = await spawnInherit2("npm", [
2530
+ "install",
2531
+ values.local ? "" : "-g",
2532
+ pkg
2533
+ ].filter(Boolean));
2534
+ if (code !== 0) {
2535
+ process.stderr.write(
2536
+ `agentproto plugins install: npm failed with exit ${code}; config not modified.
2537
+ `
2538
+ );
2539
+ return code;
2540
+ }
2541
+ }
2542
+ await addToConfig(pkg);
2543
+ process.stdout.write(`agentproto plugins: enabled '${pkg}'.
2544
+ `);
2545
+ return 0;
2546
+ }
2547
+ async function runUninstall(args) {
2548
+ const { values, positionals } = parseArgs({
2549
+ args: [...args],
2550
+ allowPositionals: true,
2551
+ options: {
2552
+ local: { type: "boolean" },
2553
+ "skip-npm": { type: "boolean" }
2554
+ },
2555
+ strict: true
2556
+ });
2557
+ const pkg = positionals[0];
2558
+ if (!pkg) {
2559
+ process.stderr.write("agentproto plugins uninstall: missing <pkg>.\n");
2560
+ return 2;
2561
+ }
2562
+ await removeFromConfig(pkg);
2563
+ if (!values["skip-npm"]) {
2564
+ const code = await spawnInherit2("npm", [
2565
+ "uninstall",
2566
+ values.local ? "" : "-g",
2567
+ pkg
2568
+ ].filter(Boolean));
2569
+ if (code !== 0) {
2570
+ process.stderr.write(
2571
+ `agentproto plugins uninstall: removed from config but npm uninstall failed with exit ${code}.
2572
+ `
2573
+ );
2574
+ return code;
2575
+ }
2576
+ }
2577
+ process.stdout.write(`agentproto plugins: disabled '${pkg}'.
2578
+ `);
2579
+ return 0;
2580
+ }
2581
+ async function runEnable(args) {
2582
+ const [pkg] = args;
2583
+ if (!pkg) {
2584
+ process.stderr.write("agentproto plugins enable: missing <pkg>.\n");
2585
+ return 2;
2586
+ }
2587
+ await addToConfig(pkg);
2588
+ process.stdout.write(`agentproto plugins: enabled '${pkg}'.
2589
+ `);
2590
+ return 0;
2591
+ }
2592
+ async function runDisable(args) {
2593
+ const [pkg] = args;
2594
+ if (!pkg) {
2595
+ process.stderr.write("agentproto plugins disable: missing <pkg>.\n");
2596
+ return 2;
2597
+ }
2598
+ await removeFromConfig(pkg);
2599
+ process.stdout.write(`agentproto plugins: disabled '${pkg}'.
2600
+ `);
2601
+ return 0;
2602
+ }
2603
+ function configPath() {
2604
+ const base = process.env["AGENTPROTO_HOME"] ?? join(homedir(), ".agentproto");
2605
+ return join(base, "config.json");
2606
+ }
2607
+ async function loadConfig2() {
2608
+ try {
2609
+ const raw = await readFile(configPath(), "utf8");
2610
+ return JSON.parse(raw);
2611
+ } catch (err) {
2612
+ if (err.code === "ENOENT") return {};
2613
+ throw err;
2614
+ }
2615
+ }
2616
+ async function saveConfig2(cfg) {
2617
+ const path = configPath();
2618
+ await mkdir(dirname(path), { recursive: true });
2619
+ await writeFile(path, `${JSON.stringify(cfg, null, 2)}
2620
+ `);
2621
+ }
2622
+ async function addToConfig(pkg) {
2623
+ const cfg = await loadConfig2();
2624
+ const plugins = cfg.plugins ?? [];
2625
+ if (!plugins.includes(pkg)) plugins.push(pkg);
2626
+ cfg.plugins = plugins;
2627
+ await saveConfig2(cfg);
2628
+ }
2629
+ async function removeFromConfig(pkg) {
2630
+ const cfg = await loadConfig2();
2631
+ cfg.plugins = (cfg.plugins ?? []).filter((p) => p !== pkg);
2632
+ await saveConfig2(cfg);
2633
+ }
2634
+ function spawnInherit2(cmd, argv) {
2635
+ return new Promise((resolveP, rejectP) => {
2636
+ const child = spawn(cmd, argv, { stdio: "inherit" });
2637
+ child.once("error", rejectP);
2638
+ child.once("exit", (code) => resolveP(code ?? 0));
2639
+ });
2640
+ }
2641
+
2642
+ // src/util/stdin.ts
2643
+ async function readStdinIfPiped() {
2644
+ if (process.stdin.isTTY) return null;
2645
+ const chunks = [];
2646
+ for await (const chunk of process.stdin) {
2647
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2648
+ }
2649
+ const text3 = Buffer.concat(chunks).toString("utf8").trim();
2650
+ return text3.length > 0 ? text3 : null;
2651
+ }
2652
+
2653
+ // src/commands/run.ts
2654
+ async function runRun(args) {
2655
+ const { values, positionals } = parseArgs({
2656
+ args: [...args],
2657
+ allowPositionals: true,
2658
+ strict: true,
2659
+ options: {
2660
+ cwd: { type: "string" },
2661
+ prompt: { type: "string", short: "p" },
2662
+ resume: { type: "string" },
2663
+ json: { type: "boolean" }
2664
+ }
2665
+ });
2666
+ const slug = positionals[0];
2667
+ if (!slug) {
2668
+ process.stderr.write(
2669
+ "agentproto run: missing adapter slug. Try: agentproto run claude-code\n"
2670
+ );
2671
+ return 2;
2672
+ }
2673
+ const cwd = values.cwd ? resolve(values.cwd) : process.cwd();
2674
+ const promptArg = values.prompt ?? await readStdinIfPiped();
2675
+ if (!promptArg) {
2676
+ process.stderr.write(
2677
+ "agentproto run: no prompt provided. Pass --prompt or pipe one over stdin.\n"
2678
+ );
2679
+ return 2;
2680
+ }
2681
+ const adapter = await resolveAdapter(slug);
2682
+ const runtime = createAgentCliRuntime(adapter.handle);
2683
+ const controller = new AbortController();
2684
+ const onSignal = (sig) => {
2685
+ process.stderr.write(`
2686
+ agentproto: received ${sig}, cancelling\u2026
2687
+ `);
2688
+ controller.abort();
2689
+ };
2690
+ process.once("SIGINT", onSignal);
2691
+ process.once("SIGTERM", onSignal);
2692
+ let session = null;
2693
+ try {
2694
+ session = await runtime.start({
2695
+ cwd,
2696
+ signal: controller.signal,
2697
+ resumeSessionId: values.resume
2698
+ });
2699
+ const printer = values.json ? printJson : printPretty;
2700
+ let exit = 0;
2701
+ for await (const ev of session.send(promptArg)) {
2702
+ printer(ev);
2703
+ if (ev.kind === "turn-end" && ev.reason !== "completed") exit = 1;
2704
+ if (ev.kind === "error") exit = 1;
2705
+ }
2706
+ return exit;
2707
+ } finally {
2708
+ process.off("SIGINT", onSignal);
2709
+ process.off("SIGTERM", onSignal);
2710
+ if (session) await session.close().catch(() => {
2711
+ });
2712
+ }
2713
+ }
2714
+ function printJson(ev) {
2715
+ process.stdout.write(`${JSON.stringify(ev)}
2716
+ `);
2717
+ }
2718
+ function printPretty(ev) {
2719
+ switch (ev.kind) {
2720
+ case "text-delta":
2721
+ process.stdout.write(ev.text);
2722
+ break;
2723
+ case "thought":
2724
+ process.stderr.write(`\x1B[2m[thought] ${ev.text}\x1B[0m
2725
+ `);
2726
+ break;
2727
+ case "tool-call":
2728
+ process.stderr.write(`\x1B[36m[tool] ${ev.toolName}\x1B[0m
2729
+ `);
2730
+ break;
2731
+ case "tool-result":
2732
+ if (ev.isError)
2733
+ process.stderr.write(`\x1B[31m[tool-error]\x1B[0m
2734
+ `);
2735
+ break;
2736
+ case "agent-prompt":
2737
+ process.stderr.write(`\x1B[33m[agent-prompt: needs input]\x1B[0m
2738
+ `);
2739
+ break;
2740
+ case "turn-end":
2741
+ process.stdout.write(`
2742
+ \x1B[2m[turn-end: ${ev.reason}]\x1B[0m
2743
+ `);
2744
+ break;
2745
+ case "error": {
2746
+ const code = typeof ev.error.code === "number" ? ` (code ${ev.error.code})` : "";
2747
+ process.stderr.write(
2748
+ `\x1B[31m[error]${code} ${ev.error.message}\x1B[0m
2749
+ `
2750
+ );
2751
+ const data = ev.error.data;
2752
+ if (data && typeof data === "object") {
2753
+ const stderr = data.stderr;
2754
+ if (typeof stderr === "string" && stderr.trim()) {
2755
+ process.stderr.write(`\x1B[2m\u2500\u2500 child stderr \u2500\u2500
2756
+ ${stderr}\x1B[0m
2757
+ `);
2758
+ }
2759
+ const rest = { ...data };
2760
+ delete rest.stderr;
2761
+ if (Object.keys(rest).length > 0) {
2762
+ process.stderr.write(
2763
+ `\x1B[2m\u2500\u2500 error.data \u2500\u2500
2764
+ ${JSON.stringify(rest, null, 2)}\x1B[0m
2765
+ `
2766
+ );
2767
+ }
2768
+ }
2769
+ break;
2770
+ }
2771
+ }
2772
+ }
2773
+ async function runTurn(ports, options = {}) {
2774
+ const historyLimit = options.historyLimit ?? 30;
2775
+ const cycleId = newCycleId();
2776
+ const cycleStart = Date.now();
2777
+ emit(ports.telemetry, {
2778
+ kind: "cycle.started",
2779
+ cycleId,
2780
+ at: nowIso(),
2781
+ ...options.since !== void 0 ? { since: options.since } : {}
2782
+ });
2783
+ const readStart = Date.now();
2784
+ const all = await ports.substrate.read(options.since);
2785
+ const recentTurns = all.slice(-historyLimit);
2786
+ emit(ports.telemetry, {
2787
+ kind: "substrate.read",
2788
+ cycleId,
2789
+ at: nowIso(),
2790
+ substrateKind: ports.substrate.kind,
2791
+ turnCount: recentTurns.length,
2792
+ durationMs: Date.now() - readStart
2793
+ });
2794
+ const dispatchStart = Date.now();
2795
+ const selected = await ports.dispatcher.selectNext({
2796
+ recentTurns,
2797
+ participants: ports.participants
2798
+ });
2799
+ emit(ports.telemetry, {
2800
+ kind: "dispatch.decided",
2801
+ cycleId,
2802
+ at: nowIso(),
2803
+ dispatcherKind: ports.dispatcher.kind,
2804
+ selected,
2805
+ durationMs: Date.now() - dispatchStart
2806
+ });
2807
+ if (selected.length === 0) {
2808
+ await ports.lifecycle?.onIdle?.();
2809
+ emit(ports.telemetry, { kind: "cycle.idle", cycleId, at: nowIso() });
2810
+ emit(ports.telemetry, {
2811
+ kind: "cycle.finished",
2812
+ cycleId,
2813
+ at: nowIso(),
2814
+ outcome: "idle",
2815
+ turnsAppended: 0,
2816
+ durationMs: Date.now() - cycleStart
2817
+ });
2818
+ return { cycle: "idle", selected: [], turnsAppended: [] };
2819
+ }
2820
+ const triggerTurn = recentTurns[recentTurns.length - 1];
2821
+ if (!triggerTurn) {
2822
+ await ports.lifecycle?.onIdle?.();
2823
+ emit(ports.telemetry, { kind: "cycle.idle", cycleId, at: nowIso() });
2824
+ emit(ports.telemetry, {
2825
+ kind: "cycle.finished",
2826
+ cycleId,
2827
+ at: nowIso(),
2828
+ outcome: "idle",
2829
+ turnsAppended: 0,
2830
+ durationMs: Date.now() - cycleStart
2831
+ });
2832
+ return { cycle: "idle", selected: [], turnsAppended: [] };
2833
+ }
2834
+ const appended = [];
2835
+ for (const participantId of selected) {
2836
+ const participant = findParticipant(ports.participants, participantId);
2837
+ if (!participant) {
2838
+ continue;
2839
+ }
2840
+ const executor = ports.executors.get(participant.executor);
2841
+ if (!executor) {
2842
+ continue;
2843
+ }
2844
+ await ports.lifecycle?.onMention?.(participantId, triggerTurn);
2845
+ const state = await ports.state.read(participantId);
2846
+ emit(ports.telemetry, {
2847
+ kind: "participant.started",
2848
+ cycleId,
2849
+ at: nowIso(),
2850
+ participantId,
2851
+ executorKind: participant.executor
2852
+ });
2853
+ const execStart = Date.now();
2854
+ let output2;
2855
+ try {
2856
+ output2 = await executor.executeTurn({
2857
+ participant,
2858
+ recentTurns,
2859
+ triggerTurn,
2860
+ state,
2861
+ signal: options.signal
2862
+ });
2863
+ } catch (err) {
2864
+ emit(ports.telemetry, {
2865
+ kind: "participant.failed",
2866
+ cycleId,
2867
+ at: nowIso(),
2868
+ participantId,
2869
+ executorKind: participant.executor,
2870
+ error: err instanceof Error ? err.message : String(err)
2871
+ });
2872
+ throw err;
2873
+ }
2874
+ emit(ports.telemetry, {
2875
+ kind: "participant.finished",
2876
+ cycleId,
2877
+ at: nowIso(),
2878
+ participantId,
2879
+ executorKind: participant.executor,
2880
+ durationMs: Date.now() - execStart,
2881
+ contentLength: output2.content.length
2882
+ });
2883
+ const turn = await ports.substrate.append({
2884
+ participantId,
2885
+ content: output2.content,
2886
+ meta: output2.meta
2887
+ });
2888
+ appended.push(turn);
2889
+ emit(ports.telemetry, {
2890
+ kind: "substrate.appended",
2891
+ cycleId,
2892
+ at: nowIso(),
2893
+ turnId: turn.id,
2894
+ participantId
2895
+ });
2896
+ if (output2.stateUpdate) {
2897
+ await ports.state.write(participantId, output2.stateUpdate);
2898
+ emit(ports.telemetry, {
2899
+ kind: "state.written",
2900
+ cycleId,
2901
+ at: nowIso(),
2902
+ participantId
2903
+ });
2904
+ }
2905
+ await ports.lifecycle?.onTurnEnd?.(turn);
2906
+ }
2907
+ emit(ports.telemetry, {
2908
+ kind: "cycle.finished",
2909
+ cycleId,
2910
+ at: nowIso(),
2911
+ outcome: "executed",
2912
+ turnsAppended: appended.length,
2913
+ durationMs: Date.now() - cycleStart
2914
+ });
2915
+ return { cycle: "executed", selected, turnsAppended: appended };
2916
+ }
2917
+ function findParticipant(participants, id) {
2918
+ for (const p of participants) {
2919
+ if (p.id === id) return p;
2920
+ }
2921
+ return void 0;
2922
+ }
2923
+ function emit(telemetry, event) {
2924
+ if (!telemetry) return;
2925
+ try {
2926
+ telemetry.emit(event);
2927
+ } catch {
2928
+ }
2929
+ }
2930
+ function nowIso() {
2931
+ return (/* @__PURE__ */ new Date()).toISOString();
2932
+ }
2933
+ function newCycleId() {
2934
+ return `c_${randomBytes(6).toString("hex")}`;
2935
+ }
2936
+ var MULTI_AGENT_RUNTIME_SCHEMA = "agentruntimes/v1";
2937
+ var MULTI_AGENT_RUNTIME_KIND = "MultiAgentRuntime";
2938
+ var AdapterConfigSchema = z.object({
2939
+ kind: z.string().min(1)
2940
+ }).loose();
2941
+ var ParticipantManifestSchema = z.object({
2942
+ id: z.string().min(1),
2943
+ executor: z.string().min(1),
2944
+ displayName: z.string().min(1).optional(),
2945
+ role: z.string().optional(),
2946
+ meta: z.record(z.string(), z.unknown()).optional()
2947
+ }).loose();
2948
+ var MultiAgentRuntimeManifestSchema = z.object({
2949
+ schema: z.literal(MULTI_AGENT_RUNTIME_SCHEMA),
2950
+ kind: z.literal(MULTI_AGENT_RUNTIME_KIND),
2951
+ id: z.string().min(1),
2952
+ participants: z.array(ParticipantManifestSchema).min(1),
2953
+ substrate: AdapterConfigSchema,
2954
+ dispatcher: AdapterConfigSchema,
2955
+ state: AdapterConfigSchema.optional(),
2956
+ lifecycle: z.object({
2957
+ onTurnEnd: z.boolean().optional(),
2958
+ onMention: z.boolean().optional(),
2959
+ onIdle: z.boolean().optional()
2960
+ }).optional()
2961
+ }).loose();
2962
+ async function loadManifest(path) {
2963
+ const abs = resolve(path);
2964
+ const raw = await readFile(abs, "utf8");
2965
+ const parsed = matter3(raw);
2966
+ const manifest = MultiAgentRuntimeManifestSchema.parse(parsed.data);
2967
+ return {
2968
+ manifest,
2969
+ body: parsed.content,
2970
+ path: abs,
2971
+ baseDir: dirname(abs)
2972
+ };
2973
+ }
2974
+
2975
+ // ../agent-runtime/dist/adapters/telemetry.mjs
2976
+ function stderrTelemetry(options = {}) {
2977
+ const prefix = options.prefix ?? "agentproto: ";
2978
+ return {
2979
+ emit(event) {
2980
+ if (options.exclude?.has(event.kind)) return;
2981
+ if (options.include && !options.include.has(event.kind)) return;
2982
+ process.stderr.write(`${prefix}${formatEvent(event)}
2983
+ `);
2984
+ }
2985
+ };
2986
+ }
2987
+ function formatEvent(event) {
2988
+ switch (event.kind) {
2989
+ case "cycle.started":
2990
+ return `${event.cycleId} cycle.started${event.since !== void 0 ? ` since=${event.since}` : ""}`;
2991
+ case "substrate.read":
2992
+ return `${event.cycleId} substrate.read ${event.substrateKind} turns=${event.turnCount} ${event.durationMs}ms`;
2993
+ case "dispatch.decided":
2994
+ return `${event.cycleId} dispatch.decided ${event.dispatcherKind} selected=[${event.selected.join(",") || "(none)"}] ${event.durationMs}ms`;
2995
+ case "participant.started":
2996
+ return `${event.cycleId} participant.started ${event.participantId} (${event.executorKind})`;
2997
+ case "participant.finished":
2998
+ return `${event.cycleId} participant.finished ${event.participantId} ${event.durationMs}ms content=${event.contentLength}b`;
2999
+ case "participant.failed":
3000
+ return `${event.cycleId} participant.failed ${event.participantId} \u2014 ${event.error}`;
3001
+ case "substrate.appended":
3002
+ return `${event.cycleId} substrate.appended turn=${event.turnId} by=${event.participantId}`;
3003
+ case "state.written":
3004
+ return `${event.cycleId} state.written ${event.participantId}`;
3005
+ case "cycle.idle":
3006
+ return `${event.cycleId} cycle.idle`;
3007
+ case "cycle.finished":
3008
+ return `${event.cycleId} cycle.finished ${event.outcome} appended=${event.turnsAppended} ${event.durationMs}ms`;
3009
+ default: {
3010
+ const _exhaustive = event;
3011
+ return JSON.stringify(_exhaustive);
3012
+ }
3013
+ }
3014
+ }
3015
+ var HEADER_RE = /^=== TURN id=([^\s]+) participant=([^\s]+) ts=([^\s]+) ===$/;
3016
+ var FileSubstrate = class {
3017
+ constructor(opts) {
3018
+ this.opts = opts;
3019
+ }
3020
+ kind = "file";
3021
+ async append(input2) {
3022
+ const timestamp = input2.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
3023
+ const id = hashTurnId(input2.participantId, timestamp, input2.content);
3024
+ const turn = {
3025
+ id,
3026
+ participantId: input2.participantId,
3027
+ timestamp,
3028
+ content: input2.content,
3029
+ meta: input2.meta
3030
+ };
3031
+ await ensureDir2(this.opts.path);
3032
+ const block = formatTurnBlock(turn);
3033
+ await appendFile(this.opts.path, block, "utf8");
3034
+ return turn;
3035
+ }
3036
+ async read(since) {
3037
+ let raw;
3038
+ try {
3039
+ raw = await readFile(this.opts.path, "utf8");
3040
+ } catch (err) {
3041
+ if (isNotFound(err)) return [];
3042
+ throw err;
3043
+ }
3044
+ const turns = parseJournal(raw);
3045
+ if (since === void 0) return turns;
3046
+ const cutoff = turns.findIndex((t) => t.id === since);
3047
+ if (cutoff === -1) return turns;
3048
+ return turns.slice(cutoff + 1);
3049
+ }
3050
+ };
3051
+ function formatTurnBlock(turn) {
3052
+ const header = `=== TURN id=${turn.id} participant=${turn.participantId} ts=${turn.timestamp} ===
3053
+ `;
3054
+ const body = turn.content.endsWith("\n") ? turn.content : `${turn.content}
3055
+ `;
3056
+ return `${header}${body}`;
3057
+ }
3058
+ function parseJournal(raw) {
3059
+ const lines = raw.split("\n");
3060
+ const turns = [];
3061
+ let current = null;
3062
+ for (const line of lines) {
3063
+ const match = HEADER_RE.exec(line);
3064
+ if (match && match[1] && match[2] && match[3]) {
3065
+ if (current) turns.push(materialise(current));
3066
+ current = { id: match[1], pid: match[2], ts: match[3], buf: [] };
3067
+ continue;
3068
+ }
3069
+ if (current) current.buf.push(line);
3070
+ }
3071
+ if (current) turns.push(materialise(current));
3072
+ return turns;
3073
+ }
3074
+ function materialise(c) {
3075
+ let body = c.buf.join("\n");
3076
+ while (body.endsWith("\n")) body = body.slice(0, -1);
3077
+ return {
3078
+ id: c.id,
3079
+ participantId: c.pid,
3080
+ timestamp: c.ts,
3081
+ content: body
3082
+ };
3083
+ }
3084
+ function hashTurnId(pid, ts, content) {
3085
+ const h = createHash("sha256");
3086
+ h.update(pid);
3087
+ h.update("\0");
3088
+ h.update(ts);
3089
+ h.update("\0");
3090
+ h.update(content);
3091
+ return `t_${h.digest("hex").slice(0, 12)}`;
3092
+ }
3093
+ async function ensureDir2(path) {
3094
+ const dir = dirname(path);
3095
+ try {
3096
+ await stat(dir);
3097
+ } catch (err) {
3098
+ if (isNotFound(err)) {
3099
+ await mkdir(dir, { recursive: true });
3100
+ return;
3101
+ }
3102
+ throw err;
3103
+ }
3104
+ }
3105
+ function isNotFound(err) {
3106
+ return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
3107
+ }
3108
+
3109
+ // ../agent-runtime/dist/adapters/dispatcher-mention.mjs
3110
+ function textContainsMention(text3, name) {
3111
+ if (text3.includes(`@${name}`)) return true;
3112
+ if (name.includes(" ")) {
3113
+ const firstName = name.split(" ")[0]?.trim();
3114
+ if (!firstName) return false;
3115
+ const regex = new RegExp(`@${firstName}(?!\\w)`, "i");
3116
+ return regex.test(text3);
3117
+ }
3118
+ return false;
3119
+ }
3120
+ var MentionDispatcher = class {
3121
+ kind = "mention";
3122
+ lastProcessedTriggerId;
3123
+ async selectNext(input2) {
3124
+ const trigger = input2.recentTurns[input2.recentTurns.length - 1];
3125
+ if (!trigger) return [];
3126
+ if (trigger.id === this.lastProcessedTriggerId) return [];
3127
+ const text3 = trigger.content;
3128
+ const selected = [];
3129
+ for (const p of input2.participants) {
3130
+ if (p.id === trigger.participantId) continue;
3131
+ if (textContainsMention(text3, p.displayName)) {
3132
+ selected.push(p.id);
3133
+ }
3134
+ }
3135
+ if (selected.length > 0) {
3136
+ this.lastProcessedTriggerId = trigger.id;
3137
+ }
3138
+ return selected;
3139
+ }
3140
+ };
3141
+ var FileStateStore = class {
3142
+ constructor(opts) {
3143
+ this.opts = opts;
3144
+ }
3145
+ kind = "fs";
3146
+ async read(participantId) {
3147
+ const path = this.pathFor(participantId);
3148
+ try {
3149
+ const raw = await readFile(path, "utf8");
3150
+ return JSON.parse(raw);
3151
+ } catch (err) {
3152
+ if (isNotFound2(err)) return Object.freeze({});
3153
+ throw err;
3154
+ }
3155
+ }
3156
+ async write(participantId, state) {
3157
+ await ensureDir3(this.opts.dir);
3158
+ const path = this.pathFor(participantId);
3159
+ await writeFile(path, JSON.stringify(state, null, 2), "utf8");
3160
+ }
3161
+ pathFor(participantId) {
3162
+ const safe = participantId.replace(/[^a-zA-Z0-9._-]/g, "_");
3163
+ return resolve(this.opts.dir, `${safe}.json`);
3164
+ }
3165
+ };
3166
+ async function ensureDir3(dir) {
3167
+ try {
3168
+ await stat(dir);
3169
+ } catch (err) {
3170
+ if (isNotFound2(err)) {
3171
+ await mkdir(dir, { recursive: true });
3172
+ return;
3173
+ }
3174
+ throw err;
3175
+ }
3176
+ }
3177
+ function isNotFound2(err) {
3178
+ return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
3179
+ }
3180
+ var AgentCliParticipant = class {
3181
+ constructor(opts) {
3182
+ this.opts = opts;
3183
+ }
3184
+ kind = "agent-cli";
3185
+ async executeTurn(input2) {
3186
+ const prompt = await assemblePrompt(input2);
3187
+ const stdout = await spawnWithStdin({
3188
+ command: this.opts.command,
3189
+ args: this.opts.args ?? [],
3190
+ cwd: this.opts.cwd ?? process.cwd(),
3191
+ timeoutMs: this.opts.timeoutMs ?? 9e4,
3192
+ stdin: prompt,
3193
+ signal: input2.signal
3194
+ });
3195
+ const parsed = this.opts.parseOutput?.(stdout) ?? null;
3196
+ const content = parsed ?? stdout.trimEnd();
3197
+ return { content };
3198
+ }
3199
+ };
3200
+ async function assemblePrompt(input2) {
3201
+ const roleText = input2.participant.role ? await loadRole(input2.participant.role) : "";
3202
+ const transcript = input2.recentTurns.map((t) => `[${t.participantId}] ${t.content}`).join("\n\n");
3203
+ return [
3204
+ roleText && `# Your role
3205
+
3206
+ ${roleText}`,
3207
+ `# Recent conversation
3208
+
3209
+ ${transcript}`,
3210
+ `# Your turn
3211
+
3212
+ You are ${input2.participant.displayName}. The latest message in the conversation triggered you (most likely because it mentions you). Read the transcript above and reply in character. Keep it conversational unless the trigger asks for detailed work. Output only your reply \u2014 no preamble, no role labels, no quotes around the response.`
3213
+ ].filter(Boolean).join("\n\n");
3214
+ }
3215
+ var ROLE_FILE_EXTENSIONS = [".md", ".markdown", ".txt"];
3216
+ async function loadRole(roleField) {
3217
+ if (!looksLikeRoleFile(roleField)) return roleField;
3218
+ try {
3219
+ const raw = await readFile(roleField, "utf8");
3220
+ const parsed = matter3(raw);
3221
+ return parsed.content.trim();
3222
+ } catch (err) {
3223
+ const code = err.code;
3224
+ process.stderr.write(
3225
+ `agent-cli participant: role path '${roleField}' not readable (${code ?? "unknown"}); using the literal string as inline role text.
3226
+ `
3227
+ );
3228
+ return roleField;
3229
+ }
3230
+ }
3231
+ function looksLikeRoleFile(s) {
3232
+ const lower = s.toLowerCase();
3233
+ return ROLE_FILE_EXTENSIONS.some((ext) => lower.endsWith(ext));
3234
+ }
3235
+ async function spawnWithStdin(args) {
3236
+ return new Promise((resolveP, rejectP) => {
3237
+ const proc = spawn(args.command, [...args.args], {
3238
+ cwd: args.cwd,
3239
+ stdio: ["pipe", "pipe", "pipe"]
3240
+ });
3241
+ let stdout = "";
3242
+ let stderr = "";
3243
+ const onAbort = () => proc.kill("SIGTERM");
3244
+ args.signal?.addEventListener("abort", onAbort);
3245
+ const timer = setTimeout(() => {
3246
+ proc.kill("SIGTERM");
3247
+ }, args.timeoutMs);
3248
+ proc.stdout.on("data", (chunk) => {
3249
+ stdout += chunk.toString("utf8");
3250
+ });
3251
+ proc.stderr.on("data", (chunk) => {
3252
+ stderr += chunk.toString("utf8");
3253
+ });
3254
+ proc.on("error", (err) => {
3255
+ clearTimeout(timer);
3256
+ args.signal?.removeEventListener("abort", onAbort);
3257
+ rejectP(err);
3258
+ });
3259
+ proc.on("close", (code) => {
3260
+ clearTimeout(timer);
3261
+ args.signal?.removeEventListener("abort", onAbort);
3262
+ if (code === 0) {
3263
+ resolveP(stdout);
1859
3264
  return;
1860
3265
  }
1861
- resolve7({ ok: true, message: `version ${m[1]}` });
3266
+ rejectP(
3267
+ new Error(
3268
+ `agent-cli participant "${args.command}" exited with code ${code}: ${stderr.trim() || "(no stderr)"}`
3269
+ )
3270
+ );
1862
3271
  });
3272
+ proc.stdin.write(args.stdin);
3273
+ proc.stdin.end();
1863
3274
  });
1864
3275
  }
3276
+ function parseClaudeJsonOutput(stdout) {
3277
+ try {
3278
+ const parsed = JSON.parse(stdout);
3279
+ if (typeof parsed === "object" && parsed !== null && "result" in parsed && typeof parsed.result === "string") {
3280
+ return parsed.result;
3281
+ }
3282
+ return null;
3283
+ } catch {
3284
+ return null;
3285
+ }
3286
+ }
1865
3287
 
1866
- // src/util/stdin.ts
1867
- async function readStdinIfPiped() {
1868
- if (process.stdin.isTTY) return null;
1869
- const chunks = [];
1870
- for await (const chunk of process.stdin) {
1871
- chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
3288
+ // src/registry/builtins.ts
3289
+ function registerBuiltins() {
3290
+ registerSubstrate("file", (cfg, ctx) => {
3291
+ const path = typeof cfg.path === "string" ? cfg.path : ".runtime/conversation.md";
3292
+ return new FileSubstrate({ path: resolve(ctx.baseDir, path) });
3293
+ });
3294
+ registerDispatcher("mention", () => new MentionDispatcher());
3295
+ registerStateStore("fs", (cfg, ctx) => {
3296
+ const dir = typeof cfg.dir === "string" ? cfg.dir : ".runtime/state";
3297
+ return new FileStateStore({ dir: resolve(ctx.baseDir, dir) });
3298
+ });
3299
+ registerExecutor("agent-cli", (cfg) => buildAgentCli(cfg));
3300
+ }
3301
+ function buildAgentCli(cfg) {
3302
+ const command = typeof cfg.command === "string" ? cfg.command : "claude";
3303
+ const args = Array.isArray(cfg.args) ? cfg.args.filter((a) => typeof a === "string") : ["--print", "--output-format=json"];
3304
+ const useClaudeJson = cfg.parseJson !== false && command === "claude";
3305
+ return new AgentCliParticipant({
3306
+ command,
3307
+ args,
3308
+ parseOutput: useClaudeJson ? parseClaudeJsonOutput : void 0
3309
+ });
3310
+ }
3311
+ async function loadPluginsFromConfig() {
3312
+ const path = configPath2();
3313
+ try {
3314
+ const raw = await readFile(path, "utf8");
3315
+ const parsed = JSON.parse(raw);
3316
+ return parsed.plugins ?? [];
3317
+ } catch (err) {
3318
+ if (err.code === "ENOENT") return [];
3319
+ process.stderr.write(
3320
+ `agentproto: failed to read ${path} \u2014 ${err instanceof Error ? err.message : String(err)}
3321
+ `
3322
+ );
3323
+ return [];
1872
3324
  }
1873
- const text3 = Buffer.concat(chunks).toString("utf8").trim();
1874
- return text3.length > 0 ? text3 : null;
3325
+ }
3326
+ async function loadPlugins(moduleIds) {
3327
+ for (const id of moduleIds) {
3328
+ try {
3329
+ const manifest = await loadPluginFromManifest(id);
3330
+ if (manifest === null) {
3331
+ await import(id);
3332
+ }
3333
+ } catch (err) {
3334
+ const msg = err instanceof Error ? err.message : String(err);
3335
+ process.stderr.write(
3336
+ `agentproto: plugin '${id}' failed to load \u2014 ${msg}
3337
+ `
3338
+ );
3339
+ }
3340
+ }
3341
+ }
3342
+ function configPath2() {
3343
+ const base = process.env["AGENTPROTO_HOME"] ?? join(homedir(), ".agentproto");
3344
+ return join(base, "config.json");
1875
3345
  }
1876
3346
 
1877
- // src/commands/run.ts
1878
- async function runRun(args) {
1879
- const { values, positionals } = parseArgs({
3347
+ // src/commands/run-swarm.ts
3348
+ async function runRunSwarm(args) {
3349
+ const { values } = parseArgs({
1880
3350
  args: [...args],
1881
- allowPositionals: true,
3351
+ allowPositionals: false,
1882
3352
  strict: true,
1883
3353
  options: {
1884
- cwd: { type: "string" },
1885
- prompt: { type: "string", short: "p" },
1886
- resume: { type: "string" },
1887
- json: { type: "boolean" }
3354
+ manifest: { type: "string", short: "m" },
3355
+ once: { type: "boolean" },
3356
+ interval: { type: "string" },
3357
+ verbose: { type: "boolean", short: "v" },
3358
+ plugin: { type: "string", multiple: true }
1888
3359
  }
1889
3360
  });
1890
- const slug = positionals[0];
1891
- if (!slug) {
3361
+ if (!values.manifest) {
1892
3362
  process.stderr.write(
1893
- "agentproto run: missing adapter slug. Try: agentproto run claude-code\n"
3363
+ "agentproto run-swarm: --manifest <path> is required.\n"
1894
3364
  );
1895
3365
  return 2;
1896
3366
  }
1897
- const cwd = values.cwd ? resolve(values.cwd) : process.cwd();
1898
- const promptArg = values.prompt ?? await readStdinIfPiped();
1899
- if (!promptArg) {
3367
+ registerBuiltins();
3368
+ const cliPlugins = values.plugin ?? [];
3369
+ const configPlugins = await loadPluginsFromConfig();
3370
+ await loadPlugins([...configPlugins, ...cliPlugins]);
3371
+ const loaded = await loadManifest(resolve(values.manifest));
3372
+ const verbose = values.verbose === true;
3373
+ const cleanups = [];
3374
+ const ctx = {
3375
+ baseDir: loaded.baseDir,
3376
+ registerCleanup: (fn) => cleanups.push(fn)
3377
+ };
3378
+ const telemetry = verbose ? stderrTelemetry({ prefix: "agentproto run-swarm: " }) : void 0;
3379
+ let ports;
3380
+ try {
3381
+ ports = await buildPorts(loaded, ctx, telemetry);
3382
+ } catch (err) {
1900
3383
  process.stderr.write(
1901
- "agentproto run: no prompt provided. Pass --prompt or pipe one over stdin.\n"
3384
+ `agentproto run-swarm: ${err instanceof Error ? err.message : String(err)}
3385
+ `
3386
+ );
3387
+ await runCleanups(cleanups);
3388
+ return 1;
3389
+ }
3390
+ const onceMode = values.once === true;
3391
+ const intervalMs = parseInterval(values.interval) ?? 2e3;
3392
+ if (verbose) {
3393
+ logVerbose(`loaded manifest "${loaded.manifest.id}" from ${loaded.path}`);
3394
+ logVerbose(
3395
+ `participants: ${ports.participants.map((p) => p.displayName).join(", ")}`
3396
+ );
3397
+ logVerbose(
3398
+ `substrate=${ports.substrate.kind} dispatcher=${ports.dispatcher.kind} state=${ports.state.kind}`
3399
+ );
3400
+ const registered = listRegisteredKinds();
3401
+ logVerbose(
3402
+ `registered: substrates=[${registered.substrates.join(",")}] dispatchers=[${registered.dispatchers.join(",")}] executors=[${registered.executors.join(",")}] stateStores=[${registered.stateStores.join(",")}]`
1902
3403
  );
1903
- return 2;
1904
3404
  }
1905
- const adapter = await resolveAdapter(slug);
1906
- const runtime = createAgentCliRuntime(adapter.handle);
1907
3405
  const controller = new AbortController();
1908
- const onSignal = (sig) => {
1909
- process.stderr.write(`
1910
- agentproto: received ${sig}, cancelling\u2026
1911
- `);
3406
+ process.once("SIGINT", () => {
3407
+ if (verbose) logVerbose("SIGINT received, draining current cycle\u2026");
1912
3408
  controller.abort();
1913
- };
1914
- process.once("SIGINT", onSignal);
1915
- process.once("SIGTERM", onSignal);
1916
- let session = null;
3409
+ });
1917
3410
  try {
1918
- session = await runtime.start({
1919
- cwd,
1920
- signal: controller.signal,
1921
- resumeSessionId: values.resume
1922
- });
1923
- const printer = values.json ? printJson : printPretty;
1924
- let exit = 0;
1925
- for await (const ev of session.send(promptArg)) {
1926
- printer(ev);
1927
- if (ev.kind === "turn-end" && ev.reason !== "completed") exit = 1;
1928
- if (ev.kind === "error") exit = 1;
1929
- }
1930
- return exit;
3411
+ do {
3412
+ if (controller.signal.aborted) break;
3413
+ try {
3414
+ await runTurn(ports, { signal: controller.signal });
3415
+ } catch (err) {
3416
+ const msg = err instanceof Error ? err.message : String(err);
3417
+ process.stderr.write(`agentproto run-swarm: cycle failed \u2014 ${msg}
3418
+ `);
3419
+ }
3420
+ if (onceMode) break;
3421
+ await sleep2(intervalMs, controller.signal);
3422
+ } while (!controller.signal.aborted);
1931
3423
  } finally {
1932
- process.off("SIGINT", onSignal);
1933
- process.off("SIGTERM", onSignal);
1934
- if (session) await session.close().catch(() => {
1935
- });
3424
+ await runCleanups(cleanups);
1936
3425
  }
3426
+ return 0;
1937
3427
  }
1938
- function printJson(ev) {
1939
- process.stdout.write(`${JSON.stringify(ev)}
1940
- `);
3428
+ async function buildPorts(loaded, ctx, telemetry) {
3429
+ const manifest = loaded.manifest;
3430
+ const substrate = await buildSubstrate(manifest, ctx);
3431
+ const dispatcher = await buildDispatcher(manifest, ctx);
3432
+ const state = await buildState(manifest, ctx);
3433
+ const participants = buildParticipants(manifest);
3434
+ const executors2 = await buildExecutors(manifest, ctx);
3435
+ return {
3436
+ substrate,
3437
+ dispatcher,
3438
+ state,
3439
+ participants,
3440
+ executors: executors2,
3441
+ ...telemetry ? { telemetry } : {}
3442
+ };
1941
3443
  }
1942
- function printPretty(ev) {
1943
- switch (ev.kind) {
1944
- case "text-delta":
1945
- process.stdout.write(ev.text);
1946
- break;
1947
- case "thought":
1948
- process.stderr.write(`\x1B[2m[thought] ${ev.text}\x1B[0m
1949
- `);
1950
- break;
1951
- case "tool-call":
1952
- process.stderr.write(`\x1B[36m[tool] ${ev.toolName}\x1B[0m
1953
- `);
1954
- break;
1955
- case "tool-result":
1956
- if (ev.isError)
1957
- process.stderr.write(`\x1B[31m[tool-error]\x1B[0m
1958
- `);
1959
- break;
1960
- case "agent-prompt":
1961
- process.stderr.write(`\x1B[33m[agent-prompt: needs input]\x1B[0m
1962
- `);
1963
- break;
1964
- case "turn-end":
1965
- process.stdout.write(`
1966
- \x1B[2m[turn-end: ${ev.reason}]\x1B[0m
1967
- `);
1968
- break;
1969
- case "error": {
1970
- const code = typeof ev.error.code === "number" ? ` (code ${ev.error.code})` : "";
1971
- process.stderr.write(
1972
- `\x1B[31m[error]${code} ${ev.error.message}\x1B[0m
1973
- `
3444
+ async function buildSubstrate(manifest, ctx) {
3445
+ const cfg = manifest.substrate;
3446
+ const factory = getSubstrateFactory(cfg.kind);
3447
+ if (!factory) {
3448
+ throw new Error(
3449
+ `unknown substrate kind '${cfg.kind}'. Registered kinds: [${listRegisteredKinds().substrates.join(", ") || "(none)"}]. Pass --plugin <module-id> or add it to ~/.agentproto/config.json plugins[] to register a third-party substrate.`
3450
+ );
3451
+ }
3452
+ return factory(cfg, ctx);
3453
+ }
3454
+ async function buildDispatcher(manifest, ctx) {
3455
+ const cfg = manifest.dispatcher;
3456
+ const factory = getDispatcherFactory(cfg.kind);
3457
+ if (!factory) {
3458
+ throw new Error(
3459
+ `unknown dispatcher kind '${cfg.kind}'. Registered kinds: [${listRegisteredKinds().dispatchers.join(", ") || "(none)"}].`
3460
+ );
3461
+ }
3462
+ return factory(cfg, ctx);
3463
+ }
3464
+ async function buildState(manifest, ctx) {
3465
+ const cfg = manifest.state ?? { kind: "fs" };
3466
+ const factory = getStateStoreFactory(cfg.kind);
3467
+ if (!factory) {
3468
+ throw new Error(
3469
+ `unknown state-store kind '${cfg.kind}'. Registered kinds: [${listRegisteredKinds().stateStores.join(", ") || "(none)"}].`
3470
+ );
3471
+ }
3472
+ return factory(cfg, ctx);
3473
+ }
3474
+ function buildParticipants(manifest) {
3475
+ return manifest.participants.map((p) => ({
3476
+ id: p.id,
3477
+ displayName: p.displayName ?? p.id,
3478
+ executor: p.executor,
3479
+ role: p.role,
3480
+ meta: p.meta
3481
+ }));
3482
+ }
3483
+ async function buildExecutors(manifest, ctx) {
3484
+ const map = /* @__PURE__ */ new Map();
3485
+ const kinds = new Set(manifest.participants.map((p) => p.executor));
3486
+ for (const kind of kinds) {
3487
+ const factory = getExecutorFactory(kind);
3488
+ if (!factory) {
3489
+ throw new Error(
3490
+ `unknown executor kind '${kind}'. Registered kinds: [${listRegisteredKinds().executors.join(", ") || "(none)"}]. Pass --plugin <module-id> or add the executor's package to ~/.agentproto/config.json plugins[].`
1974
3491
  );
1975
- const data = ev.error.data;
1976
- if (data && typeof data === "object") {
1977
- const stderr = data.stderr;
1978
- if (typeof stderr === "string" && stderr.trim()) {
1979
- process.stderr.write(`\x1B[2m\u2500\u2500 child stderr \u2500\u2500
1980
- ${stderr}\x1B[0m
3492
+ }
3493
+ map.set(kind, await factory({ kind }, ctx));
3494
+ }
3495
+ return map;
3496
+ }
3497
+ async function runCleanups(cleanups) {
3498
+ for (const fn of cleanups) {
3499
+ try {
3500
+ await fn();
3501
+ } catch (err) {
3502
+ const msg = err instanceof Error ? err.message : String(err);
3503
+ process.stderr.write(`agentproto run-swarm: cleanup failed \u2014 ${msg}
1981
3504
  `);
1982
- }
1983
- const rest = { ...data };
1984
- delete rest.stderr;
1985
- if (Object.keys(rest).length > 0) {
1986
- process.stderr.write(
1987
- `\x1B[2m\u2500\u2500 error.data \u2500\u2500
1988
- ${JSON.stringify(rest, null, 2)}\x1B[0m
1989
- `
1990
- );
1991
- }
1992
- }
1993
- break;
1994
3505
  }
1995
3506
  }
1996
3507
  }
3508
+ function parseInterval(value) {
3509
+ if (!value) return void 0;
3510
+ const match = /^(\d+)(ms|s)?$/.exec(value);
3511
+ if (!match) return void 0;
3512
+ const n = Number(match[1]);
3513
+ const unit = match[2] ?? "ms";
3514
+ return unit === "s" ? n * 1e3 : n;
3515
+ }
3516
+ function sleep2(ms, signal) {
3517
+ return new Promise((resolveP) => {
3518
+ if (signal.aborted) {
3519
+ resolveP();
3520
+ return;
3521
+ }
3522
+ const t = setTimeout(() => resolveP(), ms);
3523
+ signal.addEventListener("abort", () => {
3524
+ clearTimeout(t);
3525
+ resolveP();
3526
+ });
3527
+ });
3528
+ }
3529
+ function logVerbose(msg) {
3530
+ process.stderr.write(`agentproto run-swarm: ${msg}
3531
+ `);
3532
+ }
1997
3533
 
1998
3534
  // src/util/pty-factory.ts
1999
3535
  async function loadNodePtyFactory() {
@@ -2236,7 +3772,7 @@ function createVerbs(spec) {
2236
3772
  const relativePath = spec.pathOf(handle);
2237
3773
  const path = join(opts.dir, relativePath);
2238
3774
  const frontmatter = toFrontmatter(params);
2239
- const rendered = matter.stringify(
3775
+ const rendered = matter3.stringify(
2240
3776
  opts.body ?? defaultBody(spec, frontmatter),
2241
3777
  frontmatter
2242
3778
  );
@@ -2289,7 +3825,7 @@ function createVerbs(spec) {
2289
3825
  const mutated = await mutator(params, { handle, body });
2290
3826
  const newHandle = spec.define(mutated);
2291
3827
  const newFrontmatter = toFrontmatter(mutated);
2292
- const rendered = matter.stringify(
3828
+ const rendered = matter3.stringify(
2293
3829
  opts.body ?? body,
2294
3830
  newFrontmatter
2295
3831
  );
@@ -2299,7 +3835,7 @@ function createVerbs(spec) {
2299
3835
  }
2300
3836
  return { path, handle: newHandle, rendered };
2301
3837
  }
2302
- async function resolve7(block, ctx = {}) {
3838
+ async function resolve9(block, ctx = {}) {
2303
3839
  if ("inline" in block) {
2304
3840
  return spec.define(block.inline);
2305
3841
  }
@@ -2325,7 +3861,7 @@ function createVerbs(spec) {
2325
3861
  async function deleteFn(path) {
2326
3862
  await rm(path, { force: true });
2327
3863
  }
2328
- return { create, load, list, update, resolve: resolve7, delete: deleteFn };
3864
+ return { create, load, list, update, resolve: resolve9, delete: deleteFn };
2329
3865
  }
2330
3866
  function defaultBody(spec, frontmatter) {
2331
3867
  const id = typeof frontmatter.name === "string" ? frontmatter.name : typeof frontmatter.id === "string" ? frontmatter.id : typeof frontmatter.slug === "string" ? frontmatter.slug : spec.name;
@@ -2343,28 +3879,51 @@ createDoctype({
2343
3879
  validate(def) {
2344
3880
  const result = extensionFrontmatterSchema.safeParse(def);
2345
3881
  if (!result.success) {
2346
- throw new Error(`defineExtension (AIP-40): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
3882
+ throw new Error(
3883
+ `defineExtension (AIP-40): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
3884
+ );
2347
3885
  }
2348
3886
  },
2349
3887
  build(def) {
2350
3888
  return { ...def };
2351
3889
  }
2352
3890
  });
3891
+ function parseExtensionManifest(source) {
3892
+ const parsed = matter3(source);
3893
+ if (Object.keys(parsed.data).length === 0) {
3894
+ throw new Error("parseExtensionManifest: missing or empty frontmatter");
3895
+ }
3896
+ const result = extensionFrontmatterSchema.safeParse(parsed.data);
3897
+ if (!result.success) {
3898
+ throw new Error(
3899
+ `parseExtensionManifest: invalid frontmatter \u2014 ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
3900
+ );
3901
+ }
3902
+ return { frontmatter: result.data, body: parsed.content };
3903
+ }
3904
+
3905
+ // ../extension/dist/index.mjs
2353
3906
  function specFromExtension(extension, opts = {}) {
2354
3907
  const { parent } = opts;
2355
3908
  const isRoot = extension.extends === "none";
2356
3909
  if (!isRoot && !parent) {
2357
- throw new Error(`specFromExtension (AIP-40): extension '${extension.slug}' extends '${extension.extends}' but no parent spec was provided in opts.parent`);
3910
+ throw new Error(
3911
+ `specFromExtension (AIP-40): extension '${extension.slug}' extends '${extension.extends}' but no parent spec was provided in opts.parent`
3912
+ );
2358
3913
  }
2359
3914
  if (isRoot && !extension.path_convention) {
2360
- throw new Error(`specFromExtension (AIP-40): extension '${extension.slug}' is a root doctype (extends: none) and MUST declare path_convention`);
3915
+ throw new Error(
3916
+ `specFromExtension (AIP-40): extension '${extension.slug}' is a root doctype (extends: none) and MUST declare path_convention`
3917
+ );
2361
3918
  }
2362
3919
  if (parent && extension.tighten) {
2363
3920
  verifyTightening(extension);
2364
3921
  }
2365
3922
  const slugName = extension.slug.split(":")[1] ?? extension.slug;
2366
3923
  const pathTemplate = extension.path_convention ?? null;
2367
- const extensionKeys = new Set(Object.keys(extension.add_fields?.properties ?? {}));
3924
+ const extensionKeys = new Set(
3925
+ Object.keys(extension.add_fields?.properties ?? {})
3926
+ );
2368
3927
  const define = (params) => {
2369
3928
  const withDefaults = { ...params };
2370
3929
  if (extension.defaults) {
@@ -2380,10 +3939,8 @@ function specFromExtension(extension, opts = {}) {
2380
3939
  const parentOnly = {};
2381
3940
  const extensionOnly = {};
2382
3941
  for (const [key, value] of Object.entries(withDefaults)) {
2383
- if (extensionKeys.has(key))
2384
- extensionOnly[key] = value;
2385
- else
2386
- parentOnly[key] = value;
3942
+ if (extensionKeys.has(key)) extensionOnly[key] = value;
3943
+ else parentOnly[key] = value;
2387
3944
  }
2388
3945
  const parentHandle = parent.define(parentOnly);
2389
3946
  return Object.freeze({
@@ -2394,7 +3951,11 @@ function specFromExtension(extension, opts = {}) {
2394
3951
  const parse = isRoot ? rootParse(extension) : parent.parse;
2395
3952
  const pathOf = (handle) => {
2396
3953
  if (pathTemplate) {
2397
- return resolvePathTemplate(pathTemplate, handle, slugName);
3954
+ return resolvePathTemplate(
3955
+ pathTemplate,
3956
+ handle,
3957
+ slugName
3958
+ );
2398
3959
  }
2399
3960
  return parent.pathOf(handle);
2400
3961
  };
@@ -2411,36 +3972,33 @@ function verifyTightening(extension, parent) {
2411
3972
  const t = extension.tighten ?? {};
2412
3973
  for (const [field, override] of Object.entries(t)) {
2413
3974
  if (typeof override.minLength === "number" && typeof override.maxLength === "number" && override.minLength > override.maxLength) {
2414
- throw new Error(`specFromExtension (AIP-40): extension '${extension.slug}' tighten.${field}: minLength (${override.minLength}) > maxLength (${override.maxLength})`);
3975
+ throw new Error(
3976
+ `specFromExtension (AIP-40): extension '${extension.slug}' tighten.${field}: minLength (${override.minLength}) > maxLength (${override.maxLength})`
3977
+ );
2415
3978
  }
2416
3979
  if (typeof override.minimum === "number" && typeof override.maximum === "number" && override.minimum > override.maximum) {
2417
- throw new Error(`specFromExtension (AIP-40): extension '${extension.slug}' tighten.${field}: minimum (${override.minimum}) > maximum (${override.maximum})`);
3980
+ throw new Error(
3981
+ `specFromExtension (AIP-40): extension '${extension.slug}' tighten.${field}: minimum (${override.minimum}) > maximum (${override.maximum})`
3982
+ );
2418
3983
  }
2419
3984
  if (override.enum !== void 0 && !Array.isArray(override.enum)) {
2420
- throw new Error(`specFromExtension (AIP-40): extension '${extension.slug}' tighten.${field}: enum must be an array`);
3985
+ throw new Error(
3986
+ `specFromExtension (AIP-40): extension '${extension.slug}' tighten.${field}: enum must be an array`
3987
+ );
2421
3988
  }
2422
3989
  }
2423
3990
  }
2424
3991
  function rootParse(extension) {
2425
3992
  return (source) => {
2426
- throw new Error(`specFromExtension (AIP-40): extension '${extension.slug}' is a root doctype \u2014 supply your own parser or extend a public AIP for parser inheritance`);
3993
+ throw new Error(
3994
+ `specFromExtension (AIP-40): extension '${extension.slug}' is a root doctype \u2014 supply your own parser or extend a public AIP for parser inheritance`
3995
+ );
2427
3996
  };
2428
3997
  }
2429
3998
  function resolvePathTemplate(template, handle, doctypeSlug) {
2430
3999
  const identity = typeof handle.id === "string" && handle.id || typeof handle.slug === "string" && handle.slug || typeof handle.name === "string" && handle.name || "unknown";
2431
4000
  return template.replace(/<slug>/g, identity).replace(/<DOCTYPE>/g, doctypeSlug.toUpperCase());
2432
4001
  }
2433
- function parseExtensionManifest(source) {
2434
- const parsed = matter(source);
2435
- if (Object.keys(parsed.data).length === 0) {
2436
- throw new Error("parseExtensionManifest: missing or empty frontmatter");
2437
- }
2438
- const result = extensionFrontmatterSchema.safeParse(parsed.data);
2439
- if (!result.success) {
2440
- throw new Error(`parseExtensionManifest: invalid frontmatter \u2014 ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
2441
- }
2442
- return { frontmatter: result.data, body: parsed.content };
2443
- }
2444
4002
 
2445
4003
  // ../mcp-server/dist/index.mjs
2446
4004
  async function createMcpServer(opts) {
@@ -4203,7 +5761,7 @@ function startHeartbeat(opts) {
4203
5761
  } catch {
4204
5762
  return null;
4205
5763
  }
4206
- const parsed = matter(source);
5764
+ const parsed = matter3(source);
4207
5765
  const fm = parsed.data;
4208
5766
  const agent = typeof fm.agent === "string" ? fm.agent : null;
4209
5767
  if (!agent) return null;
@@ -4917,15 +6475,15 @@ async function startHttpServer(opts) {
4917
6475
  });
4918
6476
  });
4919
6477
  const bind = opts.bind ?? "127.0.0.1";
4920
- await new Promise((resolve8, reject) => {
6478
+ await new Promise((resolve82, reject) => {
4921
6479
  server.once("error", reject);
4922
- server.listen(opts.port, bind, () => resolve8());
6480
+ server.listen(opts.port, bind, () => resolve82());
4923
6481
  });
4924
6482
  return {
4925
6483
  url: `http://${bind}:${opts.port}`,
4926
6484
  async stop() {
4927
6485
  wss.close();
4928
- await new Promise((resolve8) => server.close(() => resolve8()));
6486
+ await new Promise((resolve82) => server.close(() => resolve82()));
4929
6487
  }
4930
6488
  };
4931
6489
  }
@@ -6062,12 +7620,12 @@ function createSessionsRegistry(opts) {
6062
7620
  } catch {
6063
7621
  }
6064
7622
  }
6065
- const nowIso = (/* @__PURE__ */ new Date()).toISOString();
7623
+ const nowIso2 = (/* @__PURE__ */ new Date()).toISOString();
6066
7624
  for (const rt of sessions.values()) {
6067
7625
  rt.emitter.removeAllListeners();
6068
7626
  if (rt.desc.status === "running" || rt.desc.status === "starting") {
6069
7627
  rt.desc.status = "killed";
6070
- rt.desc.endedAt = nowIso;
7628
+ rt.desc.endedAt = nowIso2;
6071
7629
  if (rt.agentSession) {
6072
7630
  void rt.agentSession.close().catch(() => void 0);
6073
7631
  }
@@ -6083,7 +7641,7 @@ function createSessionsRegistry(opts) {
6083
7641
  if (persist) {
6084
7642
  try {
6085
7643
  const snapshot = {
6086
- savedAt: nowIso,
7644
+ savedAt: nowIso2,
6087
7645
  sessions: Array.from(sessions.values()).map((s) => s.desc)
6088
7646
  };
6089
7647
  mkdirSync(dirname(persistPath), { recursive: true });
@@ -6378,7 +7936,7 @@ var URL_REGEX = /https:\/\/[a-z0-9-]+\.trycloudflare\.com/i;
6378
7936
  var STARTUP_TIMEOUT_MS = 3e4;
6379
7937
  function quickTunnelProvider() {
6380
7938
  let child = null;
6381
- let configPath = null;
7939
+ let configPath3 = null;
6382
7940
  return {
6383
7941
  id: "quick",
6384
7942
  async start(opts) {
@@ -6387,7 +7945,7 @@ function quickTunnelProvider() {
6387
7945
  const id = randomBytes(4).toString("hex");
6388
7946
  const dir = join(opts.workspace, ".agentproto");
6389
7947
  await mkdir(dir, { recursive: true });
6390
- configPath = join(dir, `cloudflared-${id}.yml`);
7948
+ configPath3 = join(dir, `cloudflared-${id}.yml`);
6391
7949
  const configBody = [
6392
7950
  `# generated by agentproto-runtime \u2014 sentinel only`,
6393
7951
  `# overrides ~/.cloudflared/config.yml so its ingress rules`,
@@ -6397,14 +7955,14 @@ function quickTunnelProvider() {
6397
7955
  `loglevel: debug`,
6398
7956
  ``
6399
7957
  ].join("\n");
6400
- await writeFile(configPath, configBody, "utf8");
7958
+ await writeFile(configPath3, configBody, "utf8");
6401
7959
  const proc = spawn(
6402
7960
  "cloudflared",
6403
- ["tunnel", "--config", configPath, "--url", targetUrl],
7961
+ ["tunnel", "--config", configPath3, "--url", targetUrl],
6404
7962
  { stdio: ["ignore", "pipe", "pipe"], shell: false }
6405
7963
  );
6406
7964
  child = proc;
6407
- const url = await new Promise((resolve8, reject) => {
7965
+ const url = await new Promise((resolve82, reject) => {
6408
7966
  let settled = false;
6409
7967
  const timer = setTimeout(() => {
6410
7968
  if (settled) return;
@@ -6429,7 +7987,7 @@ function quickTunnelProvider() {
6429
7987
  if (match) {
6430
7988
  settled = true;
6431
7989
  clearTimeout(timer);
6432
- resolve8(match[0]);
7990
+ resolve82(match[0]);
6433
7991
  }
6434
7992
  };
6435
7993
  proc.stderr?.on("data", onData);
@@ -6460,9 +8018,9 @@ function quickTunnelProvider() {
6460
8018
  },
6461
8019
  async stop() {
6462
8020
  const proc = child;
6463
- const cfg = configPath;
8021
+ const cfg = configPath3;
6464
8022
  child = null;
6465
- configPath = null;
8023
+ configPath3 = null;
6466
8024
  if (cfg) {
6467
8025
  try {
6468
8026
  await rm(cfg, { force: true });
@@ -6478,15 +8036,15 @@ function quickTunnelProvider() {
6478
8036
  }
6479
8037
  }, 3e3);
6480
8038
  timer.unref();
6481
- await new Promise((resolve8) => {
8039
+ await new Promise((resolve82) => {
6482
8040
  if (proc.exitCode !== null) {
6483
8041
  clearTimeout(timer);
6484
- resolve8();
8042
+ resolve82();
6485
8043
  return;
6486
8044
  }
6487
8045
  proc.once("exit", () => {
6488
8046
  clearTimeout(timer);
6489
- resolve8();
8047
+ resolve82();
6490
8048
  });
6491
8049
  });
6492
8050
  }
@@ -6565,7 +8123,7 @@ var RemoteController = class {
6565
8123
  let bearerTokenHash = "";
6566
8124
  if (exposesGateway) {
6567
8125
  bearerToken = randomBytes(32).toString("base64url");
6568
- bearerTokenHash = sha256(bearerToken);
8126
+ bearerTokenHash = sha2562(bearerToken);
6569
8127
  }
6570
8128
  const state = {
6571
8129
  provider: providerId,
@@ -6630,7 +8188,7 @@ function pickProvider(id) {
6630
8188
  const _exhaustive = id;
6631
8189
  throw new Error(`unknown remote provider: ${String(_exhaustive)}`);
6632
8190
  }
6633
- function sha256(input2) {
8191
+ function sha2562(input2) {
6634
8192
  return createHash("sha256").update(input2).digest("hex");
6635
8193
  }
6636
8194
  function errToMessage(err) {
@@ -6723,7 +8281,7 @@ var WorkspacePathError = class extends Error {
6723
8281
  };
6724
8282
  function createWorkspaceFs(opts) {
6725
8283
  const root = resolve(opts.workspace);
6726
- function resolvePath4(path) {
8284
+ function resolvePath42(path) {
6727
8285
  if (typeof path !== "string" || path.length === 0) {
6728
8286
  throw new WorkspacePathError("path must be a non-empty string");
6729
8287
  }
@@ -6743,18 +8301,18 @@ function createWorkspaceFs(opts) {
6743
8301
  }
6744
8302
  return {
6745
8303
  async readFile(path) {
6746
- const abs = resolvePath4(path);
8304
+ const abs = resolvePath42(path);
6747
8305
  const buf = await readFile(abs);
6748
8306
  return buf.toString("utf8");
6749
8307
  },
6750
8308
  async writeFile(path, content) {
6751
- const abs = resolvePath4(path);
8309
+ const abs = resolvePath42(path);
6752
8310
  await mkdir(dirname(abs), { recursive: true });
6753
8311
  await writeFile(abs, content);
6754
8312
  },
6755
8313
  async exists(path) {
6756
8314
  try {
6757
- const abs = resolvePath4(path);
8315
+ const abs = resolvePath42(path);
6758
8316
  return existsSync(abs);
6759
8317
  } catch {
6760
8318
  return false;
@@ -6949,18 +8507,40 @@ async function runServe(args) {
6949
8507
  port: { type: "string", short: "p" },
6950
8508
  bind: { type: "string", short: "b" },
6951
8509
  "allow-origin": { type: "string", multiple: true },
6952
- interactive: { type: "boolean", short: "i" }
8510
+ interactive: { type: "boolean", short: "i" },
8511
+ profile: { type: "string" }
6953
8512
  }
6954
8513
  });
6955
8514
  const cfg = await loadConfig();
6956
- const cfgDaemon = cfg.daemon ?? {};
6957
- const cfgTunnel = cfg.tunnel ?? {};
8515
+ const profileName = values.profile ?? cfg.activeProfile;
8516
+ const profile = profileName ? cfg.profiles?.[profileName] : void 0;
8517
+ if (values.profile && !profile) {
8518
+ process.stderr.write(
8519
+ `agentproto serve: profile "${values.profile}" not found in ~/.agentproto/config.json. Available: ${cfg.profiles ? Object.keys(cfg.profiles).join(", ") || "(none)" : "(no profiles block)"}
8520
+ `
8521
+ );
8522
+ return 2;
8523
+ }
8524
+ if (cfg.activeProfile && !values.profile && !profile) {
8525
+ process.stderr.write(
8526
+ `agentproto serve: \u26A0 activeProfile="${cfg.activeProfile}" but no matching entry in profiles[]; falling back to top-level config.
8527
+ `
8528
+ );
8529
+ }
8530
+ if (profile && process.stdout.isTTY) {
8531
+ process.stdout.write(
8532
+ `agentproto serve: using profile "${profileName}"
8533
+ `
8534
+ );
8535
+ }
8536
+ const cfgDaemon = { ...cfg.daemon ?? {}, ...profile?.daemon ?? {} };
8537
+ const cfgTunnel = { ...cfg.tunnel ?? {}, ...profile?.tunnel ?? {} };
6958
8538
  const workspace = resolve(
6959
8539
  values.workspace ?? cfgDaemon.workspace ?? process.cwd()
6960
8540
  );
6961
8541
  try {
6962
- const stat2 = await promises.stat(workspace);
6963
- if (!stat2.isDirectory()) {
8542
+ const stat5 = await promises.stat(workspace);
8543
+ if (!stat5.isDirectory()) {
6964
8544
  process.stderr.write(
6965
8545
  `agentproto serve: --workspace "${workspace}" is not a directory.
6966
8546
  `
@@ -6983,7 +8563,7 @@ async function runServe(args) {
6983
8563
  }
6984
8564
  const label = values.label ?? cfgDaemon.label ?? `${userInfo().username}@${hostname()}`;
6985
8565
  const connectFlag = values.connect ?? (cfgTunnel.autoconnect && cfgTunnel.host ? cfgTunnel.host : void 0);
6986
- let token = values.token ?? process.env.AGENTPROTO_TOKEN;
8566
+ let token = values.token ?? process.env.AGENTPROTO_TOKEN ?? cfgTunnel.token;
6987
8567
  if (!token && connectFlag) {
6988
8568
  const cred = await readHost(connectFlag);
6989
8569
  if (cred) {
@@ -7119,8 +8699,8 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
7119
8699
  AGENTPROTO_DAEMON_TOKEN: gateway.token
7120
8700
  }
7121
8701
  });
7122
- await new Promise((resolve7) => {
7123
- child.once("exit", () => resolve7());
8702
+ await new Promise((resolve9) => {
8703
+ child.once("exit", () => resolve9());
7124
8704
  aborter.signal.addEventListener("abort", () => {
7125
8705
  try {
7126
8706
  child.kill("SIGTERM");
@@ -7140,8 +8720,8 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
7140
8720
  `${color.dim}Press Ctrl-C to stop.${color.reset}
7141
8721
  `
7142
8722
  );
7143
- await new Promise((resolve7) => {
7144
- aborter.signal.addEventListener("abort", () => resolve7());
8723
+ await new Promise((resolve9) => {
8724
+ aborter.signal.addEventListener("abort", () => resolve9());
7145
8725
  });
7146
8726
  return 0;
7147
8727
  }
@@ -7160,7 +8740,7 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
7160
8740
  reconnectState.immediate = false;
7161
8741
  continue;
7162
8742
  }
7163
- await sleep2(2e3, aborter.signal);
8743
+ await sleep3(2e3, aborter.signal);
7164
8744
  } catch (err) {
7165
8745
  if (aborter.signal.aborted) break;
7166
8746
  const msg = err instanceof Error ? err.message : String(err);
@@ -7169,7 +8749,7 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
7169
8749
  reconnecting in ${backoffMs}ms\u2026
7170
8750
  `
7171
8751
  );
7172
- await sleep2(backoffMs, aborter.signal);
8752
+ await sleep3(backoffMs, aborter.signal);
7173
8753
  backoffMs = Math.min(backoffMs * 2, backoffMax);
7174
8754
  }
7175
8755
  }
@@ -7182,10 +8762,10 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
7182
8762
  };
7183
8763
  if (opts.token) headers.authorization = `Bearer ${opts.token}`;
7184
8764
  const ws = new WebSocket2(opts.connect, { headers });
7185
- await new Promise((resolve7, reject) => {
8765
+ await new Promise((resolve9, reject) => {
7186
8766
  const onOpen = () => {
7187
8767
  ws.off("error", onError);
7188
- resolve7();
8768
+ resolve9();
7189
8769
  };
7190
8770
  const onError = (err) => {
7191
8771
  ws.off("open", onOpen);
@@ -7239,14 +8819,14 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
7239
8819
  } catch {
7240
8820
  }
7241
8821
  }
7242
- return await new Promise((resolve7, reject) => {
8822
+ return await new Promise((resolve9, reject) => {
7243
8823
  const sock = new WebSocket2(url, protocols ? [...protocols] : void 0, {
7244
8824
  headers: upstreamHeaders
7245
8825
  });
7246
8826
  const onceOpen = () => {
7247
8827
  sock.off("error", onceError);
7248
8828
  sock.off("unexpected-response", onceUnexpected);
7249
- resolve7({
8829
+ resolve9({
7250
8830
  protocol: sock.protocol ?? "",
7251
8831
  send: (data, sendOpts) => {
7252
8832
  sock.send(data, { binary: sendOpts.binary });
@@ -7320,31 +8900,31 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
7320
8900
  }
7321
8901
  }
7322
8902
  });
7323
- await new Promise((resolve7) => {
8903
+ await new Promise((resolve9) => {
7324
8904
  const offClose = sink.onClose(() => {
7325
8905
  clearInterval(keepaliveInterval);
7326
8906
  offClose();
7327
- resolve7();
8907
+ resolve9();
7328
8908
  });
7329
8909
  if (signal.aborted) {
7330
8910
  clearInterval(keepaliveInterval);
7331
- server.close().finally(() => resolve7());
8911
+ server.close().finally(() => resolve9());
7332
8912
  }
7333
8913
  signal.addEventListener("abort", () => {
7334
8914
  clearInterval(keepaliveInterval);
7335
- server.close().finally(() => resolve7());
8915
+ server.close().finally(() => resolve9());
7336
8916
  });
7337
8917
  });
7338
8918
  process.stderr.write(`agentproto serve: tunnel closed.
7339
8919
  `);
7340
8920
  }
7341
- function sleep2(ms, signal) {
7342
- return new Promise((resolve7) => {
7343
- if (signal.aborted) return resolve7();
7344
- const timer = setTimeout(resolve7, ms);
8921
+ function sleep3(ms, signal) {
8922
+ return new Promise((resolve9) => {
8923
+ if (signal.aborted) return resolve9();
8924
+ const timer = setTimeout(resolve9, ms);
7345
8925
  signal.addEventListener("abort", () => {
7346
8926
  clearTimeout(timer);
7347
- resolve7();
8927
+ resolve9();
7348
8928
  });
7349
8929
  });
7350
8930
  }
@@ -7391,7 +8971,7 @@ var color = _isTty ? {
7391
8971
  cyan: "",
7392
8972
  red: ""
7393
8973
  };
7394
- var USAGE3 = `agentproto workspace \u2014 manage local workspaces
8974
+ var USAGE4 = `agentproto workspace \u2014 manage local workspaces
7395
8975
 
7396
8976
  Usage:
7397
8977
  agentproto workspace add <path> [--slug <slug>] [--label <text>]
@@ -7404,7 +8984,7 @@ Config file: ${DEFAULT_CONFIG_PATH()}
7404
8984
  `;
7405
8985
  async function runWorkspace(args) {
7406
8986
  if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
7407
- process.stdout.write(USAGE3);
8987
+ process.stdout.write(USAGE4);
7408
8988
  return 0;
7409
8989
  }
7410
8990
  const sub = args[0];
@@ -7414,7 +8994,7 @@ async function runWorkspace(args) {
7414
8994
  return runAdd(rest);
7415
8995
  case "list":
7416
8996
  case "ls":
7417
- return runList(rest);
8997
+ return runList2(rest);
7418
8998
  case "remove":
7419
8999
  case "rm":
7420
9000
  return runRemove(rest);
@@ -7424,7 +9004,7 @@ async function runWorkspace(args) {
7424
9004
  process.stderr.write(
7425
9005
  `agentproto workspace: unknown subcommand '${sub}'
7426
9006
 
7427
- ${USAGE3}`
9007
+ ${USAGE4}`
7428
9008
  );
7429
9009
  return 2;
7430
9010
  }
@@ -7469,7 +9049,7 @@ async function runAdd(args) {
7469
9049
  );
7470
9050
  return 0;
7471
9051
  }
7472
- async function runList(args) {
9052
+ async function runList2(args) {
7473
9053
  const { values } = parseArgs({
7474
9054
  args: [...args],
7475
9055
  allowPositionals: false,
@@ -7619,7 +9199,7 @@ function probeMtimeLatestJsonl2(storeRel) {
7619
9199
  }
7620
9200
 
7621
9201
  // src/commands/sessions.ts
7622
- var USAGE4 = `agentproto sessions \u2014 browse and control daemon sessions
9202
+ var USAGE5 = `agentproto sessions \u2014 browse and control daemon sessions
7623
9203
 
7624
9204
  Usage:
7625
9205
  agentproto sessions [--watch] [--json]
@@ -7643,7 +9223,7 @@ While attached:
7643
9223
  `;
7644
9224
  async function runSessions(args) {
7645
9225
  if (args.includes("--help") || args.includes("-h")) {
7646
- process.stdout.write(USAGE4);
9226
+ process.stdout.write(USAGE5);
7647
9227
  return 0;
7648
9228
  }
7649
9229
  const sub = args[0];
@@ -7978,9 +9558,9 @@ function printNoDaemonError(report, verb) {
7978
9558
  }
7979
9559
  async function readRuntimeJsonWithStatus(workspacePath) {
7980
9560
  const path = resolve(workspacePath, ".agentproto", "runtime.json");
7981
- let stat2;
9561
+ let stat5;
7982
9562
  try {
7983
- stat2 = await promises.stat(path);
9563
+ stat5 = await promises.stat(path);
7984
9564
  } catch {
7985
9565
  return { endpoint: null };
7986
9566
  }
@@ -8003,7 +9583,7 @@ async function readRuntimeJsonWithStatus(workspacePath) {
8003
9583
  stale: {
8004
9584
  path,
8005
9585
  pid: parsed.pid ?? null,
8006
- mtime: stat2.mtime ?? null
9586
+ mtime: stat5.mtime ?? null
8007
9587
  }
8008
9588
  };
8009
9589
  }
@@ -8804,7 +10384,7 @@ function stripAnsi(s) {
8804
10384
  return s.replace(/\x1b\[[0-9;]*m/g, "");
8805
10385
  }
8806
10386
  function httpDelete(url, token) {
8807
- return new Promise((resolve7, reject) => {
10387
+ return new Promise((resolve9, reject) => {
8808
10388
  const u = new URL(url);
8809
10389
  const lib = u.protocol === "https:" ? https : http;
8810
10390
  const headers = {};
@@ -8820,7 +10400,7 @@ function httpDelete(url, token) {
8820
10400
  return;
8821
10401
  }
8822
10402
  try {
8823
- resolve7(raw ? JSON.parse(raw) : {});
10403
+ resolve9(raw ? JSON.parse(raw) : {});
8824
10404
  } catch (err) {
8825
10405
  reject(err instanceof Error ? err : new Error(String(err)));
8826
10406
  }
@@ -9387,21 +10967,21 @@ async function runPtyAttach(endpoint, desc, _colour) {
9387
10967
  });
9388
10968
  }
9389
10969
  async function probeDaemonHealth(baseUrl) {
9390
- return new Promise((resolve7) => {
10970
+ return new Promise((resolve9) => {
9391
10971
  try {
9392
10972
  const u = new URL(`${baseUrl}/health`);
9393
10973
  const lib = u.protocol === "https:" ? https : http;
9394
10974
  const req = lib.get(u, { timeout: 500 }, (res) => {
9395
- resolve7((res.statusCode ?? 0) >= 200 && (res.statusCode ?? 0) < 300);
10975
+ resolve9((res.statusCode ?? 0) >= 200 && (res.statusCode ?? 0) < 300);
9396
10976
  res.resume();
9397
10977
  });
9398
- req.on("error", () => resolve7(false));
10978
+ req.on("error", () => resolve9(false));
9399
10979
  req.on("timeout", () => {
9400
10980
  req.destroy();
9401
- resolve7(false);
10981
+ resolve9(false);
9402
10982
  });
9403
10983
  } catch {
9404
- resolve7(false);
10984
+ resolve9(false);
9405
10985
  }
9406
10986
  });
9407
10987
  }
@@ -9441,7 +11021,7 @@ async function explain401(endpoint, verb) {
9441
11021
  return lines.join("\n");
9442
11022
  }
9443
11023
  function httpPostJson(url, body, token) {
9444
- return new Promise((resolve7, reject) => {
11024
+ return new Promise((resolve9, reject) => {
9445
11025
  const u = new URL(url);
9446
11026
  const payload = Buffer.from(JSON.stringify(body), "utf8");
9447
11027
  const lib = u.protocol === "https:" ? https : http;
@@ -9464,7 +11044,7 @@ function httpPostJson(url, body, token) {
9464
11044
  return;
9465
11045
  }
9466
11046
  try {
9467
- resolve7(JSON.parse(raw));
11047
+ resolve9(JSON.parse(raw));
9468
11048
  } catch (err) {
9469
11049
  reject(err instanceof Error ? err : new Error(String(err)));
9470
11050
  }
@@ -9480,7 +11060,7 @@ async function httpGetJson(url) {
9480
11060
  return await httpGetJsonImpl(url);
9481
11061
  }
9482
11062
  function httpGetJsonImpl(url) {
9483
- return new Promise((resolve7, reject) => {
11063
+ return new Promise((resolve9, reject) => {
9484
11064
  const u = new URL(url);
9485
11065
  const lib = u.protocol === "https:" ? https : http;
9486
11066
  lib.get(u, (res) => {
@@ -9493,7 +11073,7 @@ function httpGetJsonImpl(url) {
9493
11073
  return;
9494
11074
  }
9495
11075
  try {
9496
- resolve7(JSON.parse(body));
11076
+ resolve9(JSON.parse(body));
9497
11077
  } catch (err) {
9498
11078
  reject(err instanceof Error ? err : new Error(String(err)));
9499
11079
  }
@@ -9503,16 +11083,20 @@ function httpGetJsonImpl(url) {
9503
11083
  }
9504
11084
 
9505
11085
  // src/cli.ts
9506
- var USAGE6 = `agentproto \u2014 AIP-45 agent CLI host
11086
+ var USAGE7 = `agentproto \u2014 AIP-45 agent CLI host
9507
11087
 
9508
11088
  Usage:
9509
11089
  agentproto auth <login|status|logout> [--host <url>] [--label <name>]
9510
11090
  agentproto config <show|path|get|set|unset|edit> [args]
9511
11091
  agentproto daemon <install|uninstall|start|stop|status|logs> [args]
9512
11092
  agentproto install <slug> [--force] [--dry-run] [--skip-setup]
11093
+ <slug> \u2208 { <adapter-slug> | runtime-profile/<name> }
11094
+ agentproto plugins <list|show|install|uninstall|enable|disable> [args]
9513
11095
  agentproto setup <slug> [--force] [--dry-run] [--only <stepId>...]
9514
11096
  agentproto run <slug> [--cwd <dir>] [--prompt <text>] [--resume <session-id>]
9515
- agentproto serve [--workspace <dir>] [--port <n>] [--bind <ip>]
11097
+ agentproto run-swarm --manifest <path> [--once] [--interval <ms|Ns>] [--verbose]
11098
+ agentproto serve [--profile <name>]
11099
+ [--workspace <dir>] [--port <n>] [--bind <ip>]
9516
11100
  [--connect <url> [--token <jwt>] [--label <name>]]
9517
11101
  [--allow-origin <url> \u2026] [--interactive | -i]
9518
11102
  agentproto workspace <add|list|remove|use> [args]
@@ -9530,12 +11114,14 @@ Usage:
9530
11114
  Examples:
9531
11115
  agentproto auth login --host wss://guilde.work # device flow \u2192 ~/.agentproto/credentials.json
9532
11116
  agentproto install claude-code
11117
+ agentproto install runtime-profile/standard # drops .claude/ swarm scaffolding into the cwd
9533
11118
  agentproto setup openclaw # re-run setup (idempotent via skip_if + ledger)
9534
11119
  agentproto run claude-code --cwd . --prompt "summarise this repo"
11120
+ agentproto run-swarm --manifest .runtime/local.yaml --verbose
9535
11121
  agentproto workspace add ~/code/my-project --slug my-project
9536
11122
  agentproto workspace list
9537
11123
  agentproto serve --connect wss://guilde.work/api/v1/agentproto/tunnel
9538
- agentproto sessions start claude-code --workspace agentik-studio --attach
11124
+ agentproto sessions start claude-code --workspace my-app --attach
9539
11125
  agentproto sessions terminal --name claude-tui --attach -- claude
9540
11126
  agentproto sessions stop claude-tui
9541
11127
  agentproto config set daemon.port 18791
@@ -9548,8 +11134,10 @@ var VERBS = /* @__PURE__ */ new Set([
9548
11134
  "config",
9549
11135
  "daemon",
9550
11136
  "install",
11137
+ "plugins",
9551
11138
  "setup",
9552
11139
  "run",
11140
+ "run-swarm",
9553
11141
  "serve",
9554
11142
  "workspace",
9555
11143
  "sessions"
@@ -9562,13 +11150,13 @@ async function main(argv) {
9562
11150
  return 0;
9563
11151
  }
9564
11152
  if (argv.includes("--help") || argv.includes("-h") || argv.length === 0) {
9565
- process.stdout.write(USAGE6);
11153
+ process.stdout.write(USAGE7);
9566
11154
  return 0;
9567
11155
  }
9568
11156
  process.stderr.write(
9569
11157
  `agentproto: unrecognised argument(s): ${argv.join(" ")}
9570
11158
 
9571
- ${USAGE6}`
11159
+ ${USAGE7}`
9572
11160
  );
9573
11161
  return 2;
9574
11162
  }
@@ -9585,10 +11173,14 @@ ${USAGE6}`
9585
11173
  }
9586
11174
  case "install":
9587
11175
  return runInstall(rest);
11176
+ case "plugins":
11177
+ return runPlugins(rest);
9588
11178
  case "setup":
9589
11179
  return runSetupCommand(rest);
9590
11180
  case "run":
9591
11181
  return runRun(rest);
11182
+ case "run-swarm":
11183
+ return runRunSwarm(rest);
9592
11184
  case "serve":
9593
11185
  return runServe(rest);
9594
11186
  case "workspace":
@@ -9598,7 +11190,7 @@ ${USAGE6}`
9598
11190
  default:
9599
11191
  process.stderr.write(`agentproto: unknown verb '${verb}'
9600
11192
 
9601
- ${USAGE6}`);
11193
+ ${USAGE7}`);
9602
11194
  return 2;
9603
11195
  }
9604
11196
  }