@hilbras/omninode 2.0.0-alpha.3 → 2.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -9
- package/dist/cli/index.js +229 -35
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +165 -9
- package/dist/index.js +231 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,9 @@ existing intelligence; it does not try to become another model.
|
|
|
18
18
|
|
|
19
19
|
## Status
|
|
20
20
|
|
|
21
|
-
**v2.0.0-alpha.
|
|
21
|
+
**v2.0.0-alpha.4 — v2 Phase 4: Agent Adapter Hardening**
|
|
22
|
+
(after Phase 1: architecture & API stabilization, Phase 2: execution reliability,
|
|
23
|
+
Phase 3: agent protocol v2 — the reliability & interoperability line) (the v2
|
|
22
24
|
roadmap is [docs/ROADMAP_V2.md](docs/ROADMAP_V2.md); the v1 plan is complete:
|
|
23
25
|
the
|
|
24
26
|
full loop from §28 runs in one command —
|
|
@@ -27,14 +29,28 @@ planner → plan → execution → result` — with audit logging, error recover
|
|
|
27
29
|
production hardening (see [docs/DEVELOPMENT_PLAN.md](docs/DEVELOPMENT_PLAN.md)
|
|
28
30
|
for the plan and [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the design).
|
|
29
31
|
|
|
30
|
-
### What
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
### What's new in v2 (so far)
|
|
33
|
+
|
|
34
|
+
- **Phase 4 — Agent Adapter Hardening**: process-tree cleanup (agents run in
|
|
35
|
+
their own process group; timeout, cancel and Ctrl-C reap the whole tree, so
|
|
36
|
+
no orphaned children), explicit environment policies
|
|
37
|
+
(`inherit` / `allowlist` / `denylist` / `explicit`), working-directory
|
|
38
|
+
validation against project boundaries, per-stream output limits that kill
|
|
39
|
+
runaway agents, binary-safe output decoding, human-readable exit/signal
|
|
40
|
+
reporting, and a native `IAgentAdapter` registry so new integration styles
|
|
41
|
+
plug in without touching core.
|
|
42
|
+
- **Phase 3 — Agent Protocol v2**: versioned protocol
|
|
43
|
+
(`omninode-agent-protocol/2`), fully correlated envelopes, the complete
|
|
44
|
+
message-type set, HELLO handshake, QUESTION/RESPONSE round-trips, and
|
|
45
|
+
malformed input that can never crash OmniNode. Spec:
|
|
46
|
+
[PROTOCOL.md](docs/PROTOCOL.md).
|
|
47
|
+
- **Phase 2 — Execution Reliability**: a task killed after dispatch is
|
|
48
|
+
`unknown`, **not** `failed` — retries never duplicate side effects blindly;
|
|
49
|
+
bounded retries with backoff, execution identity and history.
|
|
50
|
+
- **Phase 1 — Architecture & API Stabilization**: one shared `JsonFileStore`
|
|
51
|
+
behind every local store, corrected dependency direction, and a guarded
|
|
52
|
+
public API ([API_STABILITY.md](docs/API_STABILITY.md), [API.md](docs/API.md),
|
|
53
|
+
[DEPRECATIONS.md](docs/DEPRECATIONS.md)).
|
|
38
54
|
|
|
39
55
|
### What's in v1.0
|
|
40
56
|
|
package/dist/cli/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { realpathSync } from "fs";
|
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
|
|
8
8
|
// src/version.ts
|
|
9
|
-
var OMNINODE_VERSION = "2.0.0-alpha.
|
|
9
|
+
var OMNINODE_VERSION = "2.0.0-alpha.4";
|
|
10
10
|
|
|
11
11
|
// src/errors/index.ts
|
|
12
12
|
var OmniNodeError = class extends Error {
|
|
@@ -83,6 +83,11 @@ var agentConfigSchema = z.object({
|
|
|
83
83
|
input_mode: z.enum(["stdin", "arg", "protocol"]).default("stdin"),
|
|
84
84
|
timeout_ms: z.number().int().positive().optional(),
|
|
85
85
|
inherit_env: z.boolean().optional(),
|
|
86
|
+
env_policy: z.enum(["inherit", "allowlist", "denylist", "explicit"]).optional(),
|
|
87
|
+
env_allowlist: z.array(z.string()).optional(),
|
|
88
|
+
env_denylist: z.array(z.string()).optional(),
|
|
89
|
+
max_output_bytes: z.number().int().positive().optional(),
|
|
90
|
+
allow_external_cwd: z.boolean().optional(),
|
|
86
91
|
metadata: z.record(z.unknown()).optional()
|
|
87
92
|
}).strict();
|
|
88
93
|
var roleConfigSchema = z.object({
|
|
@@ -257,6 +262,11 @@ function toAgentConfig(raw) {
|
|
|
257
262
|
inputMode: raw.input_mode,
|
|
258
263
|
timeoutMs: raw.timeout_ms,
|
|
259
264
|
inheritEnv: raw.inherit_env,
|
|
265
|
+
envPolicy: raw.env_policy,
|
|
266
|
+
envAllowlist: raw.env_allowlist,
|
|
267
|
+
envDenylist: raw.env_denylist,
|
|
268
|
+
maxOutputBytes: raw.max_output_bytes,
|
|
269
|
+
allowExternalCwd: raw.allow_external_cwd,
|
|
260
270
|
metadata: raw.metadata
|
|
261
271
|
};
|
|
262
272
|
}
|
|
@@ -1214,20 +1224,94 @@ var ProtocolSession = class {
|
|
|
1214
1224
|
sawV2 = false;
|
|
1215
1225
|
};
|
|
1216
1226
|
|
|
1217
|
-
// src/agents/
|
|
1218
|
-
|
|
1219
|
-
|
|
1227
|
+
// src/agents/cwd.ts
|
|
1228
|
+
import { statSync } from "fs";
|
|
1229
|
+
import { isAbsolute, relative, resolve } from "path";
|
|
1230
|
+
function validateWorkingDirectory(cwd, options = {}) {
|
|
1231
|
+
if (!cwd) return void 0;
|
|
1232
|
+
const normalized = isAbsolute(cwd) ? resolve(cwd) : resolve(process.cwd(), cwd);
|
|
1233
|
+
let stats;
|
|
1234
|
+
try {
|
|
1235
|
+
stats = statSync(normalized);
|
|
1236
|
+
} catch (error) {
|
|
1237
|
+
throw new AgentError(
|
|
1238
|
+
"AGENT_NOT_FOUND",
|
|
1239
|
+
`Working directory "${normalized}" does not exist or is not accessible.`,
|
|
1240
|
+
{ cause: error, details: { cwd: normalized } }
|
|
1241
|
+
);
|
|
1242
|
+
}
|
|
1243
|
+
if (!stats.isDirectory()) {
|
|
1244
|
+
throw new AgentError("AGENT_NOT_FOUND", `Working directory "${normalized}" is not a directory.`, {
|
|
1245
|
+
details: { cwd: normalized }
|
|
1246
|
+
});
|
|
1247
|
+
}
|
|
1248
|
+
try {
|
|
1249
|
+
statSync(resolve(normalized, "."));
|
|
1250
|
+
} catch (error) {
|
|
1251
|
+
throw new AgentError(
|
|
1252
|
+
"AGENT_NOT_FOUND",
|
|
1253
|
+
`Working directory "${normalized}" is not accessible.`,
|
|
1254
|
+
{ cause: error }
|
|
1255
|
+
);
|
|
1256
|
+
}
|
|
1257
|
+
const projectRoot = resolve(options.projectRoot ?? process.cwd());
|
|
1258
|
+
const rel = relative(projectRoot, normalized);
|
|
1259
|
+
const outsideProject = rel.startsWith("..") || isAbsolute(rel);
|
|
1260
|
+
if (outsideProject && options.allowExternal !== true) {
|
|
1261
|
+
throw new AgentError(
|
|
1262
|
+
"AGENT_NOT_FOUND",
|
|
1263
|
+
`Working directory "${normalized}" is outside the project root "${projectRoot}". Set allow_external_cwd: true on the agent to permit this.`,
|
|
1264
|
+
{ details: { cwd: normalized, projectRoot } }
|
|
1265
|
+
);
|
|
1266
|
+
}
|
|
1267
|
+
return { cwd: normalized, outsideProject };
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// src/agents/env.ts
|
|
1271
|
+
var BASELINE_KEYS = ["PATH", "HOME"];
|
|
1272
|
+
function resolveEnvPolicy(config) {
|
|
1273
|
+
if (config.envPolicy !== void 0) return config.envPolicy;
|
|
1274
|
+
if (config.inheritEnv === false) return "explicit";
|
|
1275
|
+
return "inherit";
|
|
1276
|
+
}
|
|
1220
1277
|
function buildChildEnv(config) {
|
|
1221
1278
|
const configured = config.env ?? {};
|
|
1222
|
-
|
|
1279
|
+
const policy = resolveEnvPolicy(config);
|
|
1280
|
+
if (policy === "inherit") {
|
|
1223
1281
|
return { ...process.env, ...configured };
|
|
1224
1282
|
}
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
}
|
|
1283
|
+
const base = {};
|
|
1284
|
+
for (const key of BASELINE_KEYS) {
|
|
1285
|
+
const value = process.env[key];
|
|
1286
|
+
if (value !== void 0) base[key] = value;
|
|
1287
|
+
}
|
|
1288
|
+
switch (policy) {
|
|
1289
|
+
case "explicit":
|
|
1290
|
+
return { ...base, ...configured };
|
|
1291
|
+
case "allowlist": {
|
|
1292
|
+
const allowed = { ...base };
|
|
1293
|
+
for (const key of config.envAllowlist ?? []) {
|
|
1294
|
+
const value = process.env[key];
|
|
1295
|
+
if (value !== void 0) allowed[key] = value;
|
|
1296
|
+
}
|
|
1297
|
+
return { ...allowed, ...configured };
|
|
1298
|
+
}
|
|
1299
|
+
case "denylist": {
|
|
1300
|
+
const denied = new Set((config.envDenylist ?? []).map((k) => k.toUpperCase()));
|
|
1301
|
+
const filtered = {};
|
|
1302
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
1303
|
+
if (denied.has(key.toUpperCase())) continue;
|
|
1304
|
+
filtered[key] = value;
|
|
1305
|
+
}
|
|
1306
|
+
return { ...filtered, ...configured };
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1230
1309
|
}
|
|
1310
|
+
|
|
1311
|
+
// src/agents/process/index.ts
|
|
1312
|
+
var DEFAULT_TIMEOUT_MS2 = 6e5;
|
|
1313
|
+
var KILL_GRACE_MS = 5e3;
|
|
1314
|
+
var DEFAULT_MAX_OUTPUT_BYTES = 5 * 1024 * 1024;
|
|
1231
1315
|
function composeTaskText(input) {
|
|
1232
1316
|
const sections = [`# Objective
|
|
1233
1317
|
${input.objective}`];
|
|
@@ -1289,40 +1373,73 @@ var ProcessAgent = class {
|
|
|
1289
1373
|
}
|
|
1290
1374
|
const mode = this.config.inputMode ?? "stdin";
|
|
1291
1375
|
const timeoutMs = this.config.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
1292
|
-
return new Promise((
|
|
1376
|
+
return new Promise((resolve2, reject) => {
|
|
1377
|
+
let cwd;
|
|
1378
|
+
try {
|
|
1379
|
+
cwd = validateWorkingDirectory(this.config.cwd, {
|
|
1380
|
+
allowExternal: this.config.allowExternalCwd
|
|
1381
|
+
})?.cwd;
|
|
1382
|
+
} catch (error) {
|
|
1383
|
+
reject(error);
|
|
1384
|
+
return;
|
|
1385
|
+
}
|
|
1293
1386
|
const child = spawn(
|
|
1294
1387
|
command,
|
|
1295
1388
|
[...this.config.args ?? [], ...mode === "arg" ? [composeTaskText(input)] : []],
|
|
1296
1389
|
{
|
|
1297
|
-
cwd:
|
|
1390
|
+
...cwd !== void 0 ? { cwd } : {},
|
|
1298
1391
|
env: buildChildEnv(this.config),
|
|
1299
|
-
stdio: ["pipe", "pipe", "pipe"]
|
|
1392
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1393
|
+
// Own process group so the whole tree can be terminated together
|
|
1394
|
+
// (roadmap §8: no orphaned children).
|
|
1395
|
+
...process.platform === "win32" ? {} : { detached: true }
|
|
1300
1396
|
}
|
|
1301
1397
|
);
|
|
1302
1398
|
this.running.set(input.taskId, child);
|
|
1399
|
+
GLOBAL_RUNNING.add(child);
|
|
1400
|
+
installSignalForwarding();
|
|
1303
1401
|
let stdout = "";
|
|
1304
1402
|
let stderr = "";
|
|
1305
1403
|
let timedOut = false;
|
|
1404
|
+
let outputLimitExceeded = false;
|
|
1306
1405
|
let settled = false;
|
|
1406
|
+
const maxOutputBytes = this.config.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
|
|
1307
1407
|
const timer = setTimeout(() => {
|
|
1308
1408
|
timedOut = true;
|
|
1309
|
-
this.log.warn(`Task ${input.taskId} exceeded ${timeoutMs}ms \u2014 killing process.`);
|
|
1310
|
-
child
|
|
1311
|
-
setTimeout(() => child
|
|
1409
|
+
this.log.warn(`Task ${input.taskId} exceeded ${timeoutMs}ms \u2014 killing process tree.`);
|
|
1410
|
+
killTree(child, "SIGTERM");
|
|
1411
|
+
setTimeout(() => killTree(child, "SIGKILL"), KILL_GRACE_MS).unref();
|
|
1312
1412
|
}, timeoutMs);
|
|
1313
1413
|
const settle = (finish) => {
|
|
1314
1414
|
if (settled) return;
|
|
1315
1415
|
settled = true;
|
|
1316
1416
|
clearTimeout(timer);
|
|
1317
1417
|
this.running.delete(input.taskId);
|
|
1418
|
+
GLOBAL_RUNNING.delete(child);
|
|
1318
1419
|
finish();
|
|
1319
1420
|
};
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1421
|
+
const collect = (into, chunk) => {
|
|
1422
|
+
if (outputLimitExceeded) return;
|
|
1423
|
+
const text = sanitizeChunk(chunk);
|
|
1424
|
+
if (into === "stdout") {
|
|
1425
|
+
if (stdout.length + text.length > maxOutputBytes) {
|
|
1426
|
+
stdout = (stdout + text).slice(0, maxOutputBytes);
|
|
1427
|
+
outputLimitExceeded = true;
|
|
1428
|
+
this.log.warn(`Agent "${this.config.name}" exceeded the ${maxOutputBytes} byte output limit \u2014 killing it.`);
|
|
1429
|
+
killTree(child, "SIGKILL");
|
|
1430
|
+
return;
|
|
1431
|
+
}
|
|
1432
|
+
stdout += text;
|
|
1433
|
+
} else {
|
|
1434
|
+
if (stderr.length + text.length > maxOutputBytes) {
|
|
1435
|
+
stderr = (stderr + text).slice(0, maxOutputBytes);
|
|
1436
|
+
return;
|
|
1437
|
+
}
|
|
1438
|
+
stderr += text;
|
|
1439
|
+
}
|
|
1440
|
+
};
|
|
1441
|
+
child.stdout?.on("data", (chunk) => collect("stdout", chunk));
|
|
1442
|
+
child.stderr?.on("data", (chunk) => collect("stderr", chunk));
|
|
1326
1443
|
child.stdin?.on("error", () => {
|
|
1327
1444
|
});
|
|
1328
1445
|
if (mode !== "arg") {
|
|
@@ -1376,7 +1493,7 @@ var ProcessAgent = class {
|
|
|
1376
1493
|
const logs = stderr.trim().length > 0 ? stderr.split("\n") : void 0;
|
|
1377
1494
|
if (mode === "protocol") {
|
|
1378
1495
|
try {
|
|
1379
|
-
|
|
1496
|
+
resolve2(
|
|
1380
1497
|
interpretProtocolRun({
|
|
1381
1498
|
input,
|
|
1382
1499
|
agentName: this.config.name,
|
|
@@ -1391,14 +1508,14 @@ var ProcessAgent = class {
|
|
|
1391
1508
|
return;
|
|
1392
1509
|
}
|
|
1393
1510
|
const trimmed = stdout.trim();
|
|
1394
|
-
|
|
1511
|
+
resolve2({
|
|
1395
1512
|
taskId: input.taskId,
|
|
1396
|
-
status: code === 0 ? "completed" : "failed",
|
|
1513
|
+
status: code === 0 && !outputLimitExceeded ? "completed" : "failed",
|
|
1397
1514
|
summary: trimmed.length > 0 ? firstLine(trimmed) : void 0,
|
|
1398
1515
|
rawOutput: trimmed.length > 0 ? trimmed : void 0,
|
|
1399
1516
|
exitCode: code ?? void 0,
|
|
1400
1517
|
logs,
|
|
1401
|
-
error:
|
|
1518
|
+
...outputLimitExceeded ? { error: `Agent exceeded the ${maxOutputBytes} byte output limit and was terminated.` } : code === 0 ? {} : { error: describeExit(code, signal) }
|
|
1402
1519
|
});
|
|
1403
1520
|
});
|
|
1404
1521
|
});
|
|
@@ -1407,7 +1524,7 @@ var ProcessAgent = class {
|
|
|
1407
1524
|
/** Ask the agent to stop current work (SIGTERM). */
|
|
1408
1525
|
async cancel(taskId) {
|
|
1409
1526
|
const child = this.running.get(taskId);
|
|
1410
|
-
if (child) child
|
|
1527
|
+
if (child) killTree(child, "SIGTERM");
|
|
1411
1528
|
}
|
|
1412
1529
|
runningTaskIds() {
|
|
1413
1530
|
return [...this.running.keys()];
|
|
@@ -1482,6 +1599,43 @@ function interpretProtocolRun({
|
|
|
1482
1599
|
...exitCode !== 0 ? { error: `Process exited with code ${exitCode ?? "unknown"}` } : {}
|
|
1483
1600
|
};
|
|
1484
1601
|
}
|
|
1602
|
+
var GLOBAL_RUNNING = /* @__PURE__ */ new Set();
|
|
1603
|
+
var signalForwardingInstalled = false;
|
|
1604
|
+
function installSignalForwarding() {
|
|
1605
|
+
if (signalForwardingInstalled) return;
|
|
1606
|
+
signalForwardingInstalled = true;
|
|
1607
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
1608
|
+
process.on(signal, () => {
|
|
1609
|
+
for (const child of GLOBAL_RUNNING) {
|
|
1610
|
+
killTree(child, "SIGTERM");
|
|
1611
|
+
}
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
}
|
|
1615
|
+
function killTree(child, signal) {
|
|
1616
|
+
if (child.pid === void 0) return;
|
|
1617
|
+
if (process.platform !== "win32") {
|
|
1618
|
+
try {
|
|
1619
|
+
process.kill(-child.pid, signal);
|
|
1620
|
+
return;
|
|
1621
|
+
} catch {
|
|
1622
|
+
}
|
|
1623
|
+
}
|
|
1624
|
+
try {
|
|
1625
|
+
child.kill(signal);
|
|
1626
|
+
} catch {
|
|
1627
|
+
}
|
|
1628
|
+
}
|
|
1629
|
+
function describeExit(code, signal) {
|
|
1630
|
+
if (signal !== null) {
|
|
1631
|
+
return signal === "SIGKILL" ? "Process was killed (SIGKILL) \u2014 usually an external kill or OOM." : `Process terminated by signal ${signal}.`;
|
|
1632
|
+
}
|
|
1633
|
+
if (code === null) return "Process terminated without an exit code.";
|
|
1634
|
+
return `Process exited with code ${code}.`;
|
|
1635
|
+
}
|
|
1636
|
+
function sanitizeChunk(chunk) {
|
|
1637
|
+
return chunk.toString("utf8").replace(/\u0000/g, "");
|
|
1638
|
+
}
|
|
1485
1639
|
function normalizeReport(payload, taskId, agentName, index) {
|
|
1486
1640
|
if (payload === null || typeof payload !== "object") return void 0;
|
|
1487
1641
|
const raw = payload;
|
|
@@ -1501,6 +1655,40 @@ function firstLine(text, maxLength = 200) {
|
|
|
1501
1655
|
return line.length > maxLength ? `${line.slice(0, maxLength)}\u2026` : line;
|
|
1502
1656
|
}
|
|
1503
1657
|
|
|
1658
|
+
// src/agents/adapters.ts
|
|
1659
|
+
var AgentAdapterRegistry = class {
|
|
1660
|
+
adapters = /* @__PURE__ */ new Map();
|
|
1661
|
+
register(adapter) {
|
|
1662
|
+
this.adapters.set(adapter.integration, adapter);
|
|
1663
|
+
}
|
|
1664
|
+
get(integration) {
|
|
1665
|
+
return this.adapters.get(integration);
|
|
1666
|
+
}
|
|
1667
|
+
list() {
|
|
1668
|
+
return [...this.adapters.values()];
|
|
1669
|
+
}
|
|
1670
|
+
create(config) {
|
|
1671
|
+
const adapter = this.get(config.integration);
|
|
1672
|
+
if (!adapter) {
|
|
1673
|
+
throw new AgentError(
|
|
1674
|
+
"AGENT_NOT_FOUND",
|
|
1675
|
+
`No agent adapter registered for integration "${config.integration}". Registered: ${[...this.adapters.keys()].join(", ") || "(none)"}.`
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
return adapter.create(config);
|
|
1679
|
+
}
|
|
1680
|
+
};
|
|
1681
|
+
var ProcessAgentAdapter = class {
|
|
1682
|
+
constructor(factory) {
|
|
1683
|
+
this.factory = factory;
|
|
1684
|
+
}
|
|
1685
|
+
factory;
|
|
1686
|
+
integration = "process";
|
|
1687
|
+
create(config) {
|
|
1688
|
+
return this.factory(config);
|
|
1689
|
+
}
|
|
1690
|
+
};
|
|
1691
|
+
|
|
1504
1692
|
// src/agents/registry.ts
|
|
1505
1693
|
var AgentRegistry = class {
|
|
1506
1694
|
agents = /* @__PURE__ */ new Map();
|
|
@@ -1516,14 +1704,15 @@ var AgentRegistry = class {
|
|
|
1516
1704
|
};
|
|
1517
1705
|
|
|
1518
1706
|
// src/agents/factory.ts
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1707
|
+
var defaultAgentAdapters = new AgentAdapterRegistry();
|
|
1708
|
+
defaultAgentAdapters.register(new ProcessAgentAdapter((config) => new ProcessAgent(config)));
|
|
1709
|
+
function createAgent(config, adapters = defaultAgentAdapters) {
|
|
1710
|
+
const registered = adapters.get(config.integration);
|
|
1711
|
+
if (registered) return registered.create(config);
|
|
1523
1712
|
if (config.integration === "native") {
|
|
1524
1713
|
throw new OmniNodeError(
|
|
1525
1714
|
"NOT_IMPLEMENTED",
|
|
1526
|
-
`
|
|
1715
|
+
`No native adapter is registered for "${config.name}". Register an IAgentAdapter (createAgent(config, adapters)) or use input over stdin/stdout (type "cli").`
|
|
1527
1716
|
);
|
|
1528
1717
|
}
|
|
1529
1718
|
throw new OmniNodeError("NOT_IMPLEMENTED", `Agent integration "${config.integration}" has no adapter yet.`);
|
|
@@ -1566,7 +1755,7 @@ function registerAgentCommands(program) {
|
|
|
1566
1755
|
"--input-mode <mode>",
|
|
1567
1756
|
"How the task is delivered: stdin (prompt on stdin), arg (prompt as last argument) or protocol (\xA721 JSON-lines task protocol).",
|
|
1568
1757
|
"stdin"
|
|
1569
|
-
).option(
|
|
1758
|
+
).option("--env-policy <policy>", "Environment policy: inherit, allowlist, denylist or explicit.").option("--allow-env <name>", "Variable to forward under the allowlist policy (repeatable).", collectArgs).option("--deny-env <name>", "Variable to remove under the denylist policy (repeatable).", collectArgs).option("--max-output-bytes <n>", "Per-stream output budget in bytes (default 5 MiB).", (value) => Number(value)).option("--allow-external-cwd", "Allow a working directory outside the project root.").option(
|
|
1570
1759
|
"--timeout-ms <ms>",
|
|
1571
1760
|
"Per-task timeout in milliseconds.",
|
|
1572
1761
|
(value) => Number(value)
|
|
@@ -1581,7 +1770,12 @@ async function addAgent(options) {
|
|
|
1581
1770
|
...options.arg !== void 0 && options.arg.length > 0 ? { args: options.arg } : {},
|
|
1582
1771
|
...options.cwd !== void 0 ? { cwd: options.cwd } : {},
|
|
1583
1772
|
input_mode: options.inputMode,
|
|
1584
|
-
...options.timeoutMs !== void 0 ? { timeout_ms: options.timeoutMs } : {}
|
|
1773
|
+
...options.timeoutMs !== void 0 ? { timeout_ms: options.timeoutMs } : {},
|
|
1774
|
+
...options.envPolicy !== void 0 ? { env_policy: options.envPolicy } : {},
|
|
1775
|
+
...options.allowEnv !== void 0 && options.allowEnv.length > 0 ? { env_allowlist: options.allowEnv } : {},
|
|
1776
|
+
...options.denyEnv !== void 0 && options.denyEnv.length > 0 ? { env_denylist: options.denyEnv } : {},
|
|
1777
|
+
...options.maxOutputBytes !== void 0 ? { max_output_bytes: options.maxOutputBytes } : {},
|
|
1778
|
+
...options.allowExternalCwd !== void 0 ? { allow_external_cwd: options.allowExternalCwd } : {}
|
|
1585
1779
|
});
|
|
1586
1780
|
if (!candidate.success) {
|
|
1587
1781
|
const issues = candidate.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
|
|
@@ -1985,7 +2179,7 @@ function classifyThrown(error) {
|
|
|
1985
2179
|
return "failed";
|
|
1986
2180
|
}
|
|
1987
2181
|
function sleep(ms) {
|
|
1988
|
-
return new Promise((
|
|
2182
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
1989
2183
|
}
|
|
1990
2184
|
|
|
1991
2185
|
// src/audit/index.ts
|