@agentproto/cli 0.1.0-alpha.8 → 0.1.0-alpha.9
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 +1822 -253
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +365 -37
- package/dist/index.mjs.map +1 -1
- package/dist/registry/builtins.d.ts +14 -0
- package/dist/registry/builtins.mjs +329 -0
- package/dist/registry/builtins.mjs.map +1 -0
- package/dist/registry/manifest.d.ts +88 -0
- package/dist/registry/manifest.mjs +42 -0
- package/dist/registry/manifest.mjs.map +1 -0
- package/dist/registry/plugins.d.ts +23 -0
- package/dist/registry/plugins.mjs +201 -0
- package/dist/registry/plugins.mjs.map +1 -0
- package/dist/registry/runtime.d.ts +70 -0
- package/dist/registry/runtime.mjs +52 -0
- package/dist/registry/runtime.mjs.map +1 -0
- package/dist/util/credentials.d.ts +71 -0
- package/dist/util/credentials.mjs +88 -0
- package/dist/util/credentials.mjs.map +1 -0
- package/package.json +32 -4
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,
|
|
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(
|
|
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
|
|
133
|
+
return runInstall3(rest);
|
|
132
134
|
case "uninstall":
|
|
133
|
-
return
|
|
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
|
-
${
|
|
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
|
|
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
|
|
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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
388
390
|
}
|
|
389
391
|
function launchctl(args) {
|
|
390
|
-
return new Promise((
|
|
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) =>
|
|
400
|
+
(err) => resolve9({ code: 127, stdout, stderr: err.message })
|
|
399
401
|
);
|
|
400
|
-
child.on("exit", (code) =>
|
|
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,
|
|
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
|
-
|
|
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((
|
|
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((
|
|
858
|
+
return new Promise((resolve9) => {
|
|
857
859
|
try {
|
|
858
860
|
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
859
|
-
child.once("error", () =>
|
|
861
|
+
child.once("error", () => resolve9());
|
|
860
862
|
child.once("spawn", () => {
|
|
861
863
|
child.unref();
|
|
862
|
-
|
|
864
|
+
resolve9();
|
|
863
865
|
});
|
|
864
866
|
} catch {
|
|
865
|
-
|
|
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((
|
|
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
|
-
|
|
1005
|
+
resolve9(1);
|
|
1004
1006
|
});
|
|
1005
|
-
child.on("exit", (code) =>
|
|
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
|
|
1103
|
-
if (
|
|
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((
|
|
1288
|
+
await new Promise((resolve9) => {
|
|
1287
1289
|
const child = spawn(opener, args, { stdio: "ignore", detached: true });
|
|
1288
|
-
child.once("error", () =>
|
|
1289
|
-
child.once("spawn", () =>
|
|
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((
|
|
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
|
-
|
|
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((
|
|
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
|
-
|
|
1472
|
+
resolve9({ exitCode: 127, stdout, stderr: stderr || "spawn error" });
|
|
1471
1473
|
});
|
|
1472
1474
|
child.once("exit", (code) => {
|
|
1473
1475
|
clearTimeout(timer);
|
|
1474
|
-
|
|
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(
|
|
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,174 +2134,1402 @@ async function runDownloadInstaller(opts) {
|
|
|
1826
2134
|
});
|
|
1827
2135
|
}
|
|
1828
2136
|
}
|
|
1829
|
-
function
|
|
2137
|
+
function homedir5() {
|
|
1830
2138
|
return process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/";
|
|
1831
2139
|
}
|
|
1832
2140
|
function spawnInherit(cmd, argv) {
|
|
1833
|
-
return new Promise((
|
|
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) =>
|
|
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((
|
|
2149
|
+
return new Promise((resolve9) => {
|
|
1842
2150
|
const child = spawn("bash", ["-lc", check.cmd], {
|
|
1843
2151
|
stdio: ["ignore", "pipe", "ignore"]
|
|
1844
2152
|
});
|
|
1845
|
-
let buf = "";
|
|
1846
|
-
child.stdout.on("data", (c) => {
|
|
1847
|
-
buf += c.toString("utf8");
|
|
2153
|
+
let buf = "";
|
|
2154
|
+
child.stdout.on("data", (c) => {
|
|
2155
|
+
buf += c.toString("utf8");
|
|
2156
|
+
});
|
|
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");
|
|
1848
3250
|
});
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
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
|
-
|
|
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/
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
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 [];
|
|
3324
|
+
}
|
|
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
|
+
}
|
|
1872
3340
|
}
|
|
1873
|
-
|
|
1874
|
-
|
|
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
|
|
1879
|
-
const { values
|
|
3347
|
+
// src/commands/run-swarm.ts
|
|
3348
|
+
async function runRunSwarm(args) {
|
|
3349
|
+
const { values } = parseArgs({
|
|
1880
3350
|
args: [...args],
|
|
1881
|
-
allowPositionals:
|
|
3351
|
+
allowPositionals: false,
|
|
1882
3352
|
strict: true,
|
|
1883
3353
|
options: {
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
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
|
-
|
|
1891
|
-
if (!slug) {
|
|
3361
|
+
if (!values.manifest) {
|
|
1892
3362
|
process.stderr.write(
|
|
1893
|
-
"agentproto run:
|
|
3363
|
+
"agentproto run-swarm: --manifest <path> is required.\n"
|
|
1894
3364
|
);
|
|
1895
3365
|
return 2;
|
|
1896
3366
|
}
|
|
1897
|
-
|
|
1898
|
-
const
|
|
1899
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1909
|
-
|
|
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
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
if (
|
|
1928
|
-
|
|
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
|
-
|
|
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
|
|
1939
|
-
|
|
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
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
`)
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
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
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
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 =
|
|
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 =
|
|
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
|
|
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:
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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 =
|
|
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((
|
|
6478
|
+
await new Promise((resolve82, reject) => {
|
|
4921
6479
|
server.once("error", reject);
|
|
4922
|
-
server.listen(opts.port, bind, () =>
|
|
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((
|
|
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
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
-
|
|
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(
|
|
7958
|
+
await writeFile(configPath3, configBody, "utf8");
|
|
6401
7959
|
const proc = spawn(
|
|
6402
7960
|
"cloudflared",
|
|
6403
|
-
["tunnel", "--config",
|
|
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((
|
|
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
|
-
|
|
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 =
|
|
8021
|
+
const cfg = configPath3;
|
|
6464
8022
|
child = null;
|
|
6465
|
-
|
|
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((
|
|
8039
|
+
await new Promise((resolve82) => {
|
|
6482
8040
|
if (proc.exitCode !== null) {
|
|
6483
8041
|
clearTimeout(timer);
|
|
6484
|
-
|
|
8042
|
+
resolve82();
|
|
6485
8043
|
return;
|
|
6486
8044
|
}
|
|
6487
8045
|
proc.once("exit", () => {
|
|
6488
8046
|
clearTimeout(timer);
|
|
6489
|
-
|
|
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 =
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
8315
|
+
const abs = resolvePath42(path);
|
|
6758
8316
|
return existsSync(abs);
|
|
6759
8317
|
} catch {
|
|
6760
8318
|
return false;
|
|
@@ -6959,8 +8517,8 @@ async function runServe(args) {
|
|
|
6959
8517
|
values.workspace ?? cfgDaemon.workspace ?? process.cwd()
|
|
6960
8518
|
);
|
|
6961
8519
|
try {
|
|
6962
|
-
const
|
|
6963
|
-
if (!
|
|
8520
|
+
const stat5 = await promises.stat(workspace);
|
|
8521
|
+
if (!stat5.isDirectory()) {
|
|
6964
8522
|
process.stderr.write(
|
|
6965
8523
|
`agentproto serve: --workspace "${workspace}" is not a directory.
|
|
6966
8524
|
`
|
|
@@ -7119,8 +8677,8 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
7119
8677
|
AGENTPROTO_DAEMON_TOKEN: gateway.token
|
|
7120
8678
|
}
|
|
7121
8679
|
});
|
|
7122
|
-
await new Promise((
|
|
7123
|
-
child.once("exit", () =>
|
|
8680
|
+
await new Promise((resolve9) => {
|
|
8681
|
+
child.once("exit", () => resolve9());
|
|
7124
8682
|
aborter.signal.addEventListener("abort", () => {
|
|
7125
8683
|
try {
|
|
7126
8684
|
child.kill("SIGTERM");
|
|
@@ -7140,8 +8698,8 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
7140
8698
|
`${color.dim}Press Ctrl-C to stop.${color.reset}
|
|
7141
8699
|
`
|
|
7142
8700
|
);
|
|
7143
|
-
await new Promise((
|
|
7144
|
-
aborter.signal.addEventListener("abort", () =>
|
|
8701
|
+
await new Promise((resolve9) => {
|
|
8702
|
+
aborter.signal.addEventListener("abort", () => resolve9());
|
|
7145
8703
|
});
|
|
7146
8704
|
return 0;
|
|
7147
8705
|
}
|
|
@@ -7160,7 +8718,7 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
7160
8718
|
reconnectState.immediate = false;
|
|
7161
8719
|
continue;
|
|
7162
8720
|
}
|
|
7163
|
-
await
|
|
8721
|
+
await sleep3(2e3, aborter.signal);
|
|
7164
8722
|
} catch (err) {
|
|
7165
8723
|
if (aborter.signal.aborted) break;
|
|
7166
8724
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -7169,7 +8727,7 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
7169
8727
|
reconnecting in ${backoffMs}ms\u2026
|
|
7170
8728
|
`
|
|
7171
8729
|
);
|
|
7172
|
-
await
|
|
8730
|
+
await sleep3(backoffMs, aborter.signal);
|
|
7173
8731
|
backoffMs = Math.min(backoffMs * 2, backoffMax);
|
|
7174
8732
|
}
|
|
7175
8733
|
}
|
|
@@ -7182,10 +8740,10 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
7182
8740
|
};
|
|
7183
8741
|
if (opts.token) headers.authorization = `Bearer ${opts.token}`;
|
|
7184
8742
|
const ws = new WebSocket2(opts.connect, { headers });
|
|
7185
|
-
await new Promise((
|
|
8743
|
+
await new Promise((resolve9, reject) => {
|
|
7186
8744
|
const onOpen = () => {
|
|
7187
8745
|
ws.off("error", onError);
|
|
7188
|
-
|
|
8746
|
+
resolve9();
|
|
7189
8747
|
};
|
|
7190
8748
|
const onError = (err) => {
|
|
7191
8749
|
ws.off("open", onOpen);
|
|
@@ -7239,14 +8797,14 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
7239
8797
|
} catch {
|
|
7240
8798
|
}
|
|
7241
8799
|
}
|
|
7242
|
-
return await new Promise((
|
|
8800
|
+
return await new Promise((resolve9, reject) => {
|
|
7243
8801
|
const sock = new WebSocket2(url, protocols ? [...protocols] : void 0, {
|
|
7244
8802
|
headers: upstreamHeaders
|
|
7245
8803
|
});
|
|
7246
8804
|
const onceOpen = () => {
|
|
7247
8805
|
sock.off("error", onceError);
|
|
7248
8806
|
sock.off("unexpected-response", onceUnexpected);
|
|
7249
|
-
|
|
8807
|
+
resolve9({
|
|
7250
8808
|
protocol: sock.protocol ?? "",
|
|
7251
8809
|
send: (data, sendOpts) => {
|
|
7252
8810
|
sock.send(data, { binary: sendOpts.binary });
|
|
@@ -7320,31 +8878,31 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
7320
8878
|
}
|
|
7321
8879
|
}
|
|
7322
8880
|
});
|
|
7323
|
-
await new Promise((
|
|
8881
|
+
await new Promise((resolve9) => {
|
|
7324
8882
|
const offClose = sink.onClose(() => {
|
|
7325
8883
|
clearInterval(keepaliveInterval);
|
|
7326
8884
|
offClose();
|
|
7327
|
-
|
|
8885
|
+
resolve9();
|
|
7328
8886
|
});
|
|
7329
8887
|
if (signal.aborted) {
|
|
7330
8888
|
clearInterval(keepaliveInterval);
|
|
7331
|
-
server.close().finally(() =>
|
|
8889
|
+
server.close().finally(() => resolve9());
|
|
7332
8890
|
}
|
|
7333
8891
|
signal.addEventListener("abort", () => {
|
|
7334
8892
|
clearInterval(keepaliveInterval);
|
|
7335
|
-
server.close().finally(() =>
|
|
8893
|
+
server.close().finally(() => resolve9());
|
|
7336
8894
|
});
|
|
7337
8895
|
});
|
|
7338
8896
|
process.stderr.write(`agentproto serve: tunnel closed.
|
|
7339
8897
|
`);
|
|
7340
8898
|
}
|
|
7341
|
-
function
|
|
7342
|
-
return new Promise((
|
|
7343
|
-
if (signal.aborted) return
|
|
7344
|
-
const timer = setTimeout(
|
|
8899
|
+
function sleep3(ms, signal) {
|
|
8900
|
+
return new Promise((resolve9) => {
|
|
8901
|
+
if (signal.aborted) return resolve9();
|
|
8902
|
+
const timer = setTimeout(resolve9, ms);
|
|
7345
8903
|
signal.addEventListener("abort", () => {
|
|
7346
8904
|
clearTimeout(timer);
|
|
7347
|
-
|
|
8905
|
+
resolve9();
|
|
7348
8906
|
});
|
|
7349
8907
|
});
|
|
7350
8908
|
}
|
|
@@ -7391,7 +8949,7 @@ var color = _isTty ? {
|
|
|
7391
8949
|
cyan: "",
|
|
7392
8950
|
red: ""
|
|
7393
8951
|
};
|
|
7394
|
-
var
|
|
8952
|
+
var USAGE4 = `agentproto workspace \u2014 manage local workspaces
|
|
7395
8953
|
|
|
7396
8954
|
Usage:
|
|
7397
8955
|
agentproto workspace add <path> [--slug <slug>] [--label <text>]
|
|
@@ -7404,7 +8962,7 @@ Config file: ${DEFAULT_CONFIG_PATH()}
|
|
|
7404
8962
|
`;
|
|
7405
8963
|
async function runWorkspace(args) {
|
|
7406
8964
|
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
7407
|
-
process.stdout.write(
|
|
8965
|
+
process.stdout.write(USAGE4);
|
|
7408
8966
|
return 0;
|
|
7409
8967
|
}
|
|
7410
8968
|
const sub = args[0];
|
|
@@ -7414,7 +8972,7 @@ async function runWorkspace(args) {
|
|
|
7414
8972
|
return runAdd(rest);
|
|
7415
8973
|
case "list":
|
|
7416
8974
|
case "ls":
|
|
7417
|
-
return
|
|
8975
|
+
return runList2(rest);
|
|
7418
8976
|
case "remove":
|
|
7419
8977
|
case "rm":
|
|
7420
8978
|
return runRemove(rest);
|
|
@@ -7424,7 +8982,7 @@ async function runWorkspace(args) {
|
|
|
7424
8982
|
process.stderr.write(
|
|
7425
8983
|
`agentproto workspace: unknown subcommand '${sub}'
|
|
7426
8984
|
|
|
7427
|
-
${
|
|
8985
|
+
${USAGE4}`
|
|
7428
8986
|
);
|
|
7429
8987
|
return 2;
|
|
7430
8988
|
}
|
|
@@ -7469,7 +9027,7 @@ async function runAdd(args) {
|
|
|
7469
9027
|
);
|
|
7470
9028
|
return 0;
|
|
7471
9029
|
}
|
|
7472
|
-
async function
|
|
9030
|
+
async function runList2(args) {
|
|
7473
9031
|
const { values } = parseArgs({
|
|
7474
9032
|
args: [...args],
|
|
7475
9033
|
allowPositionals: false,
|
|
@@ -7619,7 +9177,7 @@ function probeMtimeLatestJsonl2(storeRel) {
|
|
|
7619
9177
|
}
|
|
7620
9178
|
|
|
7621
9179
|
// src/commands/sessions.ts
|
|
7622
|
-
var
|
|
9180
|
+
var USAGE5 = `agentproto sessions \u2014 browse and control daemon sessions
|
|
7623
9181
|
|
|
7624
9182
|
Usage:
|
|
7625
9183
|
agentproto sessions [--watch] [--json]
|
|
@@ -7643,7 +9201,7 @@ While attached:
|
|
|
7643
9201
|
`;
|
|
7644
9202
|
async function runSessions(args) {
|
|
7645
9203
|
if (args.includes("--help") || args.includes("-h")) {
|
|
7646
|
-
process.stdout.write(
|
|
9204
|
+
process.stdout.write(USAGE5);
|
|
7647
9205
|
return 0;
|
|
7648
9206
|
}
|
|
7649
9207
|
const sub = args[0];
|
|
@@ -7978,9 +9536,9 @@ function printNoDaemonError(report, verb) {
|
|
|
7978
9536
|
}
|
|
7979
9537
|
async function readRuntimeJsonWithStatus(workspacePath) {
|
|
7980
9538
|
const path = resolve(workspacePath, ".agentproto", "runtime.json");
|
|
7981
|
-
let
|
|
9539
|
+
let stat5;
|
|
7982
9540
|
try {
|
|
7983
|
-
|
|
9541
|
+
stat5 = await promises.stat(path);
|
|
7984
9542
|
} catch {
|
|
7985
9543
|
return { endpoint: null };
|
|
7986
9544
|
}
|
|
@@ -8003,7 +9561,7 @@ async function readRuntimeJsonWithStatus(workspacePath) {
|
|
|
8003
9561
|
stale: {
|
|
8004
9562
|
path,
|
|
8005
9563
|
pid: parsed.pid ?? null,
|
|
8006
|
-
mtime:
|
|
9564
|
+
mtime: stat5.mtime ?? null
|
|
8007
9565
|
}
|
|
8008
9566
|
};
|
|
8009
9567
|
}
|
|
@@ -8804,7 +10362,7 @@ function stripAnsi(s) {
|
|
|
8804
10362
|
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
8805
10363
|
}
|
|
8806
10364
|
function httpDelete(url, token) {
|
|
8807
|
-
return new Promise((
|
|
10365
|
+
return new Promise((resolve9, reject) => {
|
|
8808
10366
|
const u = new URL(url);
|
|
8809
10367
|
const lib = u.protocol === "https:" ? https : http;
|
|
8810
10368
|
const headers = {};
|
|
@@ -8820,7 +10378,7 @@ function httpDelete(url, token) {
|
|
|
8820
10378
|
return;
|
|
8821
10379
|
}
|
|
8822
10380
|
try {
|
|
8823
|
-
|
|
10381
|
+
resolve9(raw ? JSON.parse(raw) : {});
|
|
8824
10382
|
} catch (err) {
|
|
8825
10383
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
8826
10384
|
}
|
|
@@ -9387,21 +10945,21 @@ async function runPtyAttach(endpoint, desc, _colour) {
|
|
|
9387
10945
|
});
|
|
9388
10946
|
}
|
|
9389
10947
|
async function probeDaemonHealth(baseUrl) {
|
|
9390
|
-
return new Promise((
|
|
10948
|
+
return new Promise((resolve9) => {
|
|
9391
10949
|
try {
|
|
9392
10950
|
const u = new URL(`${baseUrl}/health`);
|
|
9393
10951
|
const lib = u.protocol === "https:" ? https : http;
|
|
9394
10952
|
const req = lib.get(u, { timeout: 500 }, (res) => {
|
|
9395
|
-
|
|
10953
|
+
resolve9((res.statusCode ?? 0) >= 200 && (res.statusCode ?? 0) < 300);
|
|
9396
10954
|
res.resume();
|
|
9397
10955
|
});
|
|
9398
|
-
req.on("error", () =>
|
|
10956
|
+
req.on("error", () => resolve9(false));
|
|
9399
10957
|
req.on("timeout", () => {
|
|
9400
10958
|
req.destroy();
|
|
9401
|
-
|
|
10959
|
+
resolve9(false);
|
|
9402
10960
|
});
|
|
9403
10961
|
} catch {
|
|
9404
|
-
|
|
10962
|
+
resolve9(false);
|
|
9405
10963
|
}
|
|
9406
10964
|
});
|
|
9407
10965
|
}
|
|
@@ -9441,7 +10999,7 @@ async function explain401(endpoint, verb) {
|
|
|
9441
10999
|
return lines.join("\n");
|
|
9442
11000
|
}
|
|
9443
11001
|
function httpPostJson(url, body, token) {
|
|
9444
|
-
return new Promise((
|
|
11002
|
+
return new Promise((resolve9, reject) => {
|
|
9445
11003
|
const u = new URL(url);
|
|
9446
11004
|
const payload = Buffer.from(JSON.stringify(body), "utf8");
|
|
9447
11005
|
const lib = u.protocol === "https:" ? https : http;
|
|
@@ -9464,7 +11022,7 @@ function httpPostJson(url, body, token) {
|
|
|
9464
11022
|
return;
|
|
9465
11023
|
}
|
|
9466
11024
|
try {
|
|
9467
|
-
|
|
11025
|
+
resolve9(JSON.parse(raw));
|
|
9468
11026
|
} catch (err) {
|
|
9469
11027
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
9470
11028
|
}
|
|
@@ -9480,7 +11038,7 @@ async function httpGetJson(url) {
|
|
|
9480
11038
|
return await httpGetJsonImpl(url);
|
|
9481
11039
|
}
|
|
9482
11040
|
function httpGetJsonImpl(url) {
|
|
9483
|
-
return new Promise((
|
|
11041
|
+
return new Promise((resolve9, reject) => {
|
|
9484
11042
|
const u = new URL(url);
|
|
9485
11043
|
const lib = u.protocol === "https:" ? https : http;
|
|
9486
11044
|
lib.get(u, (res) => {
|
|
@@ -9493,7 +11051,7 @@ function httpGetJsonImpl(url) {
|
|
|
9493
11051
|
return;
|
|
9494
11052
|
}
|
|
9495
11053
|
try {
|
|
9496
|
-
|
|
11054
|
+
resolve9(JSON.parse(body));
|
|
9497
11055
|
} catch (err) {
|
|
9498
11056
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
9499
11057
|
}
|
|
@@ -9503,15 +11061,18 @@ function httpGetJsonImpl(url) {
|
|
|
9503
11061
|
}
|
|
9504
11062
|
|
|
9505
11063
|
// src/cli.ts
|
|
9506
|
-
var
|
|
11064
|
+
var USAGE7 = `agentproto \u2014 AIP-45 agent CLI host
|
|
9507
11065
|
|
|
9508
11066
|
Usage:
|
|
9509
11067
|
agentproto auth <login|status|logout> [--host <url>] [--label <name>]
|
|
9510
11068
|
agentproto config <show|path|get|set|unset|edit> [args]
|
|
9511
11069
|
agentproto daemon <install|uninstall|start|stop|status|logs> [args]
|
|
9512
11070
|
agentproto install <slug> [--force] [--dry-run] [--skip-setup]
|
|
11071
|
+
<slug> \u2208 { <adapter-slug> | runtime-profile/<name> }
|
|
11072
|
+
agentproto plugins <list|show|install|uninstall|enable|disable> [args]
|
|
9513
11073
|
agentproto setup <slug> [--force] [--dry-run] [--only <stepId>...]
|
|
9514
11074
|
agentproto run <slug> [--cwd <dir>] [--prompt <text>] [--resume <session-id>]
|
|
11075
|
+
agentproto run-swarm --manifest <path> [--once] [--interval <ms|Ns>] [--verbose]
|
|
9515
11076
|
agentproto serve [--workspace <dir>] [--port <n>] [--bind <ip>]
|
|
9516
11077
|
[--connect <url> [--token <jwt>] [--label <name>]]
|
|
9517
11078
|
[--allow-origin <url> \u2026] [--interactive | -i]
|
|
@@ -9530,8 +11091,10 @@ Usage:
|
|
|
9530
11091
|
Examples:
|
|
9531
11092
|
agentproto auth login --host wss://guilde.work # device flow \u2192 ~/.agentproto/credentials.json
|
|
9532
11093
|
agentproto install claude-code
|
|
11094
|
+
agentproto install runtime-profile/standard # drops .claude/ swarm scaffolding into the cwd
|
|
9533
11095
|
agentproto setup openclaw # re-run setup (idempotent via skip_if + ledger)
|
|
9534
11096
|
agentproto run claude-code --cwd . --prompt "summarise this repo"
|
|
11097
|
+
agentproto run-swarm --manifest .runtime/local.yaml --verbose
|
|
9535
11098
|
agentproto workspace add ~/code/my-project --slug my-project
|
|
9536
11099
|
agentproto workspace list
|
|
9537
11100
|
agentproto serve --connect wss://guilde.work/api/v1/agentproto/tunnel
|
|
@@ -9548,8 +11111,10 @@ var VERBS = /* @__PURE__ */ new Set([
|
|
|
9548
11111
|
"config",
|
|
9549
11112
|
"daemon",
|
|
9550
11113
|
"install",
|
|
11114
|
+
"plugins",
|
|
9551
11115
|
"setup",
|
|
9552
11116
|
"run",
|
|
11117
|
+
"run-swarm",
|
|
9553
11118
|
"serve",
|
|
9554
11119
|
"workspace",
|
|
9555
11120
|
"sessions"
|
|
@@ -9562,13 +11127,13 @@ async function main(argv) {
|
|
|
9562
11127
|
return 0;
|
|
9563
11128
|
}
|
|
9564
11129
|
if (argv.includes("--help") || argv.includes("-h") || argv.length === 0) {
|
|
9565
|
-
process.stdout.write(
|
|
11130
|
+
process.stdout.write(USAGE7);
|
|
9566
11131
|
return 0;
|
|
9567
11132
|
}
|
|
9568
11133
|
process.stderr.write(
|
|
9569
11134
|
`agentproto: unrecognised argument(s): ${argv.join(" ")}
|
|
9570
11135
|
|
|
9571
|
-
${
|
|
11136
|
+
${USAGE7}`
|
|
9572
11137
|
);
|
|
9573
11138
|
return 2;
|
|
9574
11139
|
}
|
|
@@ -9585,10 +11150,14 @@ ${USAGE6}`
|
|
|
9585
11150
|
}
|
|
9586
11151
|
case "install":
|
|
9587
11152
|
return runInstall(rest);
|
|
11153
|
+
case "plugins":
|
|
11154
|
+
return runPlugins(rest);
|
|
9588
11155
|
case "setup":
|
|
9589
11156
|
return runSetupCommand(rest);
|
|
9590
11157
|
case "run":
|
|
9591
11158
|
return runRun(rest);
|
|
11159
|
+
case "run-swarm":
|
|
11160
|
+
return runRunSwarm(rest);
|
|
9592
11161
|
case "serve":
|
|
9593
11162
|
return runServe(rest);
|
|
9594
11163
|
case "workspace":
|
|
@@ -9598,7 +11167,7 @@ ${USAGE6}`
|
|
|
9598
11167
|
default:
|
|
9599
11168
|
process.stderr.write(`agentproto: unknown verb '${verb}'
|
|
9600
11169
|
|
|
9601
|
-
${
|
|
11170
|
+
${USAGE7}`);
|
|
9602
11171
|
return 2;
|
|
9603
11172
|
}
|
|
9604
11173
|
}
|