@agentproto/cli 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.mjs +807 -171
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.ts +14 -0
- package/dist/index.mjs +706 -94
- package/dist/index.mjs.map +1 -1
- package/dist/registry/builtins.mjs +78 -54
- package/dist/registry/builtins.mjs.map +1 -1
- package/dist/registry/manifest.mjs +1 -1
- package/dist/registry/plugins.mjs +1 -1
- package/dist/registry/runtime.mjs +1 -1
- package/dist/util/credentials.mjs +1 -1
- package/package.json +7 -5
package/dist/cli.mjs
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { promises, existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
3
3
|
import { homedir, userInfo, hostname, platform, tmpdir } from 'os';
|
|
4
|
-
import { resolve,
|
|
4
|
+
import { resolve, isAbsolute, join, dirname, basename, normalize as normalize$1, relative } from 'path';
|
|
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 {
|
|
8
|
+
import { rm, readFile, mkdir, writeFile, readdir, unlink, chmod, stat, mkdtemp, appendFile } from 'fs/promises';
|
|
9
9
|
import { randomUUID, randomBytes, createHash } from 'crypto';
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
10
11
|
import { createInterface } from 'readline/promises';
|
|
11
12
|
import { stdout, stdin } from 'process';
|
|
12
13
|
import { createRequire } from 'module';
|
|
13
|
-
import { pathToFileURL } from 'url';
|
|
14
14
|
import { z } from 'zod';
|
|
15
15
|
import { createAgentCliRuntime } from '@agentproto/driver-agent-cli';
|
|
16
16
|
import matter3 from 'gray-matter';
|
|
17
|
-
import { wrapWebSocket, createTunnelServer } from '@agentproto/acp/tunnel';
|
|
17
|
+
import { wrapWebSocket, createTunnelServer, DEFAULT_WS_DIAL_TIMEOUT_MS, DEFAULT_HTTP_FORWARD_TIMEOUT_MS } from '@agentproto/acp/tunnel';
|
|
18
18
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
19
19
|
import '@modelcontextprotocol/sdk/server/stdio.js';
|
|
20
|
+
import { driverSpec } from '@agentproto/driver';
|
|
20
21
|
import { EventEmitter } from 'events';
|
|
21
22
|
import http, { createServer } from 'http';
|
|
22
23
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
@@ -28,7 +29,7 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
|
28
29
|
import https from 'https';
|
|
29
30
|
|
|
30
31
|
/**
|
|
31
|
-
* @agentproto/cli v0.1.
|
|
32
|
+
* @agentproto/cli v0.1.2
|
|
32
33
|
* The `agentproto` binary — install / run / serve AIP-45 agent CLIs.
|
|
33
34
|
*/
|
|
34
35
|
var __defProp = Object.defineProperty;
|
|
@@ -389,7 +390,7 @@ function xmlEscape(s) {
|
|
|
389
390
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
390
391
|
}
|
|
391
392
|
function launchctl(args) {
|
|
392
|
-
return new Promise((
|
|
393
|
+
return new Promise((resolve10) => {
|
|
393
394
|
const child = spawn("launchctl", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
394
395
|
let stdout = "";
|
|
395
396
|
let stderr = "";
|
|
@@ -397,9 +398,9 @@ function launchctl(args) {
|
|
|
397
398
|
child.stderr?.setEncoding("utf8").on("data", (c) => stderr += c);
|
|
398
399
|
child.on(
|
|
399
400
|
"error",
|
|
400
|
-
(err) =>
|
|
401
|
+
(err) => resolve10({ code: 127, stdout, stderr: err.message })
|
|
401
402
|
);
|
|
402
|
-
child.on("exit", (code) =>
|
|
403
|
+
child.on("exit", (code) => resolve10({ code: code ?? 1, stdout, stderr }));
|
|
403
404
|
});
|
|
404
405
|
}
|
|
405
406
|
function humaniseUptime(ms) {
|
|
@@ -844,7 +845,7 @@ async function postForm(url, body) {
|
|
|
844
845
|
return await res.json();
|
|
845
846
|
}
|
|
846
847
|
function sleep(ms) {
|
|
847
|
-
return new Promise((
|
|
848
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
848
849
|
}
|
|
849
850
|
function formatDuration(ms) {
|
|
850
851
|
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
@@ -855,16 +856,16 @@ function openBrowser(url) {
|
|
|
855
856
|
const p = platform();
|
|
856
857
|
const cmd = p === "darwin" ? "open" : p === "win32" ? "cmd" : "xdg-open";
|
|
857
858
|
const args = p === "win32" ? ["/c", "start", url] : [url];
|
|
858
|
-
return new Promise((
|
|
859
|
+
return new Promise((resolve10) => {
|
|
859
860
|
try {
|
|
860
861
|
const child = spawn(cmd, args, { stdio: "ignore", detached: true });
|
|
861
|
-
child.once("error", () =>
|
|
862
|
+
child.once("error", () => resolve10());
|
|
862
863
|
child.once("spawn", () => {
|
|
863
864
|
child.unref();
|
|
864
|
-
|
|
865
|
+
resolve10();
|
|
865
866
|
});
|
|
866
867
|
} catch {
|
|
867
|
-
|
|
868
|
+
resolve10();
|
|
868
869
|
}
|
|
869
870
|
});
|
|
870
871
|
}
|
|
@@ -993,7 +994,7 @@ async function runEdit() {
|
|
|
993
994
|
const cfg = await loadConfig();
|
|
994
995
|
await saveConfig(cfg);
|
|
995
996
|
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
996
|
-
return new Promise((
|
|
997
|
+
return new Promise((resolve10) => {
|
|
997
998
|
const child = spawn(editor, [CONFIG_FILE_PATH()], {
|
|
998
999
|
stdio: "inherit"
|
|
999
1000
|
});
|
|
@@ -1002,9 +1003,9 @@ async function runEdit() {
|
|
|
1002
1003
|
`agentproto config edit: failed to launch ${editor}: ${err.message}
|
|
1003
1004
|
`
|
|
1004
1005
|
);
|
|
1005
|
-
|
|
1006
|
+
resolve10(1);
|
|
1006
1007
|
});
|
|
1007
|
-
child.on("exit", (code) =>
|
|
1008
|
+
child.on("exit", (code) => resolve10(code ?? 0));
|
|
1008
1009
|
});
|
|
1009
1010
|
}
|
|
1010
1011
|
function parseValue(raw) {
|
|
@@ -1031,27 +1032,40 @@ async function resolveAdapter(slug) {
|
|
|
1031
1032
|
);
|
|
1032
1033
|
}
|
|
1033
1034
|
const packageName = `@agentproto/adapter-${slug}`;
|
|
1035
|
+
const camel = slugToCamel(slug);
|
|
1034
1036
|
let mod;
|
|
1037
|
+
let resolvedPackageName = packageName;
|
|
1035
1038
|
try {
|
|
1036
1039
|
mod = await import(packageName);
|
|
1037
|
-
} catch (
|
|
1038
|
-
const
|
|
1040
|
+
} catch (primaryErr) {
|
|
1041
|
+
const hyphen = slug.lastIndexOf("-");
|
|
1042
|
+
if (hyphen > 0) {
|
|
1043
|
+
const parentPkg = `@agentproto/adapter-${slug.slice(0, hyphen)}`;
|
|
1044
|
+
try {
|
|
1045
|
+
const parentMod = await import(parentPkg);
|
|
1046
|
+
const parentCandidate = parentMod[camel];
|
|
1047
|
+
if (parentCandidate && typeof parentCandidate === "object" && "name" in parentCandidate) {
|
|
1048
|
+
return { slug, handle: parentCandidate, source: "npm", packageName: parentPkg };
|
|
1049
|
+
}
|
|
1050
|
+
} catch {
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
const cause = primaryErr instanceof Error ? primaryErr.message : String(primaryErr);
|
|
1039
1054
|
throw new Error(
|
|
1040
1055
|
`agentproto: could not load adapter '${slug}'. Tried '${packageName}'. Install it with: npm i -g ${packageName}
|
|
1041
1056
|
cause: ${cause}`
|
|
1042
1057
|
);
|
|
1043
1058
|
}
|
|
1044
|
-
const camel = slugToCamel(slug);
|
|
1045
1059
|
const candidate = mod[camel] ?? mod.default ?? mod.handle;
|
|
1046
1060
|
if (!candidate || typeof candidate !== "object" || !("name" in candidate)) {
|
|
1047
1061
|
throw new Error(
|
|
1048
|
-
`agentproto: adapter '${
|
|
1062
|
+
`agentproto: adapter '${resolvedPackageName}' does not export an AgentCliHandle (looked for export '${camel}', 'default', or 'handle').`
|
|
1049
1063
|
);
|
|
1050
1064
|
}
|
|
1051
|
-
return { slug, handle: candidate, source: "npm", packageName };
|
|
1065
|
+
return { slug, handle: candidate, source: "npm", packageName: resolvedPackageName };
|
|
1052
1066
|
}
|
|
1053
1067
|
async function listInstalledAdapters(opts) {
|
|
1054
|
-
const roots = await collectAgentprotoNamespaceRoots(
|
|
1068
|
+
const roots = await collectAgentprotoNamespaceRoots();
|
|
1055
1069
|
const seen = /* @__PURE__ */ new Set();
|
|
1056
1070
|
const out = [];
|
|
1057
1071
|
for (const root of roots) {
|
|
@@ -1069,6 +1083,7 @@ async function listInstalledAdapters(opts) {
|
|
|
1069
1083
|
try {
|
|
1070
1084
|
const resolved = await resolveAdapter(slug);
|
|
1071
1085
|
const handle = resolved.handle;
|
|
1086
|
+
const modelsField = handle.models?.allowed;
|
|
1072
1087
|
const info = {
|
|
1073
1088
|
slug,
|
|
1074
1089
|
name: typeof handle.name === "string" ? handle.name : slug,
|
|
@@ -1076,7 +1091,9 @@ async function listInstalledAdapters(opts) {
|
|
|
1076
1091
|
description: typeof handle.description === "string" ? handle.description : "",
|
|
1077
1092
|
protocol: typeof handle.protocol === "string" ? handle.protocol : "unknown",
|
|
1078
1093
|
streaming: !!handle.capabilities?.streaming,
|
|
1079
|
-
packageName: resolved.packageName ?? `@agentproto/adapter-${slug}
|
|
1094
|
+
packageName: resolved.packageName ?? `@agentproto/adapter-${slug}`,
|
|
1095
|
+
commands: Array.isArray(handle.commands) ? handle.commands : [],
|
|
1096
|
+
models: Array.isArray(modelsField) ? modelsField.filter((m) => typeof m === "string") : []
|
|
1080
1097
|
};
|
|
1081
1098
|
out.push(info);
|
|
1082
1099
|
} catch (err) {
|
|
@@ -1092,26 +1109,95 @@ async function listInstalledAdapters(opts) {
|
|
|
1092
1109
|
return out.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
1093
1110
|
}
|
|
1094
1111
|
async function collectAgentprotoNamespaceRoots(start) {
|
|
1112
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1095
1113
|
const roots = [];
|
|
1096
|
-
let cur = start ?? process.cwd();
|
|
1097
1114
|
const candidatesAt = (dir) => [
|
|
1098
1115
|
resolve(dir, "node_modules", "@agentproto"),
|
|
1099
1116
|
resolve(dir, "node_modules", ".pnpm", "node_modules", "@agentproto")
|
|
1100
1117
|
];
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1118
|
+
async function walkUp(from) {
|
|
1119
|
+
let cur = from;
|
|
1120
|
+
for (let depth = 0; depth < 20; depth++) {
|
|
1121
|
+
if (seen.has(cur)) break;
|
|
1122
|
+
seen.add(cur);
|
|
1123
|
+
for (const candidate of candidatesAt(cur)) {
|
|
1124
|
+
try {
|
|
1125
|
+
const s = await promises.stat(candidate);
|
|
1126
|
+
if (s.isDirectory() && !roots.includes(candidate)) roots.push(candidate);
|
|
1127
|
+
} catch {
|
|
1128
|
+
}
|
|
1107
1129
|
}
|
|
1130
|
+
const parent = resolve(cur, "..");
|
|
1131
|
+
if (parent === cur) break;
|
|
1132
|
+
cur = parent;
|
|
1108
1133
|
}
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1134
|
+
}
|
|
1135
|
+
await walkUp(process.cwd());
|
|
1136
|
+
try {
|
|
1137
|
+
await walkUp(dirname(fileURLToPath(import.meta.url)));
|
|
1138
|
+
} catch {
|
|
1112
1139
|
}
|
|
1113
1140
|
return roots;
|
|
1114
1141
|
}
|
|
1142
|
+
async function listAdaptersWithCatalog(catalog) {
|
|
1143
|
+
const seenSlugs = /* @__PURE__ */ new Set();
|
|
1144
|
+
const out = [];
|
|
1145
|
+
const agentprotoHome = process.env["AGENTPROTO_HOME"] ?? join(homedir(), ".agentproto");
|
|
1146
|
+
async function hasSetupLedger(slug) {
|
|
1147
|
+
try {
|
|
1148
|
+
await promises.access(join(agentprotoHome, "setup", `${slug}.json`));
|
|
1149
|
+
return true;
|
|
1150
|
+
} catch {
|
|
1151
|
+
return false;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
for (const entry of catalog) {
|
|
1155
|
+
seenSlugs.add(entry.slug);
|
|
1156
|
+
try {
|
|
1157
|
+
const resolved = await resolveAdapter(entry.slug);
|
|
1158
|
+
const handle = resolved.handle;
|
|
1159
|
+
const setupSteps = Array.isArray(handle.setup) ? handle.setup : [];
|
|
1160
|
+
const ledgerPresent = await hasSetupLedger(entry.slug);
|
|
1161
|
+
const status = setupSteps.length === 0 || ledgerPresent ? "ready" : "available";
|
|
1162
|
+
const catalogModels = handle.models?.allowed;
|
|
1163
|
+
out.push({
|
|
1164
|
+
slug: entry.slug,
|
|
1165
|
+
name: typeof handle.name === "string" ? handle.name : entry.name,
|
|
1166
|
+
version: typeof handle.version === "string" ? handle.version : "?",
|
|
1167
|
+
description: typeof handle.description === "string" ? handle.description : entry.description,
|
|
1168
|
+
protocol: typeof handle.protocol === "string" ? handle.protocol : "unknown",
|
|
1169
|
+
streaming: !!handle.capabilities?.streaming,
|
|
1170
|
+
packageName: resolved.packageName ?? entry.packageName,
|
|
1171
|
+
commands: Array.isArray(handle.commands) ? handle.commands : [],
|
|
1172
|
+
models: Array.isArray(catalogModels) ? catalogModels.filter((m) => typeof m === "string") : [],
|
|
1173
|
+
status,
|
|
1174
|
+
hint: entry.hint
|
|
1175
|
+
});
|
|
1176
|
+
} catch {
|
|
1177
|
+
out.push({
|
|
1178
|
+
slug: entry.slug,
|
|
1179
|
+
name: entry.name,
|
|
1180
|
+
version: "not installed",
|
|
1181
|
+
description: entry.description,
|
|
1182
|
+
protocol: "unknown",
|
|
1183
|
+
streaming: false,
|
|
1184
|
+
packageName: entry.packageName,
|
|
1185
|
+
commands: [],
|
|
1186
|
+
models: [],
|
|
1187
|
+
status: "supported",
|
|
1188
|
+
hint: entry.hint
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
const installed = await listInstalledAdapters();
|
|
1193
|
+
for (const info of installed) {
|
|
1194
|
+
if (seenSlugs.has(info.slug)) continue;
|
|
1195
|
+
seenSlugs.add(info.slug);
|
|
1196
|
+
const ledgerPresent = await hasSetupLedger(info.slug);
|
|
1197
|
+
out.push({ ...info, status: ledgerPresent ? "ready" : "available" });
|
|
1198
|
+
}
|
|
1199
|
+
return out;
|
|
1200
|
+
}
|
|
1115
1201
|
async function runSetup(opts) {
|
|
1116
1202
|
const steps = opts.handle.setup ?? [];
|
|
1117
1203
|
if (steps.length === 0) {
|
|
@@ -1285,10 +1371,10 @@ async function runExternalStep(step, ledger, head) {
|
|
|
1285
1371
|
`);
|
|
1286
1372
|
const opener = platform() === "darwin" ? "open" : platform() === "win32" ? "cmd" : "xdg-open";
|
|
1287
1373
|
const args = platform() === "win32" ? ["/c", "start", step.url] : [step.url];
|
|
1288
|
-
await new Promise((
|
|
1374
|
+
await new Promise((resolve10) => {
|
|
1289
1375
|
const child = spawn(opener, args, { stdio: "ignore", detached: true });
|
|
1290
|
-
child.once("error", () =>
|
|
1291
|
-
child.once("spawn", () =>
|
|
1376
|
+
child.once("error", () => resolve10());
|
|
1377
|
+
child.once("spawn", () => resolve10());
|
|
1292
1378
|
});
|
|
1293
1379
|
let value = "";
|
|
1294
1380
|
if (step.callback?.param) {
|
|
@@ -1361,7 +1447,7 @@ async function promptString(question, opts) {
|
|
|
1361
1447
|
process.stdin.setRawMode?.(true);
|
|
1362
1448
|
let buf = "";
|
|
1363
1449
|
process.stdout.write(prompt);
|
|
1364
|
-
return new Promise((
|
|
1450
|
+
return new Promise((resolve10) => {
|
|
1365
1451
|
const onData = (chunk) => {
|
|
1366
1452
|
for (const code of chunk) {
|
|
1367
1453
|
if (code === 13 || code === 10) {
|
|
@@ -1369,7 +1455,7 @@ async function promptString(question, opts) {
|
|
|
1369
1455
|
process.stdin.setRawMode?.(false);
|
|
1370
1456
|
process.stdout.write("\n");
|
|
1371
1457
|
rl.close();
|
|
1372
|
-
|
|
1458
|
+
resolve10(buf || opts.defaultValue || "");
|
|
1373
1459
|
return;
|
|
1374
1460
|
}
|
|
1375
1461
|
if (code === 3) {
|
|
@@ -1451,7 +1537,7 @@ async function resolveSelectOptions(options) {
|
|
|
1451
1537
|
});
|
|
1452
1538
|
}
|
|
1453
1539
|
async function runShellCapturing(cmd, opts) {
|
|
1454
|
-
return new Promise((
|
|
1540
|
+
return new Promise((resolve10) => {
|
|
1455
1541
|
const child = spawn("bash", ["-lc", cmd], {
|
|
1456
1542
|
stdio: opts.interactive ? "inherit" : ["ignore", "pipe", "pipe"]
|
|
1457
1543
|
});
|
|
@@ -1469,11 +1555,11 @@ async function runShellCapturing(cmd, opts) {
|
|
|
1469
1555
|
}, opts.timeoutMs);
|
|
1470
1556
|
child.once("error", () => {
|
|
1471
1557
|
clearTimeout(timer);
|
|
1472
|
-
|
|
1558
|
+
resolve10({ exitCode: 127, stdout, stderr: stderr || "spawn error" });
|
|
1473
1559
|
});
|
|
1474
1560
|
child.once("exit", (code) => {
|
|
1475
1561
|
clearTimeout(timer);
|
|
1476
|
-
|
|
1562
|
+
resolve10({ exitCode: code ?? 0, stdout, stderr });
|
|
1477
1563
|
});
|
|
1478
1564
|
});
|
|
1479
1565
|
}
|
|
@@ -2108,7 +2194,7 @@ async function runDownloadInstaller(opts) {
|
|
|
2108
2194
|
}
|
|
2109
2195
|
if (extractCode !== 0) return extractCode;
|
|
2110
2196
|
const srcBin = join(extractDir, opts.extractBin);
|
|
2111
|
-
const binDir = process.env["AGENTPROTO_BIN_DIR"] ?? join(
|
|
2197
|
+
const binDir = process.env["AGENTPROTO_BIN_DIR"] ?? join(homedir6(), ".local", "bin");
|
|
2112
2198
|
await mkdir(binDir, { recursive: true });
|
|
2113
2199
|
const destBin = join(binDir, opts.extractBin.split("/").pop());
|
|
2114
2200
|
const cpCode = await spawnInherit("cp", ["-p", srcBin, destBin]);
|
|
@@ -2134,19 +2220,19 @@ async function runDownloadInstaller(opts) {
|
|
|
2134
2220
|
});
|
|
2135
2221
|
}
|
|
2136
2222
|
}
|
|
2137
|
-
function
|
|
2223
|
+
function homedir6() {
|
|
2138
2224
|
return process.env["HOME"] ?? process.env["USERPROFILE"] ?? "/";
|
|
2139
2225
|
}
|
|
2140
2226
|
function spawnInherit(cmd, argv) {
|
|
2141
|
-
return new Promise((
|
|
2227
|
+
return new Promise((resolve10, reject) => {
|
|
2142
2228
|
const child = spawn(cmd, argv, { stdio: "inherit" });
|
|
2143
2229
|
child.once("error", reject);
|
|
2144
|
-
child.once("exit", (code) =>
|
|
2230
|
+
child.once("exit", (code) => resolve10(code ?? 0));
|
|
2145
2231
|
});
|
|
2146
2232
|
}
|
|
2147
2233
|
async function runVersionCheck(check) {
|
|
2148
2234
|
if (!check) return { ok: false, message: "no version_check declared" };
|
|
2149
|
-
return new Promise((
|
|
2235
|
+
return new Promise((resolve10) => {
|
|
2150
2236
|
const child = spawn("bash", ["-lc", check.cmd], {
|
|
2151
2237
|
stdio: ["ignore", "pipe", "ignore"]
|
|
2152
2238
|
});
|
|
@@ -2154,19 +2240,19 @@ async function runVersionCheck(check) {
|
|
|
2154
2240
|
child.stdout.on("data", (c) => {
|
|
2155
2241
|
buf += c.toString("utf8");
|
|
2156
2242
|
});
|
|
2157
|
-
child.once("error", () =>
|
|
2243
|
+
child.once("error", () => resolve10({ ok: false, message: "check failed" }));
|
|
2158
2244
|
child.once("exit", (code) => {
|
|
2159
2245
|
if (code !== 0) {
|
|
2160
|
-
|
|
2246
|
+
resolve10({ ok: false, message: `check exited ${code}` });
|
|
2161
2247
|
return;
|
|
2162
2248
|
}
|
|
2163
2249
|
const re = new RegExp(check.parse);
|
|
2164
2250
|
const m = buf.match(re);
|
|
2165
2251
|
if (!m || !m[1]) {
|
|
2166
|
-
|
|
2252
|
+
resolve10({ ok: false, message: "could not parse version" });
|
|
2167
2253
|
return;
|
|
2168
2254
|
}
|
|
2169
|
-
|
|
2255
|
+
resolve10({ ok: true, message: `version ${m[1]}` });
|
|
2170
2256
|
});
|
|
2171
2257
|
});
|
|
2172
2258
|
}
|
|
@@ -3017,6 +3103,7 @@ var FileSubstrate = class {
|
|
|
3017
3103
|
constructor(opts) {
|
|
3018
3104
|
this.opts = opts;
|
|
3019
3105
|
}
|
|
3106
|
+
opts;
|
|
3020
3107
|
kind = "file";
|
|
3021
3108
|
async append(input2) {
|
|
3022
3109
|
const timestamp = input2.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -3142,6 +3229,7 @@ var FileStateStore = class {
|
|
|
3142
3229
|
constructor(opts) {
|
|
3143
3230
|
this.opts = opts;
|
|
3144
3231
|
}
|
|
3232
|
+
opts;
|
|
3145
3233
|
kind = "fs";
|
|
3146
3234
|
async read(participantId) {
|
|
3147
3235
|
const path = this.pathFor(participantId);
|
|
@@ -3177,10 +3265,84 @@ async function ensureDir3(dir) {
|
|
|
3177
3265
|
function isNotFound2(err) {
|
|
3178
3266
|
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
3179
3267
|
}
|
|
3268
|
+
function spawnWithStdin(opts) {
|
|
3269
|
+
const {
|
|
3270
|
+
command,
|
|
3271
|
+
args = [],
|
|
3272
|
+
stdin,
|
|
3273
|
+
cwd,
|
|
3274
|
+
timeoutMs = 9e4,
|
|
3275
|
+
signal,
|
|
3276
|
+
killSignal = "SIGTERM"
|
|
3277
|
+
} = opts;
|
|
3278
|
+
return new Promise((resolve10, reject) => {
|
|
3279
|
+
if (signal?.aborted) {
|
|
3280
|
+
reject(new Error(`${command} aborted before start`));
|
|
3281
|
+
return;
|
|
3282
|
+
}
|
|
3283
|
+
const child = spawn(command, [...args], {
|
|
3284
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
3285
|
+
...cwd ? { cwd } : {}
|
|
3286
|
+
});
|
|
3287
|
+
let out = "";
|
|
3288
|
+
let err = "";
|
|
3289
|
+
let settled = false;
|
|
3290
|
+
const finish = (fn) => {
|
|
3291
|
+
if (settled) return;
|
|
3292
|
+
settled = true;
|
|
3293
|
+
clearTimeout(timer);
|
|
3294
|
+
signal?.removeEventListener("abort", onAbort);
|
|
3295
|
+
fn();
|
|
3296
|
+
};
|
|
3297
|
+
const onAbort = () => {
|
|
3298
|
+
child.kill(killSignal);
|
|
3299
|
+
finish(() => reject(new Error(`${command} aborted`)));
|
|
3300
|
+
};
|
|
3301
|
+
const timer = setTimeout(() => {
|
|
3302
|
+
child.kill(killSignal);
|
|
3303
|
+
finish(() => reject(new Error(`${command} timed out after ${timeoutMs}ms`)));
|
|
3304
|
+
}, timeoutMs);
|
|
3305
|
+
signal?.addEventListener("abort", onAbort);
|
|
3306
|
+
child.stdout.on("data", (d) => out += d);
|
|
3307
|
+
child.stderr.on("data", (d) => err += d);
|
|
3308
|
+
child.on(
|
|
3309
|
+
"error",
|
|
3310
|
+
(e) => finish(() => reject(new Error(`${command} not runnable: ${e.message}`)))
|
|
3311
|
+
);
|
|
3312
|
+
child.on(
|
|
3313
|
+
"close",
|
|
3314
|
+
(code) => finish(() => {
|
|
3315
|
+
if (code === 0) resolve10(out);
|
|
3316
|
+
else
|
|
3317
|
+
reject(
|
|
3318
|
+
new Error(`${command} exited with code ${code}: ${err.trim().slice(0, 200) || "(no stderr)"}`)
|
|
3319
|
+
);
|
|
3320
|
+
})
|
|
3321
|
+
);
|
|
3322
|
+
child.stdin.on("error", () => {
|
|
3323
|
+
});
|
|
3324
|
+
child.stdin.write(stdin);
|
|
3325
|
+
child.stdin.end();
|
|
3326
|
+
});
|
|
3327
|
+
}
|
|
3328
|
+
function parseClaudeJsonOutput(stdout) {
|
|
3329
|
+
try {
|
|
3330
|
+
const parsed = JSON.parse(stdout);
|
|
3331
|
+
if (typeof parsed === "object" && parsed !== null && "result" in parsed && typeof parsed.result === "string") {
|
|
3332
|
+
return parsed.result;
|
|
3333
|
+
}
|
|
3334
|
+
return null;
|
|
3335
|
+
} catch {
|
|
3336
|
+
return null;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
3339
|
+
|
|
3340
|
+
// ../agent-runtime/dist/adapters/participant-agent-cli.mjs
|
|
3180
3341
|
var AgentCliParticipant = class {
|
|
3181
3342
|
constructor(opts) {
|
|
3182
3343
|
this.opts = opts;
|
|
3183
3344
|
}
|
|
3345
|
+
opts;
|
|
3184
3346
|
kind = "agent-cli";
|
|
3185
3347
|
async executeTurn(input2) {
|
|
3186
3348
|
const prompt = await assemblePrompt(input2);
|
|
@@ -3232,58 +3394,6 @@ function looksLikeRoleFile(s) {
|
|
|
3232
3394
|
const lower = s.toLowerCase();
|
|
3233
3395
|
return ROLE_FILE_EXTENSIONS.some((ext) => lower.endsWith(ext));
|
|
3234
3396
|
}
|
|
3235
|
-
async function spawnWithStdin(args) {
|
|
3236
|
-
return new Promise((resolveP, rejectP) => {
|
|
3237
|
-
const proc = spawn(args.command, [...args.args], {
|
|
3238
|
-
cwd: args.cwd,
|
|
3239
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
3240
|
-
});
|
|
3241
|
-
let stdout = "";
|
|
3242
|
-
let stderr = "";
|
|
3243
|
-
const onAbort = () => proc.kill("SIGTERM");
|
|
3244
|
-
args.signal?.addEventListener("abort", onAbort);
|
|
3245
|
-
const timer = setTimeout(() => {
|
|
3246
|
-
proc.kill("SIGTERM");
|
|
3247
|
-
}, args.timeoutMs);
|
|
3248
|
-
proc.stdout.on("data", (chunk) => {
|
|
3249
|
-
stdout += chunk.toString("utf8");
|
|
3250
|
-
});
|
|
3251
|
-
proc.stderr.on("data", (chunk) => {
|
|
3252
|
-
stderr += chunk.toString("utf8");
|
|
3253
|
-
});
|
|
3254
|
-
proc.on("error", (err) => {
|
|
3255
|
-
clearTimeout(timer);
|
|
3256
|
-
args.signal?.removeEventListener("abort", onAbort);
|
|
3257
|
-
rejectP(err);
|
|
3258
|
-
});
|
|
3259
|
-
proc.on("close", (code) => {
|
|
3260
|
-
clearTimeout(timer);
|
|
3261
|
-
args.signal?.removeEventListener("abort", onAbort);
|
|
3262
|
-
if (code === 0) {
|
|
3263
|
-
resolveP(stdout);
|
|
3264
|
-
return;
|
|
3265
|
-
}
|
|
3266
|
-
rejectP(
|
|
3267
|
-
new Error(
|
|
3268
|
-
`agent-cli participant "${args.command}" exited with code ${code}: ${stderr.trim() || "(no stderr)"}`
|
|
3269
|
-
)
|
|
3270
|
-
);
|
|
3271
|
-
});
|
|
3272
|
-
proc.stdin.write(args.stdin);
|
|
3273
|
-
proc.stdin.end();
|
|
3274
|
-
});
|
|
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
|
-
}
|
|
3287
3397
|
|
|
3288
3398
|
// src/registry/builtins.ts
|
|
3289
3399
|
function registerBuiltins() {
|
|
@@ -3700,6 +3810,48 @@ function normalizeConfig(parsed) {
|
|
|
3700
3810
|
if (active !== void 0) out.active = active;
|
|
3701
3811
|
return out;
|
|
3702
3812
|
}
|
|
3813
|
+
var IMPORTED_MCPS_PATH = () => resolve(homedir(), ".agentproto", "imported-mcps.json");
|
|
3814
|
+
var IMPORTED_MCPS_VERSION = 1;
|
|
3815
|
+
var EMPTY = {
|
|
3816
|
+
version: IMPORTED_MCPS_VERSION,
|
|
3817
|
+
imports: []
|
|
3818
|
+
};
|
|
3819
|
+
async function loadImportedMcps(path = IMPORTED_MCPS_PATH()) {
|
|
3820
|
+
let raw;
|
|
3821
|
+
try {
|
|
3822
|
+
raw = await promises.readFile(path, "utf8");
|
|
3823
|
+
} catch (err) {
|
|
3824
|
+
if (err.code === "ENOENT") return EMPTY;
|
|
3825
|
+
throw err;
|
|
3826
|
+
}
|
|
3827
|
+
let parsed;
|
|
3828
|
+
try {
|
|
3829
|
+
parsed = JSON.parse(raw);
|
|
3830
|
+
} catch (err) {
|
|
3831
|
+
throw new Error(
|
|
3832
|
+
`agentproto: ${path} is not valid JSON (${err instanceof Error ? err.message : String(err)}). Delete or fix manually.`
|
|
3833
|
+
);
|
|
3834
|
+
}
|
|
3835
|
+
return normalize(parsed);
|
|
3836
|
+
}
|
|
3837
|
+
function normalize(parsed) {
|
|
3838
|
+
if (!parsed || typeof parsed !== "object") return EMPTY;
|
|
3839
|
+
const obj = parsed;
|
|
3840
|
+
const imports = [];
|
|
3841
|
+
if (Array.isArray(obj.imports)) {
|
|
3842
|
+
for (const entry of obj.imports) {
|
|
3843
|
+
if (!entry || typeof entry !== "object") continue;
|
|
3844
|
+
const e = entry;
|
|
3845
|
+
const id = typeof e.id === "string" ? e.id : "";
|
|
3846
|
+
const alias = typeof e.alias === "string" ? e.alias : id;
|
|
3847
|
+
const addedAt = typeof e.addedAt === "string" ? e.addedAt : (/* @__PURE__ */ new Date()).toISOString();
|
|
3848
|
+
const snapshot = e.snapshot;
|
|
3849
|
+
if (!id || !snapshot) continue;
|
|
3850
|
+
imports.push({ id, alias, addedAt, snapshot });
|
|
3851
|
+
}
|
|
3852
|
+
}
|
|
3853
|
+
return { version: IMPORTED_MCPS_VERSION, imports };
|
|
3854
|
+
}
|
|
3703
3855
|
|
|
3704
3856
|
// ../define-doctype/dist/index.mjs
|
|
3705
3857
|
var DEFAULT_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{1,79}$/;
|
|
@@ -3835,7 +3987,7 @@ function createVerbs(spec) {
|
|
|
3835
3987
|
}
|
|
3836
3988
|
return { path, handle: newHandle, rendered };
|
|
3837
3989
|
}
|
|
3838
|
-
async function
|
|
3990
|
+
async function resolve10(block, ctx = {}) {
|
|
3839
3991
|
if ("inline" in block) {
|
|
3840
3992
|
return spec.define(block.inline);
|
|
3841
3993
|
}
|
|
@@ -3861,7 +4013,7 @@ function createVerbs(spec) {
|
|
|
3861
4013
|
async function deleteFn(path) {
|
|
3862
4014
|
await rm(path, { force: true });
|
|
3863
4015
|
}
|
|
3864
|
-
return { create, load, list, update, resolve:
|
|
4016
|
+
return { create, load, list, update, resolve: resolve10, delete: deleteFn };
|
|
3865
4017
|
}
|
|
3866
4018
|
function defaultBody(spec, frontmatter) {
|
|
3867
4019
|
const id = typeof frontmatter.name === "string" ? frontmatter.name : typeof frontmatter.id === "string" ? frontmatter.id : typeof frontmatter.slug === "string" ? frontmatter.slug : spec.name;
|
|
@@ -3999,8 +4151,374 @@ function resolvePathTemplate(template, handle, doctypeSlug) {
|
|
|
3999
4151
|
const identity = typeof handle.id === "string" && handle.id || typeof handle.slug === "string" && handle.slug || typeof handle.name === "string" && handle.name || "unknown";
|
|
4000
4152
|
return template.replace(/<slug>/g, identity).replace(/<DOCTYPE>/g, doctypeSlug.toUpperCase());
|
|
4001
4153
|
}
|
|
4154
|
+
var agentFrontmatterSchema = z.object({ "schema": z.literal("agent/v1"), "id": z.string().regex(new RegExp("^[a-z0-9@][a-z0-9.@/_-]*$")).min(2).max(80).describe("Machine identifier. Optional @<owner>/ prefix. Unique within the registry that hosts the agent."), "description": z.string().min(1).max(2e3).describe("One-paragraph purpose."), "version": z.string().regex(new RegExp("^\\d+\\.\\d+\\.\\d+(?:[-+][\\w.\\-]+)?$")).describe("Spec version of THIS file.").default("1.0.0"), "extends": z.any().describe("Parent AGENT this extends. Inherits all fields; child overrides win.").optional(), "model": z.any().describe("The brain \u2014 provider/model id string or structured ref."), "identity": z.any().describe("AIP-23 identity ref. Defaults to host policy.").optional(), "persona": z.any().describe("AIP-25 persona ref.").optional(), "runner": z.any().describe("AIP-17 runtime engine ref.").optional(), "tools": z.array(z.any()).describe("AIP-14 tool refs.").default([]), "actions": z.object({ "granted": z.array(z.any()).default([]) }).strict().describe("Explicit action allow-list. POLICY checks union of this + tools' implements.").optional(), "skills": z.array(z.any()).describe("AIP-3 skill refs.").default([]), "workflows": z.array(z.any()).describe("AIP-15 workflow refs.").default([]), "routines": z.array(z.any()).describe("AIP-41 routine refs that auto-fire this agent.").default([]), "delegates_to": z.array(z.any()).describe("Sub-agents this agent may dispatch to (council pattern, AIP-24).").default([]), "memory": z.any().describe("Memory configuration.").optional(), "governance": z.any().describe("AIP-7 governance binding.").optional(), "policy": z.any().describe("AIP-38 POLICY binding.").optional(), "traits": z.record(z.string(), z.number().gte(0).lte(10)).describe("Free-form numeric trait scores (0-10).").default({}), "autonomy": z.number().int().gte(0).lte(10).describe("How much the agent acts vs asks. 0 = always asks, 10 = full autonomy.").default(5), "boundaries": z.array(z.string().min(1)).describe("Hard rules the agent MUST decline / escalate. Surfaced into system prompt.").default([]), "on": z.record(z.string(), z.any().superRefine((x, ctx) => {
|
|
4155
|
+
const schemas = [z.any(), z.array(z.any())];
|
|
4156
|
+
const { errors, failed } = schemas.reduce(
|
|
4157
|
+
({ errors: errors2, failed: failed2 }, schema) => ((result) => result.error ? {
|
|
4158
|
+
errors: [...errors2, ...result.error.issues],
|
|
4159
|
+
failed: failed2 + 1
|
|
4160
|
+
} : { errors: errors2, failed: failed2 })(
|
|
4161
|
+
schema.safeParse(x)
|
|
4162
|
+
),
|
|
4163
|
+
{ errors: [], failed: 0 }
|
|
4164
|
+
);
|
|
4165
|
+
const passed = schemas.length - failed;
|
|
4166
|
+
if (passed !== 1) {
|
|
4167
|
+
ctx.addIssue(errors.length ? {
|
|
4168
|
+
path: [],
|
|
4169
|
+
code: "invalid_union",
|
|
4170
|
+
errors: [errors],
|
|
4171
|
+
message: "Invalid input: Should pass single schema. Passed " + passed
|
|
4172
|
+
} : {
|
|
4173
|
+
path: [],
|
|
4174
|
+
code: "custom",
|
|
4175
|
+
errors: [errors],
|
|
4176
|
+
message: "Invalid input: Should pass single schema. Passed " + passed
|
|
4177
|
+
});
|
|
4178
|
+
}
|
|
4179
|
+
})).describe("Lifecycle hooks. AIP-37 event name -> action-ref(s) to invoke.").default({}), "publish": z.object({ "visibility": z.enum(["private", "unlisted", "public"]).default("private"), "registry": z.string().optional() }).strict().default({ "visibility": "private" }), "tags": z.array(z.string()).default([]), "metadata": z.record(z.string(), z.any()).optional() }).strict().describe("Validates the YAML frontmatter portion of an AIP-42 AGENT.md manifest. Composes identity, persona, model, tools, actions, skills, workflows, runner, memory, governance, policy, routines into a single runnable definition.");
|
|
4180
|
+
var defineAgent = createDoctype({
|
|
4181
|
+
aip: 42,
|
|
4182
|
+
name: "agent",
|
|
4183
|
+
// AIP-42 ids accept an optional `@<owner>/` prefix for namespacing
|
|
4184
|
+
// across registries (e.g. `@agentik/writer`). Bare ids stay valid.
|
|
4185
|
+
idPattern: /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]{0,79}$/,
|
|
4186
|
+
validate(def) {
|
|
4187
|
+
const result = agentFrontmatterSchema.safeParse(def);
|
|
4188
|
+
if (!result.success) {
|
|
4189
|
+
throw new Error(
|
|
4190
|
+
`defineAgent (AIP-42): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
4191
|
+
);
|
|
4192
|
+
}
|
|
4193
|
+
},
|
|
4194
|
+
build(def) {
|
|
4195
|
+
return { ...def };
|
|
4196
|
+
}
|
|
4197
|
+
});
|
|
4198
|
+
function parseAgentManifest(source) {
|
|
4199
|
+
const parsed = matter3(source);
|
|
4200
|
+
if (Object.keys(parsed.data).length === 0) {
|
|
4201
|
+
throw new Error("parseAgentManifest: missing or empty frontmatter");
|
|
4202
|
+
}
|
|
4203
|
+
const result = agentFrontmatterSchema.safeParse(parsed.data);
|
|
4204
|
+
if (!result.success) {
|
|
4205
|
+
throw new Error(
|
|
4206
|
+
`parseAgentManifest: invalid frontmatter \u2014 ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
4207
|
+
);
|
|
4208
|
+
}
|
|
4209
|
+
return { frontmatter: result.data, body: parsed.content };
|
|
4210
|
+
}
|
|
4002
4211
|
|
|
4003
|
-
// ../
|
|
4212
|
+
// ../agent/dist/index.mjs
|
|
4213
|
+
var agentSpec = {
|
|
4214
|
+
name: "agent",
|
|
4215
|
+
aip: 42,
|
|
4216
|
+
schemaLiteral: "agent/v1",
|
|
4217
|
+
pathOf: (h) => `.agents/${h.id}/AGENT.md`,
|
|
4218
|
+
define: defineAgent,
|
|
4219
|
+
parse: (source) => {
|
|
4220
|
+
const m = parseAgentManifest(source);
|
|
4221
|
+
return {
|
|
4222
|
+
frontmatter: m.frontmatter,
|
|
4223
|
+
body: m.body
|
|
4224
|
+
};
|
|
4225
|
+
}
|
|
4226
|
+
};
|
|
4227
|
+
var agentVerbs = createVerbs(agentSpec);
|
|
4228
|
+
var PROVIDER_KINDS = [
|
|
4229
|
+
"cli",
|
|
4230
|
+
"http",
|
|
4231
|
+
"mcp",
|
|
4232
|
+
"sdk",
|
|
4233
|
+
"builtin"
|
|
4234
|
+
];
|
|
4235
|
+
var constructTool = createDoctype({
|
|
4236
|
+
aip: 14,
|
|
4237
|
+
name: "tool",
|
|
4238
|
+
validate(def) {
|
|
4239
|
+
if ("execute" in def) {
|
|
4240
|
+
throw new Error(
|
|
4241
|
+
`defineTool: id='${def.id}' carries an 'execute' property. Bodies live on AIP-30 PROVIDER manifests, not on the TOOL contract. See https://agentproto.sh/docs/aip-30 for migration.`
|
|
4242
|
+
);
|
|
4243
|
+
}
|
|
4244
|
+
},
|
|
4245
|
+
build(def) {
|
|
4246
|
+
return {
|
|
4247
|
+
id: def.id,
|
|
4248
|
+
name: def.name ?? def.id,
|
|
4249
|
+
description: def.description,
|
|
4250
|
+
version: def.version,
|
|
4251
|
+
inputSchema: def.inputSchema,
|
|
4252
|
+
outputSchema: def.outputSchema,
|
|
4253
|
+
contextSchema: def.contextSchema,
|
|
4254
|
+
mutates: Object.freeze([...def.mutates ?? []]),
|
|
4255
|
+
requires: freezeCapabilities(def.requires),
|
|
4256
|
+
approval: defaultApproval(def.approval, def.mutates),
|
|
4257
|
+
riskLevel: def.riskLevel ?? 0,
|
|
4258
|
+
costClass: def.costClass ?? "trivial",
|
|
4259
|
+
timeoutMs: def.timeoutMs ?? 3e4,
|
|
4260
|
+
retry: def.retry,
|
|
4261
|
+
tags: Object.freeze([...def.tags ?? []]),
|
|
4262
|
+
metadata: Object.freeze({ ...def.metadata ?? {} }),
|
|
4263
|
+
idempotent: def.idempotent ?? false,
|
|
4264
|
+
defaultImplementation: def.defaultImplementation,
|
|
4265
|
+
driverConstraints: freezeProviderConstraints(def.driverConstraints)
|
|
4266
|
+
};
|
|
4267
|
+
}
|
|
4268
|
+
});
|
|
4269
|
+
function defineTool(definition) {
|
|
4270
|
+
return constructTool(
|
|
4271
|
+
definition
|
|
4272
|
+
);
|
|
4273
|
+
}
|
|
4274
|
+
function defaultApproval(declared, mutates) {
|
|
4275
|
+
if (declared) return declared;
|
|
4276
|
+
return mutates && mutates.length > 0 ? "on-mutate" : "auto";
|
|
4277
|
+
}
|
|
4278
|
+
function freezeCapabilities(caps) {
|
|
4279
|
+
return Object.freeze({
|
|
4280
|
+
network: Object.freeze([...caps?.network ?? []]),
|
|
4281
|
+
secrets: Object.freeze([...caps?.secrets ?? []]),
|
|
4282
|
+
tools: Object.freeze([...caps?.tools ?? []])
|
|
4283
|
+
});
|
|
4284
|
+
}
|
|
4285
|
+
function freezeProviderConstraints(c) {
|
|
4286
|
+
const forbid = (c?.forbid ?? []).filter(
|
|
4287
|
+
(k) => PROVIDER_KINDS.includes(k)
|
|
4288
|
+
);
|
|
4289
|
+
const requireKind = (c?.requireKind ?? []).filter(
|
|
4290
|
+
(k) => PROVIDER_KINDS.includes(k)
|
|
4291
|
+
);
|
|
4292
|
+
return Object.freeze({
|
|
4293
|
+
forbid: Object.freeze(forbid),
|
|
4294
|
+
requireKind: Object.freeze(requireKind)
|
|
4295
|
+
});
|
|
4296
|
+
}
|
|
4297
|
+
var toolManifestFrontmatterSchema = z.object({
|
|
4298
|
+
schema: z.literal("agentproto/tool/v1").optional(),
|
|
4299
|
+
name: z.string().min(1).max(80),
|
|
4300
|
+
id: z.string().regex(/^[a-z][a-z0-9._-]{1,63}$/),
|
|
4301
|
+
description: z.string().min(1).max(2e3),
|
|
4302
|
+
version: z.string().regex(/^\d+\.\d+\.\d+/),
|
|
4303
|
+
// Optional metadata
|
|
4304
|
+
mutates: z.array(z.string()).optional(),
|
|
4305
|
+
requires: z.object({
|
|
4306
|
+
network: z.array(z.string()).optional(),
|
|
4307
|
+
secrets: z.array(z.string()).optional(),
|
|
4308
|
+
tools: z.array(z.string()).optional()
|
|
4309
|
+
}).optional(),
|
|
4310
|
+
// `ApprovalClass` is `"auto" | "always" | "on-mutate" | \`policy:${string}\``.
|
|
4311
|
+
// z.union widens the regex branch to plain `string` (zod can't express
|
|
4312
|
+
// template literal types), so we use `z.custom` to keep the inferred
|
|
4313
|
+
// type exact — matters because `defineTool` accepts `ApprovalClass`.
|
|
4314
|
+
approval: z.custom(
|
|
4315
|
+
(v) => typeof v === "string" && (v === "auto" || v === "always" || v === "on-mutate" || /^policy:/.test(v)),
|
|
4316
|
+
{ message: "expected 'auto' | 'always' | 'on-mutate' | 'policy:<name>'" }
|
|
4317
|
+
).optional(),
|
|
4318
|
+
risk_level: z.union([z.literal(0), z.literal(1), z.literal(2), z.literal(3)]).optional(),
|
|
4319
|
+
cost_class: z.enum(["trivial", "metered", "expensive"]).optional(),
|
|
4320
|
+
timeout_ms: z.number().int().positive().optional(),
|
|
4321
|
+
idempotent: z.boolean().optional(),
|
|
4322
|
+
tags: z.array(z.string()).optional(),
|
|
4323
|
+
metadata: z.record(z.string(), z.unknown()).optional(),
|
|
4324
|
+
// AIP-26 / AIP-17 / AIP-19 references — kept loose; validated by their
|
|
4325
|
+
// respective AIPs' adapters when consumed.
|
|
4326
|
+
code: z.unknown().optional(),
|
|
4327
|
+
run: z.unknown().optional(),
|
|
4328
|
+
runner: z.unknown().optional(),
|
|
4329
|
+
secrets: z.unknown().optional(),
|
|
4330
|
+
network: z.unknown().optional()
|
|
4331
|
+
});
|
|
4332
|
+
function parseToolManifest(source) {
|
|
4333
|
+
const parsed = matter3(source);
|
|
4334
|
+
if (Object.keys(parsed.data).length === 0) {
|
|
4335
|
+
throw new Error("parseToolManifest: missing or empty frontmatter");
|
|
4336
|
+
}
|
|
4337
|
+
const result = toolManifestFrontmatterSchema.safeParse(parsed.data);
|
|
4338
|
+
if (!result.success) {
|
|
4339
|
+
throw new Error(
|
|
4340
|
+
`parseToolManifest: invalid frontmatter \u2014 ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
4341
|
+
);
|
|
4342
|
+
}
|
|
4343
|
+
return { frontmatter: result.data, body: parsed.content };
|
|
4344
|
+
}
|
|
4345
|
+
var toolSpec = {
|
|
4346
|
+
name: "tool",
|
|
4347
|
+
aip: 14,
|
|
4348
|
+
schemaLiteral: "agentproto/tool/v1",
|
|
4349
|
+
pathOf: (h) => `${h.id}/TOOL.md`,
|
|
4350
|
+
define: (params) => defineTool(params),
|
|
4351
|
+
parse: (source) => {
|
|
4352
|
+
const m = parseToolManifest(source);
|
|
4353
|
+
return {
|
|
4354
|
+
frontmatter: m.frontmatter,
|
|
4355
|
+
body: m.body
|
|
4356
|
+
};
|
|
4357
|
+
}
|
|
4358
|
+
};
|
|
4359
|
+
var toolVerbs = createVerbs(toolSpec);
|
|
4360
|
+
var routineFrontmatterSchema = z.object({ "schema": z.literal("routine/v1"), "id": z.string().regex(new RegExp("^[a-z0-9@][a-z0-9.@/_-]*$")).min(2).max(80).describe("Machine identifier. Lowercase, digits, dashes, dots, optional @owner/ prefix. Unique within the registry that hosts the routine."), "description": z.string().min(1).max(2e3).describe("One-paragraph purpose."), "version": z.string().regex(new RegExp("^\\d+\\.\\d+\\.\\d+(?:[-+][\\w.\\-]+)?$")).describe("Spec version of THIS file.").default("1.0.0"), "schedule": z.any().describe("When the routine fires."), "target": z.any().describe("What the routine invokes when it fires."), "identity": z.any().describe("Identity that owns the routine fire (AIP-23). Defaults to host policy.").optional(), "retry": z.any().describe("Retry behaviour on failure.").optional(), "on_failure": z.any().describe("Where to route failures after retries exhaust.").optional(), "history": z.any().describe("Run history retention.").optional(), "fires_events": z.array(z.string().min(1)).describe("AIP-37 LIFECYCLE event names this routine fires.").default(["routine-triggered", "routine-completed", "routine-failed"]), "enabled": z.boolean().describe("If false, routine registers but does not fire. Useful for staging.").default(true), "tags": z.array(z.string()).describe("Free-form discovery tags.").default([]), "metadata": z.record(z.string(), z.any()).describe("Free-form, namespaced.").optional() }).strict().describe("Validates the YAML frontmatter portion of an AIP-41 ROUTINE.md manifest. Decouples 'when' (schedule) from 'what' (target action/workflow/tool).");
|
|
4361
|
+
var defineRoutine = createDoctype({
|
|
4362
|
+
aip: 41,
|
|
4363
|
+
name: "routine",
|
|
4364
|
+
validate(def) {
|
|
4365
|
+
const result = routineFrontmatterSchema.safeParse(def);
|
|
4366
|
+
if (!result.success) {
|
|
4367
|
+
throw new Error(
|
|
4368
|
+
`defineRoutine (AIP-41): ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
4369
|
+
);
|
|
4370
|
+
}
|
|
4371
|
+
},
|
|
4372
|
+
build(def) {
|
|
4373
|
+
return { ...def };
|
|
4374
|
+
}
|
|
4375
|
+
});
|
|
4376
|
+
function parseRoutineManifest(source) {
|
|
4377
|
+
const parsed = matter3(source);
|
|
4378
|
+
if (Object.keys(parsed.data).length === 0) {
|
|
4379
|
+
throw new Error("parseRoutineManifest: missing or empty frontmatter");
|
|
4380
|
+
}
|
|
4381
|
+
const result = routineFrontmatterSchema.safeParse(parsed.data);
|
|
4382
|
+
if (!result.success) {
|
|
4383
|
+
throw new Error(
|
|
4384
|
+
`parseRoutineManifest: invalid frontmatter \u2014 ${result.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`
|
|
4385
|
+
);
|
|
4386
|
+
}
|
|
4387
|
+
return { frontmatter: result.data, body: parsed.content };
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4390
|
+
// ../routine/dist/index.mjs
|
|
4391
|
+
var routineSpec = {
|
|
4392
|
+
name: "routine",
|
|
4393
|
+
aip: 41,
|
|
4394
|
+
schemaLiteral: "routine/v1",
|
|
4395
|
+
pathOf: (h) => `.routines/${h.id}/ROUTINE.md`,
|
|
4396
|
+
define: defineRoutine,
|
|
4397
|
+
parse: (source) => {
|
|
4398
|
+
const m = parseRoutineManifest(source);
|
|
4399
|
+
return {
|
|
4400
|
+
frontmatter: m.frontmatter,
|
|
4401
|
+
body: m.body
|
|
4402
|
+
};
|
|
4403
|
+
}
|
|
4404
|
+
};
|
|
4405
|
+
var routineVerbs = createVerbs(routineSpec);
|
|
4406
|
+
async function summarizeToolRef(raw, workspace) {
|
|
4407
|
+
if (typeof raw === "string") {
|
|
4408
|
+
return { id: raw, description: "(string ref \u2014 not locally resolved)" };
|
|
4409
|
+
}
|
|
4410
|
+
if (typeof raw !== "object" || raw === null) {
|
|
4411
|
+
return { id: String(raw), description: "(unknown ref shape)" };
|
|
4412
|
+
}
|
|
4413
|
+
const block = raw;
|
|
4414
|
+
if (block.file) {
|
|
4415
|
+
try {
|
|
4416
|
+
const handle = await toolVerbs.resolve(
|
|
4417
|
+
{ file: block.file },
|
|
4418
|
+
{ baseDir: workspace }
|
|
4419
|
+
);
|
|
4420
|
+
return { id: handle.id, description: handle.description ?? "" };
|
|
4421
|
+
} catch {
|
|
4422
|
+
return { id: block.file, description: "(file ref \u2014 could not load)" };
|
|
4423
|
+
}
|
|
4424
|
+
}
|
|
4425
|
+
if (block.inline) {
|
|
4426
|
+
return {
|
|
4427
|
+
id: String(block.inline.id ?? ""),
|
|
4428
|
+
description: String(block.inline.description ?? "")
|
|
4429
|
+
};
|
|
4430
|
+
}
|
|
4431
|
+
if (block.ref) {
|
|
4432
|
+
return { id: block.ref, description: "(ref \u2014 not locally resolved)" };
|
|
4433
|
+
}
|
|
4434
|
+
return { id: JSON.stringify(raw), description: "(unknown ref shape)" };
|
|
4435
|
+
}
|
|
4436
|
+
async function summarizeRoutineRef(raw, workspace) {
|
|
4437
|
+
if (typeof raw === "string") {
|
|
4438
|
+
return { id: raw, description: "(string ref \u2014 not locally resolved)" };
|
|
4439
|
+
}
|
|
4440
|
+
if (typeof raw !== "object" || raw === null) {
|
|
4441
|
+
return { id: String(raw), description: "(unknown ref shape)" };
|
|
4442
|
+
}
|
|
4443
|
+
const block = raw;
|
|
4444
|
+
if (block.file) {
|
|
4445
|
+
try {
|
|
4446
|
+
const handle = await routineVerbs.resolve(
|
|
4447
|
+
{ file: block.file },
|
|
4448
|
+
{ baseDir: workspace }
|
|
4449
|
+
);
|
|
4450
|
+
return { id: handle.id, description: handle.description ?? "" };
|
|
4451
|
+
} catch {
|
|
4452
|
+
return { id: block.file, description: "(file ref \u2014 could not load)" };
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
if (block.inline) {
|
|
4456
|
+
return {
|
|
4457
|
+
id: String(block.inline.id ?? ""),
|
|
4458
|
+
description: String(block.inline.description ?? "")
|
|
4459
|
+
};
|
|
4460
|
+
}
|
|
4461
|
+
if (block.ref) {
|
|
4462
|
+
return { id: block.ref, description: "(ref \u2014 not locally resolved)" };
|
|
4463
|
+
}
|
|
4464
|
+
return { id: JSON.stringify(raw), description: "(unknown ref shape)" };
|
|
4465
|
+
}
|
|
4466
|
+
async function selfInspect(agentId, workspace) {
|
|
4467
|
+
const agentPath = join(workspace, ".agents", agentId, "AGENT.md");
|
|
4468
|
+
let handle;
|
|
4469
|
+
try {
|
|
4470
|
+
const result = await agentVerbs.load(agentPath);
|
|
4471
|
+
handle = result.handle;
|
|
4472
|
+
} catch (err) {
|
|
4473
|
+
const e = new Error(
|
|
4474
|
+
`No AGENT.md found for agent '${agentId}' at '${agentPath}'. Ensure an AGENT.md exists at <workspace>/.agents/${agentId}/AGENT.md.`
|
|
4475
|
+
);
|
|
4476
|
+
e.code = "agent_not_found";
|
|
4477
|
+
throw e;
|
|
4478
|
+
}
|
|
4479
|
+
const rawTools = handle.tools ?? [];
|
|
4480
|
+
const rawRoutines = handle.routines ?? [];
|
|
4481
|
+
const [tools, routines] = await Promise.all([
|
|
4482
|
+
Promise.all(rawTools.map((r) => summarizeToolRef(r, workspace))),
|
|
4483
|
+
Promise.all(rawRoutines.map((r) => summarizeRoutineRef(r, workspace)))
|
|
4484
|
+
]);
|
|
4485
|
+
return { agentPath, tools, routines };
|
|
4486
|
+
}
|
|
4487
|
+
function registerSelfInspectTool(server, opts) {
|
|
4488
|
+
server.tool(
|
|
4489
|
+
"self_inspect",
|
|
4490
|
+
"Return this agent's AIP-42 manifest summary (tools + routines) without requiring knowledge of disk paths. Pass the agent's logical `id` (the `id:` field in its AGENT.md frontmatter); the runtime resolves it to `<workspace>/.agents/<agentId>/AGENT.md`. Returns `{ agentPath, tools, routines }` \u2014 each item has at minimum `{ id, description }`. File refs are loaded; string/ref refs are surfaced as-is.",
|
|
4491
|
+
{
|
|
4492
|
+
agentId: z.string().min(1).describe(
|
|
4493
|
+
"The agent's logical id (e.g. 'writer'). Matches the `id:` field in the AGENT.md frontmatter. The runtime resolves this to `<workspace>/.agents/<agentId>/AGENT.md` \u2014 you do not need to know the absolute disk path."
|
|
4494
|
+
)
|
|
4495
|
+
},
|
|
4496
|
+
async ({ agentId }) => {
|
|
4497
|
+
try {
|
|
4498
|
+
const result = await selfInspect(agentId, opts.workspace);
|
|
4499
|
+
return {
|
|
4500
|
+
content: [
|
|
4501
|
+
{
|
|
4502
|
+
type: "text",
|
|
4503
|
+
text: JSON.stringify(result, null, 2)
|
|
4504
|
+
}
|
|
4505
|
+
]
|
|
4506
|
+
};
|
|
4507
|
+
} catch (err) {
|
|
4508
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
4509
|
+
return {
|
|
4510
|
+
content: [
|
|
4511
|
+
{
|
|
4512
|
+
type: "text",
|
|
4513
|
+
text: JSON.stringify({ error: "agent_not_found", message }, null, 2)
|
|
4514
|
+
}
|
|
4515
|
+
],
|
|
4516
|
+
isError: true
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
}
|
|
4520
|
+
);
|
|
4521
|
+
}
|
|
4004
4522
|
async function createMcpServer(opts) {
|
|
4005
4523
|
const server = new McpServer({
|
|
4006
4524
|
name: opts.name ?? "agentproto-mcp-server",
|
|
@@ -4015,6 +4533,9 @@ async function createMcpServer(opts) {
|
|
|
4015
4533
|
for (const spec of allSpecs) {
|
|
4016
4534
|
registerVerbs(server, spec, anchor);
|
|
4017
4535
|
}
|
|
4536
|
+
if (opts.workspace) {
|
|
4537
|
+
registerSelfInspectTool(server, { workspace: opts.workspace });
|
|
4538
|
+
}
|
|
4018
4539
|
return {
|
|
4019
4540
|
server,
|
|
4020
4541
|
registered: allSpecs.map((s) => s.name)
|
|
@@ -4042,7 +4563,7 @@ function registerVerbs(server, spec, anchor) {
|
|
|
4042
4563
|
body,
|
|
4043
4564
|
dryRun
|
|
4044
4565
|
});
|
|
4045
|
-
return
|
|
4566
|
+
return contentText2({
|
|
4046
4567
|
path: result.path,
|
|
4047
4568
|
rendered: result.rendered
|
|
4048
4569
|
});
|
|
@@ -4056,7 +4577,7 @@ function registerVerbs(server, spec, anchor) {
|
|
|
4056
4577
|
},
|
|
4057
4578
|
async ({ path }) => {
|
|
4058
4579
|
const result = await verbs.load(anchor(path));
|
|
4059
|
-
return
|
|
4580
|
+
return contentText2({ path: result.path, handle: result.handle });
|
|
4060
4581
|
}
|
|
4061
4582
|
);
|
|
4062
4583
|
server.tool(
|
|
@@ -4071,7 +4592,7 @@ function registerVerbs(server, spec, anchor) {
|
|
|
4071
4592
|
},
|
|
4072
4593
|
async ({ dir, skipDirs }) => {
|
|
4073
4594
|
const handles = await verbs.list(anchor(dir), { skipDirs });
|
|
4074
|
-
return
|
|
4595
|
+
return contentText2({ count: handles.length, handles });
|
|
4075
4596
|
}
|
|
4076
4597
|
);
|
|
4077
4598
|
server.tool(
|
|
@@ -4091,7 +4612,7 @@ function registerVerbs(server, spec, anchor) {
|
|
|
4091
4612
|
(existing) => ({ ...existing, ...patch }),
|
|
4092
4613
|
{ body }
|
|
4093
4614
|
);
|
|
4094
|
-
return
|
|
4615
|
+
return contentText2({ path: result.path, rendered: result.rendered });
|
|
4095
4616
|
}
|
|
4096
4617
|
);
|
|
4097
4618
|
server.tool(
|
|
@@ -4105,14 +4626,16 @@ function registerVerbs(server, spec, anchor) {
|
|
|
4105
4626
|
z.object({ inline: z.record(z.string(), z.unknown()) }),
|
|
4106
4627
|
z.object({ ref: z.string() }),
|
|
4107
4628
|
z.object({ file: z.string() })
|
|
4108
|
-
]).describe(
|
|
4629
|
+
]).describe(
|
|
4630
|
+
'The composition block. Exactly one of: { "inline": {...params} } | { "ref": "@scope/id" } | { "file": "relative/path.md" }. Omitting the wrapping key causes invalid_union.'
|
|
4631
|
+
),
|
|
4109
4632
|
baseDir: z.string().optional().describe("Base dir for `file:` references.")
|
|
4110
4633
|
},
|
|
4111
4634
|
async ({ block, baseDir }) => {
|
|
4112
4635
|
const handle = await verbs.resolve(block, {
|
|
4113
4636
|
baseDir: baseDir ? anchor(baseDir) : void 0
|
|
4114
4637
|
});
|
|
4115
|
-
return
|
|
4638
|
+
return contentText2({ handle });
|
|
4116
4639
|
}
|
|
4117
4640
|
);
|
|
4118
4641
|
server.tool(
|
|
@@ -4124,7 +4647,7 @@ function registerVerbs(server, spec, anchor) {
|
|
|
4124
4647
|
async ({ path }) => {
|
|
4125
4648
|
const target = anchor(path);
|
|
4126
4649
|
await verbs.delete(target);
|
|
4127
|
-
return
|
|
4650
|
+
return contentText2({ deleted: target });
|
|
4128
4651
|
}
|
|
4129
4652
|
);
|
|
4130
4653
|
}
|
|
@@ -4168,7 +4691,7 @@ async function loadExtensions(workspace, specs) {
|
|
|
4168
4691
|
}
|
|
4169
4692
|
return out;
|
|
4170
4693
|
}
|
|
4171
|
-
function
|
|
4694
|
+
function contentText2(payload) {
|
|
4172
4695
|
return {
|
|
4173
4696
|
content: [
|
|
4174
4697
|
{
|
|
@@ -4270,7 +4793,7 @@ function makeCwdAnchor(workspace) {
|
|
|
4270
4793
|
const root = resolve(workspace);
|
|
4271
4794
|
return (input2) => {
|
|
4272
4795
|
if (!input2 || input2.length === 0) return root;
|
|
4273
|
-
const candidate = isAbsolute(input2) ? normalize(input2) : normalize(join(root, input2));
|
|
4796
|
+
const candidate = isAbsolute(input2) ? normalize$1(input2) : normalize$1(join(root, input2));
|
|
4274
4797
|
const rel = relative(root, candidate);
|
|
4275
4798
|
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
4276
4799
|
throw new Error(
|
|
@@ -4565,7 +5088,7 @@ function makeAnchor(workspace) {
|
|
|
4565
5088
|
if (typeof input2 !== "string" || input2.length === 0) {
|
|
4566
5089
|
throw new FsPathError("path must be a non-empty string");
|
|
4567
5090
|
}
|
|
4568
|
-
const candidate = isAbsolute(input2) ? normalize(input2) : normalize(join(root, input2));
|
|
5091
|
+
const candidate = isAbsolute(input2) ? normalize$1(input2) : normalize$1(join(root, input2));
|
|
4569
5092
|
const rel = relative(root, candidate);
|
|
4570
5093
|
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
4571
5094
|
throw new FsPathError(`path escapes the workspace: '${input2}'`);
|
|
@@ -4946,18 +5469,18 @@ function stringifyValues(raw) {
|
|
|
4946
5469
|
}
|
|
4947
5470
|
return out;
|
|
4948
5471
|
}
|
|
4949
|
-
var
|
|
4950
|
-
var
|
|
4951
|
-
var
|
|
4952
|
-
version:
|
|
5472
|
+
var IMPORTED_MCPS_PATH2 = () => resolve(homedir(), ".agentproto", "imported-mcps.json");
|
|
5473
|
+
var IMPORTED_MCPS_VERSION2 = 1;
|
|
5474
|
+
var EMPTY2 = {
|
|
5475
|
+
version: IMPORTED_MCPS_VERSION2,
|
|
4953
5476
|
imports: []
|
|
4954
5477
|
};
|
|
4955
|
-
async function
|
|
5478
|
+
async function loadImportedMcps2(path = IMPORTED_MCPS_PATH2()) {
|
|
4956
5479
|
let raw;
|
|
4957
5480
|
try {
|
|
4958
5481
|
raw = await promises.readFile(path, "utf8");
|
|
4959
5482
|
} catch (err) {
|
|
4960
|
-
if (err.code === "ENOENT") return
|
|
5483
|
+
if (err.code === "ENOENT") return EMPTY2;
|
|
4961
5484
|
throw err;
|
|
4962
5485
|
}
|
|
4963
5486
|
let parsed;
|
|
@@ -4970,7 +5493,7 @@ async function loadImportedMcps(path = IMPORTED_MCPS_PATH()) {
|
|
|
4970
5493
|
}
|
|
4971
5494
|
return normalize3(parsed);
|
|
4972
5495
|
}
|
|
4973
|
-
async function saveImportedMcps(config, path =
|
|
5496
|
+
async function saveImportedMcps(config, path = IMPORTED_MCPS_PATH2()) {
|
|
4974
5497
|
await promises.mkdir(dirname(path), { recursive: true });
|
|
4975
5498
|
const tmp = `${path}.tmp.${process.pid}`;
|
|
4976
5499
|
await promises.writeFile(tmp, JSON.stringify(config, null, 2) + "\n", "utf8");
|
|
@@ -4995,7 +5518,7 @@ function removeImport(config, id) {
|
|
|
4995
5518
|
return { ...config, imports: config.imports.filter((e) => e.id !== id) };
|
|
4996
5519
|
}
|
|
4997
5520
|
function normalize3(parsed) {
|
|
4998
|
-
if (!parsed || typeof parsed !== "object") return
|
|
5521
|
+
if (!parsed || typeof parsed !== "object") return EMPTY2;
|
|
4999
5522
|
const obj = parsed;
|
|
5000
5523
|
const imports = [];
|
|
5001
5524
|
if (Array.isArray(obj.imports)) {
|
|
@@ -5010,7 +5533,7 @@ function normalize3(parsed) {
|
|
|
5010
5533
|
imports.push({ id, alias, addedAt, snapshot });
|
|
5011
5534
|
}
|
|
5012
5535
|
}
|
|
5013
|
-
return { version:
|
|
5536
|
+
return { version: IMPORTED_MCPS_VERSION2, imports };
|
|
5014
5537
|
}
|
|
5015
5538
|
function registerSessionTools(server, opts) {
|
|
5016
5539
|
const { registry, resolveAgentAdapter, listAgentAdapters, mcpProxy } = opts;
|
|
@@ -5300,7 +5823,7 @@ function registerSessionTools(server, opts) {
|
|
|
5300
5823
|
{},
|
|
5301
5824
|
async () => {
|
|
5302
5825
|
try {
|
|
5303
|
-
const config = await
|
|
5826
|
+
const config = await loadImportedMcps2();
|
|
5304
5827
|
return {
|
|
5305
5828
|
content: [
|
|
5306
5829
|
{ type: "text", text: JSON.stringify(config, null, 2) }
|
|
@@ -5345,7 +5868,7 @@ function registerSessionTools(server, opts) {
|
|
|
5345
5868
|
isError: true
|
|
5346
5869
|
};
|
|
5347
5870
|
}
|
|
5348
|
-
const cfg = await
|
|
5871
|
+
const cfg = await loadImportedMcps2();
|
|
5349
5872
|
const next = addImport(cfg, {
|
|
5350
5873
|
snapshot,
|
|
5351
5874
|
...input2.alias ? { alias: input2.alias } : {}
|
|
@@ -5378,7 +5901,7 @@ function registerSessionTools(server, opts) {
|
|
|
5378
5901
|
},
|
|
5379
5902
|
async (input2) => {
|
|
5380
5903
|
try {
|
|
5381
|
-
const cfg = await
|
|
5904
|
+
const cfg = await loadImportedMcps2();
|
|
5382
5905
|
if (!cfg.imports.some((e) => e.id === input2.id)) {
|
|
5383
5906
|
return {
|
|
5384
5907
|
content: [
|
|
@@ -6260,7 +6783,7 @@ async function startHttpServer(opts) {
|
|
|
6260
6783
|
return;
|
|
6261
6784
|
}
|
|
6262
6785
|
if (path === "/mcps/imports" && req.method === "GET") {
|
|
6263
|
-
const config = await
|
|
6786
|
+
const config = await loadImportedMcps2();
|
|
6264
6787
|
res.writeHead(200, { "content-type": "application/json" });
|
|
6265
6788
|
res.end(JSON.stringify(config));
|
|
6266
6789
|
return;
|
|
@@ -6284,7 +6807,7 @@ async function startHttpServer(opts) {
|
|
|
6284
6807
|
);
|
|
6285
6808
|
return;
|
|
6286
6809
|
}
|
|
6287
|
-
const cfg = await
|
|
6810
|
+
const cfg = await loadImportedMcps2();
|
|
6288
6811
|
const next = addImport(cfg, {
|
|
6289
6812
|
snapshot,
|
|
6290
6813
|
...body.alias ? { alias: body.alias } : {}
|
|
@@ -6297,7 +6820,7 @@ async function startHttpServer(opts) {
|
|
|
6297
6820
|
const importMatch = path.match(/^\/mcps\/imports\/(.+)$/);
|
|
6298
6821
|
if (importMatch && req.method === "DELETE") {
|
|
6299
6822
|
const id = decodeURIComponent(importMatch[1] ?? "");
|
|
6300
|
-
const cfg = await
|
|
6823
|
+
const cfg = await loadImportedMcps2();
|
|
6301
6824
|
if (!cfg.imports.some((e) => e.id === id)) {
|
|
6302
6825
|
res.writeHead(404, { "content-type": "application/json" });
|
|
6303
6826
|
res.end(JSON.stringify({ error: "import_not_found", id }));
|
|
@@ -7715,13 +8238,13 @@ var McpProxyRegistry = class {
|
|
|
7715
8238
|
async ensureCurrent() {
|
|
7716
8239
|
let mtimeMs = 0;
|
|
7717
8240
|
try {
|
|
7718
|
-
const st = await promises.stat(
|
|
8241
|
+
const st = await promises.stat(IMPORTED_MCPS_PATH2());
|
|
7719
8242
|
mtimeMs = st.mtimeMs;
|
|
7720
8243
|
} catch {
|
|
7721
8244
|
mtimeMs = 0;
|
|
7722
8245
|
}
|
|
7723
8246
|
if (this.hasReadOnce && mtimeMs === this.lastMtimeMs) return;
|
|
7724
|
-
const config = await
|
|
8247
|
+
const config = await loadImportedMcps2().catch(() => ({
|
|
7725
8248
|
version: 1,
|
|
7726
8249
|
imports: []
|
|
7727
8250
|
}));
|
|
@@ -8290,7 +8813,7 @@ function createWorkspaceFs(opts) {
|
|
|
8290
8813
|
"absolute paths are not allowed; use a workspace-relative path"
|
|
8291
8814
|
);
|
|
8292
8815
|
}
|
|
8293
|
-
const joined = normalize(join(root, path));
|
|
8816
|
+
const joined = normalize$1(join(root, path));
|
|
8294
8817
|
const rel = relative(root, joined);
|
|
8295
8818
|
if (rel.startsWith("..") || isAbsolute(rel)) {
|
|
8296
8819
|
throw new WorkspacePathError(
|
|
@@ -8494,6 +9017,51 @@ async function runBoot(workspace, opts, conversations, events) {
|
|
|
8494
9017
|
durationMs: 0
|
|
8495
9018
|
});
|
|
8496
9019
|
}
|
|
9020
|
+
|
|
9021
|
+
// src/registry/catalog.ts
|
|
9022
|
+
var CATALOG = [
|
|
9023
|
+
// ── Agent CLIs ────────────────────────────────────────────────────────
|
|
9024
|
+
{
|
|
9025
|
+
type: "agent-cli",
|
|
9026
|
+
slug: "claude-code",
|
|
9027
|
+
name: "Claude Code",
|
|
9028
|
+
description: "Anthropic's Claude Code via @agentclientprotocol/claude-agent-acp ACP wrapper.",
|
|
9029
|
+
packageName: "@agentproto/adapter-claude-code",
|
|
9030
|
+
hint: "anthropic \xB7 ACP \xB7 resumable"
|
|
9031
|
+
},
|
|
9032
|
+
{
|
|
9033
|
+
type: "agent-cli",
|
|
9034
|
+
slug: "opencode",
|
|
9035
|
+
name: "OpenCode",
|
|
9036
|
+
description: "sst/opencode with first-party ACP mode. Multi-provider: Anthropic, OpenAI, OpenRouter, Groq.",
|
|
9037
|
+
packageName: "@agentproto/adapter-opencode",
|
|
9038
|
+
hint: "multi-provider \xB7 ACP \xB7 resumable"
|
|
9039
|
+
},
|
|
9040
|
+
{
|
|
9041
|
+
type: "agent-cli",
|
|
9042
|
+
slug: "codex",
|
|
9043
|
+
name: "Codex",
|
|
9044
|
+
description: "OpenAI Codex coding agent via Zed's @zed-industries/codex-acp ACP wrapper.",
|
|
9045
|
+
packageName: "@agentproto/adapter-codex",
|
|
9046
|
+
hint: "openai \xB7 ACP \xB7 resumable"
|
|
9047
|
+
},
|
|
9048
|
+
{
|
|
9049
|
+
type: "agent-cli",
|
|
9050
|
+
slug: "hermes",
|
|
9051
|
+
name: "Hermes",
|
|
9052
|
+
description: "Nous Research Hermes agent with skills, sandboxes, and memory plugin surface.",
|
|
9053
|
+
packageName: "@agentproto/adapter-hermes",
|
|
9054
|
+
hint: "nous \xB7 ACP \xB7 sub-agents"
|
|
9055
|
+
},
|
|
9056
|
+
{
|
|
9057
|
+
type: "agent-cli",
|
|
9058
|
+
slug: "openclaw",
|
|
9059
|
+
name: "OpenClaw",
|
|
9060
|
+
description: "OpenClaw coding-agent platform with native ACP bridge and plugin surface.",
|
|
9061
|
+
packageName: "@agentproto/adapter-openclaw",
|
|
9062
|
+
hint: "gateway \xB7 ACP \xB7 plugins"
|
|
9063
|
+
}
|
|
9064
|
+
];
|
|
8497
9065
|
async function runServe(args) {
|
|
8498
9066
|
const { values } = parseArgs({
|
|
8499
9067
|
args: [...args],
|
|
@@ -8600,10 +9168,11 @@ async function runServe(args) {
|
|
|
8600
9168
|
const adapter = await resolveAdapter(slug);
|
|
8601
9169
|
const runtime = createAgentCliRuntime(adapter.handle);
|
|
8602
9170
|
return {
|
|
8603
|
-
async startSession({ cwd, resumeSessionId }) {
|
|
9171
|
+
async startSession({ cwd, resumeSessionId, model }) {
|
|
8604
9172
|
return runtime.start({
|
|
8605
9173
|
cwd,
|
|
8606
|
-
...resumeSessionId ? { resumeSessionId } : {}
|
|
9174
|
+
...resumeSessionId ? { resumeSessionId } : {},
|
|
9175
|
+
...model ? { config: { options: { model } } } : {}
|
|
8607
9176
|
});
|
|
8608
9177
|
},
|
|
8609
9178
|
commandPreview: `${adapter.handle.bin} ${(adapter.handle.bin_args ?? []).join(" ")}`.trim()
|
|
@@ -8622,15 +9191,15 @@ async function runServe(args) {
|
|
|
8622
9191
|
workspace: opts.workspace,
|
|
8623
9192
|
port: opts.port,
|
|
8624
9193
|
bind: opts.bind,
|
|
8625
|
-
specs: [],
|
|
9194
|
+
specs: [driverSpec],
|
|
8626
9195
|
name: "agentproto-serve",
|
|
8627
9196
|
// BOOT.md is silly for a tunnel daemon — skip it.
|
|
8628
9197
|
boot: false,
|
|
8629
9198
|
resolveAgentAdapter,
|
|
8630
9199
|
// Discovery for UIs / operators — `GET /adapters` + `list_adapters`
|
|
8631
|
-
// MCP tool.
|
|
8632
|
-
//
|
|
8633
|
-
listAgentAdapters:
|
|
9200
|
+
// MCP tool. Starts from the bundled catalog so known adapters always
|
|
9201
|
+
// appear (with status "supported") even when not yet installed.
|
|
9202
|
+
listAgentAdapters: () => listAdaptersWithCatalog(CATALOG),
|
|
8634
9203
|
...spawnPty ? { spawnPty } : {},
|
|
8635
9204
|
...opts.allowedOrigins ? { allowedOrigins: opts.allowedOrigins } : {},
|
|
8636
9205
|
...opts.strictOrigins ? { strictOrigins: true } : {}
|
|
@@ -8642,6 +9211,10 @@ async function runServe(args) {
|
|
|
8642
9211
|
);
|
|
8643
9212
|
return 1;
|
|
8644
9213
|
}
|
|
9214
|
+
const installedAdapterSlugs = await listAdaptersWithCatalog(CATALOG).then((list) => list.filter((a) => a.status !== "supported").map((a) => a.slug)).catch(() => []);
|
|
9215
|
+
const announcedTools = [
|
|
9216
|
+
.../* @__PURE__ */ new Set([...gateway.registered, ...installedAdapterSlugs])
|
|
9217
|
+
];
|
|
8645
9218
|
printBootBanner({
|
|
8646
9219
|
url: gateway.url,
|
|
8647
9220
|
workspace: gateway.workspace,
|
|
@@ -8699,8 +9272,8 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
8699
9272
|
AGENTPROTO_DAEMON_TOKEN: gateway.token
|
|
8700
9273
|
}
|
|
8701
9274
|
});
|
|
8702
|
-
await new Promise((
|
|
8703
|
-
child.once("exit", () =>
|
|
9275
|
+
await new Promise((resolve10) => {
|
|
9276
|
+
child.once("exit", () => resolve10());
|
|
8704
9277
|
aborter.signal.addEventListener("abort", () => {
|
|
8705
9278
|
try {
|
|
8706
9279
|
child.kill("SIGTERM");
|
|
@@ -8720,8 +9293,8 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
8720
9293
|
`${color.dim}Press Ctrl-C to stop.${color.reset}
|
|
8721
9294
|
`
|
|
8722
9295
|
);
|
|
8723
|
-
await new Promise((
|
|
8724
|
-
aborter.signal.addEventListener("abort", () =>
|
|
9296
|
+
await new Promise((resolve10) => {
|
|
9297
|
+
aborter.signal.addEventListener("abort", () => resolve10());
|
|
8725
9298
|
});
|
|
8726
9299
|
return 0;
|
|
8727
9300
|
}
|
|
@@ -8734,7 +9307,14 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
8734
9307
|
const reconnectState = { immediate: false };
|
|
8735
9308
|
while (!aborter.signal.aborted) {
|
|
8736
9309
|
try {
|
|
8737
|
-
await runOneTunnel(
|
|
9310
|
+
await runOneTunnel(
|
|
9311
|
+
opts,
|
|
9312
|
+
gateway,
|
|
9313
|
+
announcedTools,
|
|
9314
|
+
spawnPty,
|
|
9315
|
+
aborter.signal,
|
|
9316
|
+
reconnectState
|
|
9317
|
+
);
|
|
8738
9318
|
backoffMs = opts.reconnectMinMs ?? 1e3;
|
|
8739
9319
|
if (reconnectState.immediate) {
|
|
8740
9320
|
reconnectState.immediate = false;
|
|
@@ -8755,17 +9335,17 @@ ${color.dim}\u2500\u2500 shutting down (${signal}) \u2500\u2500${color.reset}
|
|
|
8755
9335
|
}
|
|
8756
9336
|
return 0;
|
|
8757
9337
|
}
|
|
8758
|
-
async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
9338
|
+
async function runOneTunnel(opts, gateway, announcedTools, spawnPty, signal, reconnectState) {
|
|
8759
9339
|
if (!opts.connect) throw new Error("runOneTunnel: --connect not set");
|
|
8760
9340
|
const headers = {
|
|
8761
|
-
"user-agent": "
|
|
9341
|
+
"user-agent": `agentproto/${"0.1.2"}`
|
|
8762
9342
|
};
|
|
8763
9343
|
if (opts.token) headers.authorization = `Bearer ${opts.token}`;
|
|
8764
9344
|
const ws = new WebSocket2(opts.connect, { headers });
|
|
8765
|
-
await new Promise((
|
|
9345
|
+
await new Promise((resolve10, reject) => {
|
|
8766
9346
|
const onOpen = () => {
|
|
8767
9347
|
ws.off("error", onError);
|
|
8768
|
-
|
|
9348
|
+
resolve10();
|
|
8769
9349
|
};
|
|
8770
9350
|
const onError = (err) => {
|
|
8771
9351
|
ws.off("open", onOpen);
|
|
@@ -8796,18 +9376,34 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
8796
9376
|
label: opts.label,
|
|
8797
9377
|
pty: spawnPty !== null,
|
|
8798
9378
|
...spawnPty ? { spawnPty } : {},
|
|
9379
|
+
// Announce what this daemon serves (doctypes + installed agent adapters)
|
|
9380
|
+
// so a multi-daemon host can enumerate + route by capability.
|
|
9381
|
+
...announcedTools.length ? { tools: announcedTools } : {},
|
|
8799
9382
|
// Generic HTTP-relay upstream for tunnel `http_request` frames.
|
|
8800
9383
|
// Cloud-side callers (e.g. the API's local-daemon filesystem
|
|
8801
9384
|
// provider) can now route MCP JSON-RPC + any other HTTP through
|
|
8802
9385
|
// the daemon without needing a public URL. We point at the local
|
|
8803
9386
|
// gateway since that's where `/mcp`, `/sessions`, `/events` live.
|
|
8804
9387
|
httpUpstream: gateway.url,
|
|
9388
|
+
// Forward bounds, stated explicitly so they're visible and tunable here
|
|
9389
|
+
// (the local gateway is fast, so the package defaults fit; bump these if
|
|
9390
|
+
// this daemon ever fronts a slower upstream):
|
|
9391
|
+
// - connect + buffered-body / connect + stream-headers ceiling
|
|
9392
|
+
httpForwardTimeoutMs: DEFAULT_HTTP_FORWARD_TIMEOUT_MS,
|
|
9393
|
+
// - WS upgrade dial ceiling
|
|
9394
|
+
wsDialTimeoutMs: DEFAULT_WS_DIAL_TIMEOUT_MS,
|
|
9395
|
+
// Bound a streaming forward against a silent upstream: if an SSE/ndjson
|
|
9396
|
+
// stream sends headers then stalls with no bytes for 2 min, end it instead
|
|
9397
|
+
// of holding the reqId open forever. The window resets per chunk, so a
|
|
9398
|
+
// well-behaved stream (events or heartbeat comments) is never cut — only a
|
|
9399
|
+
// genuinely dead upstream trips it.
|
|
9400
|
+
httpStreamIdleTimeoutMs: 12e4,
|
|
8805
9401
|
// WS forwarding upstream — daemon dials the local gateway's WS
|
|
8806
9402
|
// endpoints (/sessions/:id/pty, etc) and pipes frames to the host.
|
|
8807
9403
|
// Used by the cloud tunnel pod so browsers on mobile can attach to
|
|
8808
9404
|
// interactive PTY sessions even though the daemon is only reachable
|
|
8809
9405
|
// through the host (not directly).
|
|
8810
|
-
dialUpstreamWs: async ({ url, protocols, headers: headers2 }) => {
|
|
9406
|
+
dialUpstreamWs: async ({ url, protocols, headers: headers2, signal: signal2 }) => {
|
|
8811
9407
|
const upstreamHeaders = {
|
|
8812
9408
|
...headers2
|
|
8813
9409
|
};
|
|
@@ -8819,14 +9415,28 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
8819
9415
|
} catch {
|
|
8820
9416
|
}
|
|
8821
9417
|
}
|
|
8822
|
-
return await new Promise((
|
|
9418
|
+
return await new Promise((resolve10, reject) => {
|
|
8823
9419
|
const sock = new WebSocket2(url, protocols ? [...protocols] : void 0, {
|
|
8824
9420
|
headers: upstreamHeaders
|
|
8825
9421
|
});
|
|
9422
|
+
const onAbort = () => {
|
|
9423
|
+
sock.off("open", onceOpen);
|
|
9424
|
+
sock.off("error", onceError);
|
|
9425
|
+
sock.off("unexpected-response", onceUnexpected);
|
|
9426
|
+
try {
|
|
9427
|
+
sock.terminate();
|
|
9428
|
+
} catch {
|
|
9429
|
+
}
|
|
9430
|
+
reject(
|
|
9431
|
+
signal2?.reason instanceof Error ? signal2.reason : new Error("ws dial aborted")
|
|
9432
|
+
);
|
|
9433
|
+
};
|
|
9434
|
+
const detachAbort = () => signal2?.removeEventListener("abort", onAbort);
|
|
8826
9435
|
const onceOpen = () => {
|
|
9436
|
+
detachAbort();
|
|
8827
9437
|
sock.off("error", onceError);
|
|
8828
9438
|
sock.off("unexpected-response", onceUnexpected);
|
|
8829
|
-
|
|
9439
|
+
resolve10({
|
|
8830
9440
|
protocol: sock.protocol ?? "",
|
|
8831
9441
|
send: (data, sendOpts) => {
|
|
8832
9442
|
sock.send(data, { binary: sendOpts.binary });
|
|
@@ -8853,18 +9463,43 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
8853
9463
|
});
|
|
8854
9464
|
};
|
|
8855
9465
|
const onceError = (err) => {
|
|
9466
|
+
detachAbort();
|
|
8856
9467
|
sock.off("open", onceOpen);
|
|
8857
9468
|
reject(err);
|
|
8858
9469
|
};
|
|
8859
9470
|
const onceUnexpected = (_req, res) => {
|
|
9471
|
+
detachAbort();
|
|
8860
9472
|
sock.off("open", onceOpen);
|
|
8861
9473
|
reject(new Error(`Unexpected server response: ${res.statusCode ?? 0}`));
|
|
8862
9474
|
};
|
|
9475
|
+
if (signal2) {
|
|
9476
|
+
if (signal2.aborted) {
|
|
9477
|
+
onAbort();
|
|
9478
|
+
return;
|
|
9479
|
+
}
|
|
9480
|
+
signal2.addEventListener("abort", onAbort, { once: true });
|
|
9481
|
+
}
|
|
8863
9482
|
sock.once("open", onceOpen);
|
|
8864
9483
|
sock.once("error", onceError);
|
|
8865
9484
|
sock.once("unexpected-response", onceUnexpected);
|
|
8866
9485
|
});
|
|
8867
9486
|
},
|
|
9487
|
+
// Resolve a named WS upstream to a registered import's origin. A host
|
|
9488
|
+
// can watch a tab on an imported capability server (e.g. a browser
|
|
9489
|
+
// daemon) by aliasing the import instead of the default gateway — the
|
|
9490
|
+
// path rides the import's own origin (`http://127.0.0.1:<port>`), the
|
|
9491
|
+
// daemon never accepts a raw origin from the host.
|
|
9492
|
+
resolveWsUpstream: async (alias) => {
|
|
9493
|
+
const cfg = await loadImportedMcps();
|
|
9494
|
+
const entry = cfg.imports.find((e) => e.alias === alias);
|
|
9495
|
+
const url = entry?.snapshot.url;
|
|
9496
|
+
if (!url) return void 0;
|
|
9497
|
+
try {
|
|
9498
|
+
return new URL(url).origin;
|
|
9499
|
+
} catch {
|
|
9500
|
+
return void 0;
|
|
9501
|
+
}
|
|
9502
|
+
},
|
|
8868
9503
|
// v0 authorize hook: trust the bearer-authenticated host completely.
|
|
8869
9504
|
// Token possession proves the host was provisioned for this daemon.
|
|
8870
9505
|
// Per-spawn policy filtering will land alongside the policy.toml.
|
|
@@ -8900,31 +9535,31 @@ async function runOneTunnel(opts, gateway, spawnPty, signal, reconnectState) {
|
|
|
8900
9535
|
}
|
|
8901
9536
|
}
|
|
8902
9537
|
});
|
|
8903
|
-
await new Promise((
|
|
9538
|
+
await new Promise((resolve10) => {
|
|
8904
9539
|
const offClose = sink.onClose(() => {
|
|
8905
9540
|
clearInterval(keepaliveInterval);
|
|
8906
9541
|
offClose();
|
|
8907
|
-
|
|
9542
|
+
resolve10();
|
|
8908
9543
|
});
|
|
8909
9544
|
if (signal.aborted) {
|
|
8910
9545
|
clearInterval(keepaliveInterval);
|
|
8911
|
-
server.close().finally(() =>
|
|
9546
|
+
server.close().finally(() => resolve10());
|
|
8912
9547
|
}
|
|
8913
9548
|
signal.addEventListener("abort", () => {
|
|
8914
9549
|
clearInterval(keepaliveInterval);
|
|
8915
|
-
server.close().finally(() =>
|
|
9550
|
+
server.close().finally(() => resolve10());
|
|
8916
9551
|
});
|
|
8917
9552
|
});
|
|
8918
9553
|
process.stderr.write(`agentproto serve: tunnel closed.
|
|
8919
9554
|
`);
|
|
8920
9555
|
}
|
|
8921
9556
|
function sleep3(ms, signal) {
|
|
8922
|
-
return new Promise((
|
|
8923
|
-
if (signal.aborted) return
|
|
8924
|
-
const timer = setTimeout(
|
|
9557
|
+
return new Promise((resolve10) => {
|
|
9558
|
+
if (signal.aborted) return resolve10();
|
|
9559
|
+
const timer = setTimeout(resolve10, ms);
|
|
8925
9560
|
signal.addEventListener("abort", () => {
|
|
8926
9561
|
clearTimeout(timer);
|
|
8927
|
-
|
|
9562
|
+
resolve10();
|
|
8928
9563
|
});
|
|
8929
9564
|
});
|
|
8930
9565
|
}
|
|
@@ -10384,7 +11019,7 @@ function stripAnsi(s) {
|
|
|
10384
11019
|
return s.replace(/\x1b\[[0-9;]*m/g, "");
|
|
10385
11020
|
}
|
|
10386
11021
|
function httpDelete(url, token) {
|
|
10387
|
-
return new Promise((
|
|
11022
|
+
return new Promise((resolve10, reject) => {
|
|
10388
11023
|
const u = new URL(url);
|
|
10389
11024
|
const lib = u.protocol === "https:" ? https : http;
|
|
10390
11025
|
const headers = {};
|
|
@@ -10400,7 +11035,7 @@ function httpDelete(url, token) {
|
|
|
10400
11035
|
return;
|
|
10401
11036
|
}
|
|
10402
11037
|
try {
|
|
10403
|
-
|
|
11038
|
+
resolve10(raw ? JSON.parse(raw) : {});
|
|
10404
11039
|
} catch (err) {
|
|
10405
11040
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
10406
11041
|
}
|
|
@@ -10967,21 +11602,21 @@ async function runPtyAttach(endpoint, desc, _colour) {
|
|
|
10967
11602
|
});
|
|
10968
11603
|
}
|
|
10969
11604
|
async function probeDaemonHealth(baseUrl) {
|
|
10970
|
-
return new Promise((
|
|
11605
|
+
return new Promise((resolve10) => {
|
|
10971
11606
|
try {
|
|
10972
11607
|
const u = new URL(`${baseUrl}/health`);
|
|
10973
11608
|
const lib = u.protocol === "https:" ? https : http;
|
|
10974
11609
|
const req = lib.get(u, { timeout: 500 }, (res) => {
|
|
10975
|
-
|
|
11610
|
+
resolve10((res.statusCode ?? 0) >= 200 && (res.statusCode ?? 0) < 300);
|
|
10976
11611
|
res.resume();
|
|
10977
11612
|
});
|
|
10978
|
-
req.on("error", () =>
|
|
11613
|
+
req.on("error", () => resolve10(false));
|
|
10979
11614
|
req.on("timeout", () => {
|
|
10980
11615
|
req.destroy();
|
|
10981
|
-
|
|
11616
|
+
resolve10(false);
|
|
10982
11617
|
});
|
|
10983
11618
|
} catch {
|
|
10984
|
-
|
|
11619
|
+
resolve10(false);
|
|
10985
11620
|
}
|
|
10986
11621
|
});
|
|
10987
11622
|
}
|
|
@@ -11021,7 +11656,7 @@ async function explain401(endpoint, verb) {
|
|
|
11021
11656
|
return lines.join("\n");
|
|
11022
11657
|
}
|
|
11023
11658
|
function httpPostJson(url, body, token) {
|
|
11024
|
-
return new Promise((
|
|
11659
|
+
return new Promise((resolve10, reject) => {
|
|
11025
11660
|
const u = new URL(url);
|
|
11026
11661
|
const payload = Buffer.from(JSON.stringify(body), "utf8");
|
|
11027
11662
|
const lib = u.protocol === "https:" ? https : http;
|
|
@@ -11044,7 +11679,7 @@ function httpPostJson(url, body, token) {
|
|
|
11044
11679
|
return;
|
|
11045
11680
|
}
|
|
11046
11681
|
try {
|
|
11047
|
-
|
|
11682
|
+
resolve10(JSON.parse(raw));
|
|
11048
11683
|
} catch (err) {
|
|
11049
11684
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
11050
11685
|
}
|
|
@@ -11060,7 +11695,7 @@ async function httpGetJson(url) {
|
|
|
11060
11695
|
return await httpGetJsonImpl(url);
|
|
11061
11696
|
}
|
|
11062
11697
|
function httpGetJsonImpl(url) {
|
|
11063
|
-
return new Promise((
|
|
11698
|
+
return new Promise((resolve10, reject) => {
|
|
11064
11699
|
const u = new URL(url);
|
|
11065
11700
|
const lib = u.protocol === "https:" ? https : http;
|
|
11066
11701
|
lib.get(u, (res) => {
|
|
@@ -11073,7 +11708,7 @@ function httpGetJsonImpl(url) {
|
|
|
11073
11708
|
return;
|
|
11074
11709
|
}
|
|
11075
11710
|
try {
|
|
11076
|
-
|
|
11711
|
+
resolve10(JSON.parse(body));
|
|
11077
11712
|
} catch (err) {
|
|
11078
11713
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
11079
11714
|
}
|
|
@@ -11146,7 +11781,8 @@ async function main(argv) {
|
|
|
11146
11781
|
const verbIdx = argv.findIndex((a) => VERBS.has(a));
|
|
11147
11782
|
if (verbIdx === -1) {
|
|
11148
11783
|
if (argv.includes("--version") || argv.includes("-v")) {
|
|
11149
|
-
process.stdout.write(
|
|
11784
|
+
process.stdout.write(`agentproto ${"0.1.2"}
|
|
11785
|
+
`);
|
|
11150
11786
|
return 0;
|
|
11151
11787
|
}
|
|
11152
11788
|
if (argv.includes("--help") || argv.includes("-h") || argv.length === 0) {
|