omniagent 0.1.13 → 0.1.16
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 +24 -9
- package/dist/agy-DlbWeyP_.js +379 -0
- package/dist/{claude-DWeyS4fP.js → claude-CcxRb8OW.js} +2 -2
- package/dist/cli.js +1044 -154
- package/dist/{codex-0b2YLh_8.js → codex-DhlBosXm.js} +2 -2
- package/dist/{pty-CZBSAJzE.js → pty-D8BFQQQg.js} +13 -10
- package/package.json +4 -1
- package/dist/gemini-BVRg6OMO.js +0 -437
package/dist/cli.js
CHANGED
|
@@ -3,7 +3,7 @@ import { constants, realpathSync, existsSync, readFileSync } from "node:fs";
|
|
|
3
3
|
import { pathToFileURL, fileURLToPath } from "node:url";
|
|
4
4
|
import yargs from "yargs";
|
|
5
5
|
import { hideBin } from "yargs/helpers";
|
|
6
|
-
import { stat, rm, readdir, access, readFile, mkdir, writeFile, rename } from "node:fs/promises";
|
|
6
|
+
import { stat, rm, readdir, access, readFile, mkdir, writeFile, rename, mkdtemp } from "node:fs/promises";
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import { createHash, randomUUID } from "node:crypto";
|
|
9
9
|
import os from "node:os";
|
|
@@ -11,6 +11,9 @@ import { Minimatch } from "minimatch";
|
|
|
11
11
|
import { createInterface } from "node:readline/promises";
|
|
12
12
|
import { TextDecoder } from "node:util";
|
|
13
13
|
import { spawn } from "node:child_process";
|
|
14
|
+
import Ajv from "ajv";
|
|
15
|
+
import Ajv2019 from "ajv/dist/2019.js";
|
|
16
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
14
17
|
async function pathExists$2(candidate) {
|
|
15
18
|
try {
|
|
16
19
|
await stat(candidate);
|
|
@@ -475,14 +478,14 @@ const ALLOWED_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
475
478
|
]);
|
|
476
479
|
const ALLOWED_CATEGORY_KEYS = new Set(PROFILE_CATEGORIES);
|
|
477
480
|
const ALLOWED_TARGET_SETTING_KEYS = /* @__PURE__ */ new Set(["enabled"]);
|
|
478
|
-
function isPlainObject$
|
|
481
|
+
function isPlainObject$2(value) {
|
|
479
482
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
480
483
|
}
|
|
481
484
|
function pushError(errors, path2, message) {
|
|
482
485
|
errors.push({ path: path2, message });
|
|
483
486
|
}
|
|
484
487
|
function validatePatternMap(value, pathPrefix, errors) {
|
|
485
|
-
if (!isPlainObject$
|
|
488
|
+
if (!isPlainObject$2(value)) {
|
|
486
489
|
pushError(errors, pathPrefix, "must be an object.");
|
|
487
490
|
return;
|
|
488
491
|
}
|
|
@@ -507,7 +510,7 @@ function validatePatternMap(value, pathPrefix, errors) {
|
|
|
507
510
|
}
|
|
508
511
|
}
|
|
509
512
|
function validateTargets(value, errors) {
|
|
510
|
-
if (!isPlainObject$
|
|
513
|
+
if (!isPlainObject$2(value)) {
|
|
511
514
|
pushError(errors, "targets", "must be an object.");
|
|
512
515
|
return;
|
|
513
516
|
}
|
|
@@ -516,7 +519,7 @@ function validateTargets(value, errors) {
|
|
|
516
519
|
pushError(errors, "targets", `target keys must be non-empty strings (got "${targetName}").`);
|
|
517
520
|
continue;
|
|
518
521
|
}
|
|
519
|
-
if (!isPlainObject$
|
|
522
|
+
if (!isPlainObject$2(setting)) {
|
|
520
523
|
pushError(errors, `targets.${targetName}`, "must be an object.");
|
|
521
524
|
continue;
|
|
522
525
|
}
|
|
@@ -532,7 +535,7 @@ function validateTargets(value, errors) {
|
|
|
532
535
|
}
|
|
533
536
|
function validateProfile(value) {
|
|
534
537
|
const errors = [];
|
|
535
|
-
if (!isPlainObject$
|
|
538
|
+
if (!isPlainObject$2(value)) {
|
|
536
539
|
return {
|
|
537
540
|
valid: false,
|
|
538
541
|
errors: [{ path: "", message: "profile must be a JSON object." }]
|
|
@@ -578,7 +581,7 @@ function validateProfile(value) {
|
|
|
578
581
|
};
|
|
579
582
|
}
|
|
580
583
|
function validateVariables(value, errors) {
|
|
581
|
-
if (!isPlainObject$
|
|
584
|
+
if (!isPlainObject$2(value)) {
|
|
582
585
|
pushError(errors, "variables", "must be an object of string values.");
|
|
583
586
|
return;
|
|
584
587
|
}
|
|
@@ -1272,6 +1275,74 @@ function resolveEffectiveTargets(options) {
|
|
|
1272
1275
|
const skipSet = new Set(overrideSkip.map((target) => normalizeTargetName(target)));
|
|
1273
1276
|
return dedupeTargets(base.filter((target) => !skipSet.has(normalizeTargetName(target))));
|
|
1274
1277
|
}
|
|
1278
|
+
const agyTarget = {
|
|
1279
|
+
id: "agy",
|
|
1280
|
+
displayName: "Antigravity CLI",
|
|
1281
|
+
aliases: ["gemini"],
|
|
1282
|
+
cli: {
|
|
1283
|
+
modes: {
|
|
1284
|
+
interactive: { command: "agy" },
|
|
1285
|
+
oneShot: { command: "agy" }
|
|
1286
|
+
},
|
|
1287
|
+
// agy requires the prompt as -p's argument; the shim always passes the
|
|
1288
|
+
// (possibly stdin-derived) prompt inline, so piped stdin works.
|
|
1289
|
+
prompt: { type: "flag", flag: ["-p"] },
|
|
1290
|
+
flags: {
|
|
1291
|
+
approval: {
|
|
1292
|
+
values: {
|
|
1293
|
+
prompt: [],
|
|
1294
|
+
"auto-edit": null,
|
|
1295
|
+
yolo: ["--dangerously-skip-permissions"]
|
|
1296
|
+
}
|
|
1297
|
+
},
|
|
1298
|
+
sandbox: {
|
|
1299
|
+
values: {
|
|
1300
|
+
"workspace-write": ["--sandbox"],
|
|
1301
|
+
off: []
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
output: {
|
|
1305
|
+
byMode: {
|
|
1306
|
+
"one-shot": {
|
|
1307
|
+
text: [],
|
|
1308
|
+
json: null,
|
|
1309
|
+
"stream-json": null
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
},
|
|
1313
|
+
// Model names are display strings, e.g. "Gemini 3.5 Flash (Low)"; list via `agy models`.
|
|
1314
|
+
model: { flag: ["--model"] },
|
|
1315
|
+
structuredOutputFallback: {
|
|
1316
|
+
extraction: { type: "text" }
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
},
|
|
1320
|
+
outputs: {
|
|
1321
|
+
skills: "{repoRoot}/.agents/skills/{itemName}",
|
|
1322
|
+
subagents: {
|
|
1323
|
+
path: "{repoRoot}/.agents/skills/{itemName}",
|
|
1324
|
+
fallback: { mode: "convert", targetType: "skills" }
|
|
1325
|
+
},
|
|
1326
|
+
commands: {
|
|
1327
|
+
fallback: { mode: "convert", targetType: "skills" }
|
|
1328
|
+
},
|
|
1329
|
+
instructions: {
|
|
1330
|
+
filename: "AGENTS.md",
|
|
1331
|
+
group: "agents"
|
|
1332
|
+
}
|
|
1333
|
+
},
|
|
1334
|
+
usage: {
|
|
1335
|
+
windows: ["weekly"],
|
|
1336
|
+
launch: {
|
|
1337
|
+
command: "agy",
|
|
1338
|
+
timeoutMs: 7e4
|
|
1339
|
+
},
|
|
1340
|
+
extract: async (context) => {
|
|
1341
|
+
const { extractAgyUsage } = await import("./agy-DlbWeyP_.js");
|
|
1342
|
+
return extractAgyUsage(context);
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1275
1346
|
const claudeTarget = {
|
|
1276
1347
|
id: "claude",
|
|
1277
1348
|
displayName: "Claude Code",
|
|
@@ -1298,7 +1369,13 @@ const claudeTarget = {
|
|
|
1298
1369
|
}
|
|
1299
1370
|
}
|
|
1300
1371
|
},
|
|
1301
|
-
model: { flag: ["--model"] }
|
|
1372
|
+
model: { flag: ["--model"] },
|
|
1373
|
+
structuredOutput: {
|
|
1374
|
+
delivery: "inline",
|
|
1375
|
+
flag: ["--json-schema"],
|
|
1376
|
+
companionArgs: ["--output-format", "json"],
|
|
1377
|
+
extraction: { type: "json-envelope", field: "structured_output" }
|
|
1378
|
+
}
|
|
1302
1379
|
}
|
|
1303
1380
|
},
|
|
1304
1381
|
outputs: {
|
|
@@ -1322,7 +1399,7 @@ const claudeTarget = {
|
|
|
1322
1399
|
timeoutMs: 6e4
|
|
1323
1400
|
},
|
|
1324
1401
|
extract: async (context) => {
|
|
1325
|
-
const { extractClaudeUsage } = await import("./claude-
|
|
1402
|
+
const { extractClaudeUsage } = await import("./claude-CcxRb8OW.js");
|
|
1326
1403
|
return extractClaudeUsage(context);
|
|
1327
1404
|
}
|
|
1328
1405
|
}
|
|
@@ -1368,7 +1445,12 @@ const codexTarget = {
|
|
|
1368
1445
|
}
|
|
1369
1446
|
},
|
|
1370
1447
|
model: { flag: ["-m"] },
|
|
1371
|
-
web: { on: ["--search"], off: ["--disable", "web_search_request"] }
|
|
1448
|
+
web: { on: ["--search"], off: ["--disable", "web_search_request"] },
|
|
1449
|
+
structuredOutput: {
|
|
1450
|
+
delivery: "file",
|
|
1451
|
+
flag: ["--output-schema"],
|
|
1452
|
+
extraction: { type: "last-message-file", flag: ["--output-last-message"] }
|
|
1453
|
+
}
|
|
1372
1454
|
}
|
|
1373
1455
|
},
|
|
1374
1456
|
outputs: {
|
|
@@ -1402,7 +1484,7 @@ const codexTarget = {
|
|
|
1402
1484
|
timeoutMs: 6e4
|
|
1403
1485
|
},
|
|
1404
1486
|
extract: async (context) => {
|
|
1405
|
-
const { extractCodexUsage } = await import("./codex-
|
|
1487
|
+
const { extractCodexUsage } = await import("./codex-DhlBosXm.js");
|
|
1406
1488
|
return extractCodexUsage(context);
|
|
1407
1489
|
}
|
|
1408
1490
|
}
|
|
@@ -1500,7 +1582,11 @@ const copilotTarget = {
|
|
|
1500
1582
|
}
|
|
1501
1583
|
}
|
|
1502
1584
|
},
|
|
1503
|
-
model: { flag: ["--model"] }
|
|
1585
|
+
model: { flag: ["--model"] },
|
|
1586
|
+
structuredOutputFallback: {
|
|
1587
|
+
args: ["--silent"],
|
|
1588
|
+
extraction: { type: "text" }
|
|
1589
|
+
}
|
|
1504
1590
|
}
|
|
1505
1591
|
},
|
|
1506
1592
|
outputs: {
|
|
@@ -1547,74 +1633,10 @@ const copilotTarget = {
|
|
|
1547
1633
|
}
|
|
1548
1634
|
}
|
|
1549
1635
|
};
|
|
1550
|
-
const geminiTarget = {
|
|
1551
|
-
id: "gemini",
|
|
1552
|
-
displayName: "Gemini CLI",
|
|
1553
|
-
cli: {
|
|
1554
|
-
modes: {
|
|
1555
|
-
interactive: { command: "gemini" },
|
|
1556
|
-
oneShot: { command: "gemini" }
|
|
1557
|
-
},
|
|
1558
|
-
prompt: { type: "flag", flag: ["-p"] },
|
|
1559
|
-
flags: {
|
|
1560
|
-
approval: {
|
|
1561
|
-
values: {
|
|
1562
|
-
prompt: ["--approval-mode", "default"],
|
|
1563
|
-
"auto-edit": ["--approval-mode", "auto_edit"],
|
|
1564
|
-
yolo: ["--yolo"]
|
|
1565
|
-
}
|
|
1566
|
-
},
|
|
1567
|
-
sandbox: {
|
|
1568
|
-
values: {
|
|
1569
|
-
"workspace-write": ["--sandbox"],
|
|
1570
|
-
off: []
|
|
1571
|
-
}
|
|
1572
|
-
},
|
|
1573
|
-
output: {
|
|
1574
|
-
byMode: {
|
|
1575
|
-
"one-shot": {
|
|
1576
|
-
text: [],
|
|
1577
|
-
json: ["--output-format", "json"],
|
|
1578
|
-
"stream-json": ["--output-format", "stream-json"]
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
},
|
|
1582
|
-
model: { flag: ["--model"] },
|
|
1583
|
-
web: { on: [], off: null }
|
|
1584
|
-
}
|
|
1585
|
-
},
|
|
1586
|
-
outputs: {
|
|
1587
|
-
skills: "{repoRoot}/.gemini/skills/{itemName}",
|
|
1588
|
-
subagents: {
|
|
1589
|
-
path: "{repoRoot}/.gemini/skills/{itemName}",
|
|
1590
|
-
fallback: { mode: "convert", targetType: "skills" }
|
|
1591
|
-
},
|
|
1592
|
-
commands: {
|
|
1593
|
-
projectPath: "{repoRoot}/.gemini/commands/{itemName}.toml",
|
|
1594
|
-
userPath: "{homeDir}/.gemini/commands/{itemName}.toml"
|
|
1595
|
-
},
|
|
1596
|
-
instructions: {
|
|
1597
|
-
filename: "GEMINI.md"
|
|
1598
|
-
}
|
|
1599
|
-
},
|
|
1600
|
-
usage: {
|
|
1601
|
-
windows: ["model"],
|
|
1602
|
-
launch: {
|
|
1603
|
-
command: "gemini",
|
|
1604
|
-
// /model inspection does not need a model override; Gemini requires session-scoped trust.
|
|
1605
|
-
args: ["--skip-trust"],
|
|
1606
|
-
timeoutMs: 7e4
|
|
1607
|
-
},
|
|
1608
|
-
extract: async (context) => {
|
|
1609
|
-
const { extractGeminiUsage } = await import("./gemini-BVRg6OMO.js");
|
|
1610
|
-
return extractGeminiUsage(context);
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
};
|
|
1614
1636
|
const BUILTIN_TARGETS = [
|
|
1615
1637
|
codexTarget,
|
|
1616
1638
|
claudeTarget,
|
|
1617
|
-
|
|
1639
|
+
agyTarget,
|
|
1618
1640
|
copilotTarget
|
|
1619
1641
|
];
|
|
1620
1642
|
Object.freeze(BUILTIN_TARGETS.map((target) => target.id));
|
|
@@ -2386,7 +2408,7 @@ const COMMON_PLACEHOLDERS = /* @__PURE__ */ new Set([
|
|
|
2386
2408
|
"itemName"
|
|
2387
2409
|
]);
|
|
2388
2410
|
const COMMAND_PLACEHOLDERS = /* @__PURE__ */ new Set([...COMMON_PLACEHOLDERS, "commandLocation"]);
|
|
2389
|
-
function isPlainObject(value) {
|
|
2411
|
+
function isPlainObject$1(value) {
|
|
2390
2412
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
2391
2413
|
}
|
|
2392
2414
|
function normalizeString(value) {
|
|
@@ -2415,7 +2437,7 @@ function validateStringArray(value, label, errors, options = {}) {
|
|
|
2415
2437
|
}
|
|
2416
2438
|
}
|
|
2417
2439
|
function validateFlagMapValues(value, label, allowedValues, errors) {
|
|
2418
|
-
if (!isPlainObject(value)) {
|
|
2440
|
+
if (!isPlainObject$1(value)) {
|
|
2419
2441
|
errors.push(`${label} must be an object.`);
|
|
2420
2442
|
return;
|
|
2421
2443
|
}
|
|
@@ -2431,7 +2453,7 @@ function validateFlagMapValues(value, label, allowedValues, errors) {
|
|
|
2431
2453
|
}
|
|
2432
2454
|
}
|
|
2433
2455
|
function validateFlagMap(value, label, allowedValues, errors) {
|
|
2434
|
-
if (!isPlainObject(value)) {
|
|
2456
|
+
if (!isPlainObject$1(value)) {
|
|
2435
2457
|
errors.push(`${label} must be an object.`);
|
|
2436
2458
|
return;
|
|
2437
2459
|
}
|
|
@@ -2439,7 +2461,7 @@ function validateFlagMap(value, label, allowedValues, errors) {
|
|
|
2439
2461
|
validateFlagMapValues(value.values, `${label}.values`, allowedValues, errors);
|
|
2440
2462
|
}
|
|
2441
2463
|
if (value.byMode !== void 0) {
|
|
2442
|
-
if (!isPlainObject(value.byMode)) {
|
|
2464
|
+
if (!isPlainObject$1(value.byMode)) {
|
|
2443
2465
|
errors.push(`${label}.byMode must be an object.`);
|
|
2444
2466
|
} else {
|
|
2445
2467
|
for (const [mode, entries] of Object.entries(value.byMode)) {
|
|
@@ -2452,8 +2474,64 @@ function validateFlagMap(value, label, allowedValues, errors) {
|
|
|
2452
2474
|
}
|
|
2453
2475
|
}
|
|
2454
2476
|
}
|
|
2477
|
+
function validateStructuredOutputSpec(value, label, errors) {
|
|
2478
|
+
if (!isPlainObject$1(value)) {
|
|
2479
|
+
errors.push(`${label} must be an object.`);
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
if (value.delivery !== "inline" && value.delivery !== "file") {
|
|
2483
|
+
errors.push(`${label}.delivery must be "inline" or "file".`);
|
|
2484
|
+
}
|
|
2485
|
+
validateStringArray(value.flag, `${label}.flag`, errors);
|
|
2486
|
+
if (value.companionArgs !== void 0) {
|
|
2487
|
+
validateStringArray(value.companionArgs, `${label}.companionArgs`, errors, {
|
|
2488
|
+
allowEmpty: true
|
|
2489
|
+
});
|
|
2490
|
+
}
|
|
2491
|
+
if (!isPlainObject$1(value.extraction)) {
|
|
2492
|
+
errors.push(`${label}.extraction must be an object.`);
|
|
2493
|
+
return;
|
|
2494
|
+
}
|
|
2495
|
+
if (value.extraction.type === "json-envelope") {
|
|
2496
|
+
if (normalizeString(value.extraction.field) === null) {
|
|
2497
|
+
errors.push(`${label}.extraction.field must be a non-empty string.`);
|
|
2498
|
+
}
|
|
2499
|
+
return;
|
|
2500
|
+
}
|
|
2501
|
+
if (value.extraction.type === "last-message-file") {
|
|
2502
|
+
validateStringArray(value.extraction.flag, `${label}.extraction.flag`, errors);
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
errors.push(`${label}.extraction.type must be "json-envelope" or "last-message-file".`);
|
|
2506
|
+
}
|
|
2507
|
+
function validateStructuredOutputFallbackSpec(value, label, errors) {
|
|
2508
|
+
if (!isPlainObject$1(value)) {
|
|
2509
|
+
errors.push(`${label} must be an object.`);
|
|
2510
|
+
return;
|
|
2511
|
+
}
|
|
2512
|
+
if (value.args !== void 0) {
|
|
2513
|
+
validateStringArray(value.args, `${label}.args`, errors, { allowEmpty: true });
|
|
2514
|
+
}
|
|
2515
|
+
if (value.extraction === void 0) {
|
|
2516
|
+
return;
|
|
2517
|
+
}
|
|
2518
|
+
if (!isPlainObject$1(value.extraction)) {
|
|
2519
|
+
errors.push(`${label}.extraction must be an object.`);
|
|
2520
|
+
return;
|
|
2521
|
+
}
|
|
2522
|
+
if (value.extraction.type === "text") {
|
|
2523
|
+
return;
|
|
2524
|
+
}
|
|
2525
|
+
if (value.extraction.type === "json-envelope") {
|
|
2526
|
+
if (normalizeString(value.extraction.field) === null) {
|
|
2527
|
+
errors.push(`${label}.extraction.field must be a non-empty string.`);
|
|
2528
|
+
}
|
|
2529
|
+
return;
|
|
2530
|
+
}
|
|
2531
|
+
errors.push(`${label}.extraction.type must be "text" or "json-envelope".`);
|
|
2532
|
+
}
|
|
2455
2533
|
function validateModeCommand(value, label, errors) {
|
|
2456
|
-
if (!isPlainObject(value)) {
|
|
2534
|
+
if (!isPlainObject$1(value)) {
|
|
2457
2535
|
errors.push(`${label} must be an object.`);
|
|
2458
2536
|
return;
|
|
2459
2537
|
}
|
|
@@ -2466,7 +2544,7 @@ function validateModeCommand(value, label, errors) {
|
|
|
2466
2544
|
}
|
|
2467
2545
|
}
|
|
2468
2546
|
function validatePromptSpec(value, label, errors) {
|
|
2469
|
-
if (!isPlainObject(value)) {
|
|
2547
|
+
if (!isPlainObject$1(value)) {
|
|
2470
2548
|
errors.push(`${label} must be an object.`);
|
|
2471
2549
|
return;
|
|
2472
2550
|
}
|
|
@@ -2486,11 +2564,11 @@ function validateCliDefinition(cli, label, errors) {
|
|
|
2486
2564
|
if (!cli) {
|
|
2487
2565
|
return;
|
|
2488
2566
|
}
|
|
2489
|
-
if (!isPlainObject(cli)) {
|
|
2567
|
+
if (!isPlainObject$1(cli)) {
|
|
2490
2568
|
errors.push(`${label} must be an object.`);
|
|
2491
2569
|
return;
|
|
2492
2570
|
}
|
|
2493
|
-
if (!isPlainObject(cli.modes)) {
|
|
2571
|
+
if (!isPlainObject$1(cli.modes)) {
|
|
2494
2572
|
errors.push(`${label}.modes is required.`);
|
|
2495
2573
|
return;
|
|
2496
2574
|
}
|
|
@@ -2500,7 +2578,7 @@ function validateCliDefinition(cli, label, errors) {
|
|
|
2500
2578
|
validatePromptSpec(cli.prompt, `${label}.prompt`, errors);
|
|
2501
2579
|
}
|
|
2502
2580
|
if (cli.flags !== void 0) {
|
|
2503
|
-
if (!isPlainObject(cli.flags)) {
|
|
2581
|
+
if (!isPlainObject$1(cli.flags)) {
|
|
2504
2582
|
errors.push(`${label}.flags must be an object.`);
|
|
2505
2583
|
} else {
|
|
2506
2584
|
if (cli.flags.approval !== void 0) {
|
|
@@ -2513,7 +2591,7 @@ function validateCliDefinition(cli, label, errors) {
|
|
|
2513
2591
|
validateFlagMap(cli.flags.output, `${label}.flags.output`, OUTPUT_FORMATS, errors);
|
|
2514
2592
|
}
|
|
2515
2593
|
if (cli.flags.model !== void 0) {
|
|
2516
|
-
if (!isPlainObject(cli.flags.model)) {
|
|
2594
|
+
if (!isPlainObject$1(cli.flags.model)) {
|
|
2517
2595
|
errors.push(`${label}.flags.model must be an object.`);
|
|
2518
2596
|
} else {
|
|
2519
2597
|
validateStringArray(cli.flags.model.flag, `${label}.flags.model.flag`, errors);
|
|
@@ -2527,8 +2605,22 @@ function validateCliDefinition(cli, label, errors) {
|
|
|
2527
2605
|
}
|
|
2528
2606
|
}
|
|
2529
2607
|
}
|
|
2608
|
+
if (cli.flags.structuredOutput !== void 0) {
|
|
2609
|
+
validateStructuredOutputSpec(
|
|
2610
|
+
cli.flags.structuredOutput,
|
|
2611
|
+
`${label}.flags.structuredOutput`,
|
|
2612
|
+
errors
|
|
2613
|
+
);
|
|
2614
|
+
}
|
|
2615
|
+
if (cli.flags.structuredOutputFallback !== void 0) {
|
|
2616
|
+
validateStructuredOutputFallbackSpec(
|
|
2617
|
+
cli.flags.structuredOutputFallback,
|
|
2618
|
+
`${label}.flags.structuredOutputFallback`,
|
|
2619
|
+
errors
|
|
2620
|
+
);
|
|
2621
|
+
}
|
|
2530
2622
|
if (cli.flags.web !== void 0) {
|
|
2531
|
-
if (!isPlainObject(cli.flags.web)) {
|
|
2623
|
+
if (!isPlainObject$1(cli.flags.web)) {
|
|
2532
2624
|
errors.push(`${label}.flags.web must be an object.`);
|
|
2533
2625
|
} else {
|
|
2534
2626
|
if (cli.flags.web.on !== void 0 && cli.flags.web.on !== null) {
|
|
@@ -2554,7 +2646,7 @@ function validateCliDefinition(cli, label, errors) {
|
|
|
2554
2646
|
}
|
|
2555
2647
|
}
|
|
2556
2648
|
if (cli.passthrough !== void 0) {
|
|
2557
|
-
if (!isPlainObject(cli.passthrough)) {
|
|
2649
|
+
if (!isPlainObject$1(cli.passthrough)) {
|
|
2558
2650
|
errors.push(`${label}.passthrough must be an object.`);
|
|
2559
2651
|
} else if (cli.passthrough.position !== void 0 && cli.passthrough.position !== "after" && cli.passthrough.position !== "before-prompt") {
|
|
2560
2652
|
errors.push(`${label}.passthrough.position must be "after" or "before-prompt".`);
|
|
@@ -2568,13 +2660,13 @@ function validateUsageDefinition(usage, label, errors) {
|
|
|
2568
2660
|
if (usage === void 0) {
|
|
2569
2661
|
return;
|
|
2570
2662
|
}
|
|
2571
|
-
if (!isPlainObject(usage)) {
|
|
2663
|
+
if (!isPlainObject$1(usage)) {
|
|
2572
2664
|
errors.push(`${label} must be an object.`);
|
|
2573
2665
|
return;
|
|
2574
2666
|
}
|
|
2575
2667
|
validateStringArray(usage.windows, `${label}.windows`, errors);
|
|
2576
2668
|
if (usage.launch !== void 0) {
|
|
2577
|
-
if (!isPlainObject(usage.launch)) {
|
|
2669
|
+
if (!isPlainObject$1(usage.launch)) {
|
|
2578
2670
|
errors.push(`${label}.launch must be an object.`);
|
|
2579
2671
|
} else {
|
|
2580
2672
|
if (usage.launch.command !== void 0 && normalizeString(usage.launch.command) === null) {
|
|
@@ -2632,7 +2724,7 @@ function validateOutputDefinition(output, label, errors) {
|
|
|
2632
2724
|
validateTemplate(output, label, COMMON_PLACEHOLDERS, errors);
|
|
2633
2725
|
return;
|
|
2634
2726
|
}
|
|
2635
|
-
if (!isPlainObject(output)) {
|
|
2727
|
+
if (!isPlainObject$1(output)) {
|
|
2636
2728
|
errors.push(`${label} must be a string or an object.`);
|
|
2637
2729
|
return;
|
|
2638
2730
|
}
|
|
@@ -2647,7 +2739,7 @@ function validateCommandOutputDefinition(output, label, errors) {
|
|
|
2647
2739
|
validateTemplate(output, label, COMMAND_PLACEHOLDERS, errors);
|
|
2648
2740
|
return;
|
|
2649
2741
|
}
|
|
2650
|
-
if (!isPlainObject(output)) {
|
|
2742
|
+
if (!isPlainObject$1(output)) {
|
|
2651
2743
|
errors.push(`${label} must be a string or an object.`);
|
|
2652
2744
|
return;
|
|
2653
2745
|
}
|
|
@@ -2671,7 +2763,7 @@ function validateInstructionOutputDefinition(output, label, errors) {
|
|
|
2671
2763
|
validateTemplate(output, label, COMMON_PLACEHOLDERS, errors);
|
|
2672
2764
|
return;
|
|
2673
2765
|
}
|
|
2674
|
-
if (!isPlainObject(output)) {
|
|
2766
|
+
if (!isPlainObject$1(output)) {
|
|
2675
2767
|
errors.push(`${label} must be a string or an object.`);
|
|
2676
2768
|
return;
|
|
2677
2769
|
}
|
|
@@ -2684,7 +2776,7 @@ function validateOutputs(outputs, label, errors) {
|
|
|
2684
2776
|
if (!outputs) {
|
|
2685
2777
|
return;
|
|
2686
2778
|
}
|
|
2687
|
-
if (!isPlainObject(outputs)) {
|
|
2779
|
+
if (!isPlainObject$1(outputs)) {
|
|
2688
2780
|
errors.push(`${label} must be an object.`);
|
|
2689
2781
|
return;
|
|
2690
2782
|
}
|
|
@@ -2702,7 +2794,7 @@ function validateTargetConfig(options) {
|
|
|
2702
2794
|
if (config === null) {
|
|
2703
2795
|
return { valid: true, errors, config: null };
|
|
2704
2796
|
}
|
|
2705
|
-
if (!isPlainObject(config)) {
|
|
2797
|
+
if (!isPlainObject$1(config)) {
|
|
2706
2798
|
return {
|
|
2707
2799
|
valid: false,
|
|
2708
2800
|
errors: ["Config must export an object."],
|
|
@@ -2717,9 +2809,11 @@ function validateTargetConfig(options) {
|
|
|
2717
2809
|
}
|
|
2718
2810
|
const builtInIds = new Set(options.builtIns.map((target) => normalizeLower(target.id)));
|
|
2719
2811
|
const builtInAliasSet = /* @__PURE__ */ new Set();
|
|
2812
|
+
const builtInAliasToId = /* @__PURE__ */ new Map();
|
|
2720
2813
|
for (const target of options.builtIns) {
|
|
2721
2814
|
for (const alias of target.aliases ?? []) {
|
|
2722
2815
|
builtInAliasSet.add(normalizeLower(alias));
|
|
2816
|
+
builtInAliasToId.set(normalizeLower(alias), normalizeLower(target.id));
|
|
2723
2817
|
}
|
|
2724
2818
|
}
|
|
2725
2819
|
const seenIds = /* @__PURE__ */ new Set();
|
|
@@ -2736,7 +2830,8 @@ function validateTargetConfig(options) {
|
|
|
2736
2830
|
errors.push("disableTargets entries must be non-empty strings.");
|
|
2737
2831
|
continue;
|
|
2738
2832
|
}
|
|
2739
|
-
const
|
|
2833
|
+
const rawKey = normalizeLower(normalized);
|
|
2834
|
+
const key = builtInAliasToId.get(rawKey) ?? rawKey;
|
|
2740
2835
|
if (!builtInIds.has(key)) {
|
|
2741
2836
|
errors.push(`disableTargets includes unknown built-in: ${normalized}.`);
|
|
2742
2837
|
continue;
|
|
@@ -2755,7 +2850,7 @@ function validateTargetConfig(options) {
|
|
|
2755
2850
|
} else {
|
|
2756
2851
|
for (const [index, entry2] of config.targets.entries()) {
|
|
2757
2852
|
const label = `targets[${index}]`;
|
|
2758
|
-
if (!isPlainObject(entry2)) {
|
|
2853
|
+
if (!isPlainObject$1(entry2)) {
|
|
2759
2854
|
errors.push(`${label} must be an object.`);
|
|
2760
2855
|
continue;
|
|
2761
2856
|
}
|
|
@@ -2770,6 +2865,14 @@ function validateTargetConfig(options) {
|
|
|
2770
2865
|
} else {
|
|
2771
2866
|
seenIds.add(idKey);
|
|
2772
2867
|
}
|
|
2868
|
+
const aliasOwner = builtInAliasToId.get(idKey);
|
|
2869
|
+
if (aliasOwner) {
|
|
2870
|
+
errors.push(
|
|
2871
|
+
`${label}.id collides with built-in alias (${id}) of target ${aliasOwner}. Pick a distinct id.`
|
|
2872
|
+
);
|
|
2873
|
+
} else if (seenAliases.has(idKey)) {
|
|
2874
|
+
errors.push(`${label}.id collides with existing alias (${id}).`);
|
|
2875
|
+
}
|
|
2773
2876
|
if (entry2.displayName !== void 0 && normalizeString(entry2.displayName) === null) {
|
|
2774
2877
|
errors.push(`${label}.displayName must be a non-empty string when provided.`);
|
|
2775
2878
|
}
|
|
@@ -2779,7 +2882,8 @@ function validateTargetConfig(options) {
|
|
|
2779
2882
|
}
|
|
2780
2883
|
if (inherits) {
|
|
2781
2884
|
const inheritKey = normalizeLower(inherits);
|
|
2782
|
-
|
|
2885
|
+
const canonicalInherit = builtInAliasToId.get(inheritKey) ?? inheritKey;
|
|
2886
|
+
if (!builtInIds.has(canonicalInherit)) {
|
|
2783
2887
|
errors.push(`${label}.inherits references unknown built-in: ${inherits}.`);
|
|
2784
2888
|
}
|
|
2785
2889
|
}
|
|
@@ -2818,7 +2922,8 @@ function validateTargetConfig(options) {
|
|
|
2818
2922
|
errors.push(`${label}.aliases collides with existing target id (${aliasValue}).`);
|
|
2819
2923
|
continue;
|
|
2820
2924
|
}
|
|
2821
|
-
|
|
2925
|
+
const collidesWithOtherBuiltInAlias = builtInAliasSet.has(aliasKey) && builtInAliasToId.get(aliasKey) !== idKey;
|
|
2926
|
+
if (seenAliases.has(aliasKey) || collidesWithOtherBuiltInAlias) {
|
|
2822
2927
|
errors.push(`${label}.aliases collides with existing alias (${aliasValue}).`);
|
|
2823
2928
|
continue;
|
|
2824
2929
|
}
|
|
@@ -2835,7 +2940,8 @@ function validateTargetConfig(options) {
|
|
|
2835
2940
|
}
|
|
2836
2941
|
if (config.disableTargets && Array.isArray(config.disableTargets)) {
|
|
2837
2942
|
for (const targetId of config.disableTargets) {
|
|
2838
|
-
const
|
|
2943
|
+
const rawKey = normalizeLower(targetId);
|
|
2944
|
+
const normalized = builtInAliasToId.get(rawKey) ?? rawKey;
|
|
2839
2945
|
if (customBuiltInIds.has(normalized)) {
|
|
2840
2946
|
errors.push(`disableTargets cannot include overridden/inherited target (${targetId}).`);
|
|
2841
2947
|
}
|
|
@@ -2890,7 +2996,7 @@ function mergeOutputs(base, override) {
|
|
|
2890
2996
|
}
|
|
2891
2997
|
function resolveInheritTarget(builtIns, inherits) {
|
|
2892
2998
|
const key = normalizeKey$2(inherits);
|
|
2893
|
-
const found = builtIns.find((target) => normalizeKey$2(target.id) === key);
|
|
2999
|
+
const found = builtIns.find((target) => normalizeKey$2(target.id) === key) ?? builtIns.find((target) => (target.aliases ?? []).some((alias) => normalizeKey$2(alias) === key));
|
|
2894
3000
|
return found ?? null;
|
|
2895
3001
|
}
|
|
2896
3002
|
function resolveTargets(options) {
|
|
@@ -2899,12 +3005,18 @@ function resolveTargets(options) {
|
|
|
2899
3005
|
for (const target of builtIns) {
|
|
2900
3006
|
builtInMap.set(normalizeKey$2(target.id), target);
|
|
2901
3007
|
}
|
|
3008
|
+
const builtInAliasToId = /* @__PURE__ */ new Map();
|
|
3009
|
+
for (const target of builtIns) {
|
|
3010
|
+
for (const alias of target.aliases ?? []) {
|
|
3011
|
+
builtInAliasToId.set(normalizeKey$2(alias), normalizeKey$2(target.id));
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
2902
3014
|
const disabledTargets = [];
|
|
2903
3015
|
const disableSet = /* @__PURE__ */ new Set();
|
|
2904
3016
|
if (options.config?.disableTargets) {
|
|
2905
3017
|
for (const entry2 of options.config.disableTargets) {
|
|
2906
|
-
const
|
|
2907
|
-
disableSet.add(
|
|
3018
|
+
const rawKey = normalizeKey$2(entry2);
|
|
3019
|
+
disableSet.add(builtInAliasToId.get(rawKey) ?? rawKey);
|
|
2908
3020
|
disabledTargets.push(entry2);
|
|
2909
3021
|
}
|
|
2910
3022
|
}
|
|
@@ -2938,7 +3050,9 @@ function resolveTargets(options) {
|
|
|
2938
3050
|
resolvedTargets.push({
|
|
2939
3051
|
id: customTarget.id,
|
|
2940
3052
|
displayName: customTarget.displayName ?? inherited?.displayName ?? customTarget.id,
|
|
2941
|
-
|
|
3053
|
+
// Aliases follow the overridden built-in's identity, not the inherited
|
|
3054
|
+
// definition — inheriting them would move the alias between targets.
|
|
3055
|
+
aliases: customTarget.aliases ?? builtIn.aliases ?? [],
|
|
2942
3056
|
outputs: mergedOutputs,
|
|
2943
3057
|
cli: cloneCli(customTarget.cli ?? inherited?.cli),
|
|
2944
3058
|
usage: cloneUsage(customTarget.usage ?? inherited?.usage),
|
|
@@ -2951,7 +3065,7 @@ function resolveTargets(options) {
|
|
|
2951
3065
|
resolvedTargets.push({
|
|
2952
3066
|
id: customTarget.id,
|
|
2953
3067
|
displayName: customTarget.displayName ?? customTarget.id,
|
|
2954
|
-
aliases: customTarget.aliases ?? [],
|
|
3068
|
+
aliases: customTarget.aliases ?? builtIn.aliases ?? [],
|
|
2955
3069
|
outputs: cloneOutputs(customTarget.outputs),
|
|
2956
3070
|
cli: cloneCli(customTarget.cli),
|
|
2957
3071
|
usage: cloneUsage(customTarget.usage),
|
|
@@ -2972,7 +3086,9 @@ function resolveTargets(options) {
|
|
|
2972
3086
|
resolvedTargets.push({
|
|
2973
3087
|
id: target.id,
|
|
2974
3088
|
displayName: target.displayName ?? inherited?.displayName ?? target.id,
|
|
2975
|
-
|
|
3089
|
+
// Aliases name a specific target, so a new custom target never inherits
|
|
3090
|
+
// them — otherwise it would shadow the built-in's alias in aliasToId.
|
|
3091
|
+
aliases: target.aliases ?? [],
|
|
2976
3092
|
outputs: mergedOutputs,
|
|
2977
3093
|
cli: cloneCli(target.cli ?? inherited?.cli),
|
|
2978
3094
|
usage: cloneUsage(target.usage ?? inherited?.usage),
|
|
@@ -3144,7 +3260,7 @@ Profile files must be valid JSON. This commented version is just a guide:
|
|
|
3144
3260
|
|
|
3145
3261
|
"targets": {
|
|
3146
3262
|
"claude": { "enabled": true }, // includes Claude; overrides an earlier profile setting it false
|
|
3147
|
-
"
|
|
3263
|
+
"agy": { "enabled": false } // skips Antigravity for this profile
|
|
3148
3264
|
},
|
|
3149
3265
|
|
|
3150
3266
|
"enable": { // names/globs to include; also opts in items marked enabled:false
|
|
@@ -3578,6 +3694,18 @@ function processTemplating(content, options) {
|
|
|
3578
3694
|
const validSet = new Set(normalizedValid);
|
|
3579
3695
|
const context = { sourcePath: options.sourcePath, validAgents: normalizedValid };
|
|
3580
3696
|
const target = options.target ? options.target.toLowerCase() : null;
|
|
3697
|
+
const targetKeys = target ? /* @__PURE__ */ new Set([target, ...(options.targetAliases ?? []).map((alias) => alias.toLowerCase())]) : null;
|
|
3698
|
+
const intersects = (set) => {
|
|
3699
|
+
if (!targetKeys) {
|
|
3700
|
+
return false;
|
|
3701
|
+
}
|
|
3702
|
+
for (const key of targetKeys) {
|
|
3703
|
+
if (set.has(key)) {
|
|
3704
|
+
return true;
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3707
|
+
return false;
|
|
3708
|
+
};
|
|
3581
3709
|
let output = "";
|
|
3582
3710
|
let index = 0;
|
|
3583
3711
|
while (index < content.length) {
|
|
@@ -3608,7 +3736,7 @@ function processTemplating(content, options) {
|
|
|
3608
3736
|
);
|
|
3609
3737
|
}
|
|
3610
3738
|
const { include, exclude } = parseSelectorList(selectorRaw, validSet, context);
|
|
3611
|
-
const shouldInclude = target === null ? false : include.size > 0 ? include
|
|
3739
|
+
const shouldInclude = target === null ? false : include.size > 0 ? intersects(include) && !intersects(exclude) : !intersects(exclude);
|
|
3612
3740
|
let cursor = contentStart;
|
|
3613
3741
|
let blockOutput = "";
|
|
3614
3742
|
while (cursor < content.length) {
|
|
@@ -3658,6 +3786,7 @@ function validateAgentTemplating(options) {
|
|
|
3658
3786
|
function applyAgentTemplating(options) {
|
|
3659
3787
|
return processTemplating(options.content, {
|
|
3660
3788
|
target: options.target,
|
|
3789
|
+
targetAliases: options.targetAliases,
|
|
3661
3790
|
validAgents: options.validAgents,
|
|
3662
3791
|
sourcePath: options.sourcePath
|
|
3663
3792
|
});
|
|
@@ -4030,6 +4159,7 @@ const DEFAULT_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
4030
4159
|
".git",
|
|
4031
4160
|
"node_modules",
|
|
4032
4161
|
"dist",
|
|
4162
|
+
".agents",
|
|
4033
4163
|
".claude",
|
|
4034
4164
|
".codex",
|
|
4035
4165
|
".gemini",
|
|
@@ -5167,6 +5297,7 @@ async function copySkillDirectory(options) {
|
|
|
5167
5297
|
const templated = applyAgentTemplating({
|
|
5168
5298
|
content: withScripts,
|
|
5169
5299
|
target: options.targetId,
|
|
5300
|
+
targetAliases: options.targetAliases,
|
|
5170
5301
|
validAgents: options.validAgents,
|
|
5171
5302
|
sourcePath: winner.sourcePath
|
|
5172
5303
|
});
|
|
@@ -5186,6 +5317,7 @@ const defaultSkillWriter = {
|
|
|
5186
5317
|
source: item.directoryPath,
|
|
5187
5318
|
destination: options.outputPath,
|
|
5188
5319
|
targetId: options.context.targetId,
|
|
5320
|
+
targetAliases: options.context.targetAliases,
|
|
5189
5321
|
validAgents: options.context.validAgents,
|
|
5190
5322
|
skillFileName: item.skillFileName,
|
|
5191
5323
|
outputFileName: item.outputFileName,
|
|
@@ -5211,6 +5343,7 @@ const defaultSubagentWriter = {
|
|
|
5211
5343
|
const templated = applyAgentTemplating({
|
|
5212
5344
|
content: withScripts,
|
|
5213
5345
|
target: options.context.targetId,
|
|
5346
|
+
targetAliases: options.context.targetAliases,
|
|
5214
5347
|
validAgents: options.context.validAgents,
|
|
5215
5348
|
sourcePath: item.sourcePath
|
|
5216
5349
|
});
|
|
@@ -5552,6 +5685,7 @@ async function syncInstructions(request) {
|
|
|
5552
5685
|
const content = applyAgentTemplating({
|
|
5553
5686
|
content: withScripts,
|
|
5554
5687
|
target: targetName,
|
|
5688
|
+
targetAliases: selection.target.aliases,
|
|
5555
5689
|
validAgents: request.validAgents,
|
|
5556
5690
|
sourcePath: template.sourcePath
|
|
5557
5691
|
});
|
|
@@ -5753,6 +5887,7 @@ async function syncInstructions(request) {
|
|
|
5753
5887
|
agentsDir: agentsRoot,
|
|
5754
5888
|
homeDir,
|
|
5755
5889
|
targetId: candidate.targetName,
|
|
5890
|
+
targetAliases: selectionById.get(candidate.targetName)?.target.aliases,
|
|
5756
5891
|
outputType: "instructions",
|
|
5757
5892
|
validAgents: request.validAgents
|
|
5758
5893
|
});
|
|
@@ -5805,6 +5940,7 @@ async function syncInstructions(request) {
|
|
|
5805
5940
|
agentsDir: agentsRoot,
|
|
5806
5941
|
homeDir,
|
|
5807
5942
|
targetId: candidate.targetName,
|
|
5943
|
+
targetAliases: selectionById.get(candidate.targetName)?.target.aliases,
|
|
5808
5944
|
outputType: "instructions",
|
|
5809
5945
|
validAgents: request.validAgents,
|
|
5810
5946
|
templateScriptRuntime
|
|
@@ -6301,6 +6437,7 @@ async function syncSkills(request) {
|
|
|
6301
6437
|
agentsDir: agentsDirPath,
|
|
6302
6438
|
homeDir,
|
|
6303
6439
|
targetId: target.id,
|
|
6440
|
+
targetAliases: target.aliases,
|
|
6304
6441
|
outputType: "skills",
|
|
6305
6442
|
validAgents: request.validAgents
|
|
6306
6443
|
});
|
|
@@ -6361,6 +6498,7 @@ async function syncSkills(request) {
|
|
|
6361
6498
|
agentsDir: agentsDirPath,
|
|
6362
6499
|
homeDir,
|
|
6363
6500
|
targetId: target.id,
|
|
6501
|
+
targetAliases: target.aliases,
|
|
6364
6502
|
outputType: "skills",
|
|
6365
6503
|
validAgents: request.validAgents,
|
|
6366
6504
|
templateScriptRuntime
|
|
@@ -6698,7 +6836,7 @@ function buildInvalidTargetWarnings$1(commands) {
|
|
|
6698
6836
|
}
|
|
6699
6837
|
return warnings;
|
|
6700
6838
|
}
|
|
6701
|
-
async function applyTemplatingToCommand(command, targetName, validAgents, runtime) {
|
|
6839
|
+
async function applyTemplatingToCommand(command, targetName, validAgents, runtime, targetAliases) {
|
|
6702
6840
|
const withScripts = runtime ? await evaluateTemplateScripts({
|
|
6703
6841
|
templatePath: command.sourcePath,
|
|
6704
6842
|
content: command.rawContents,
|
|
@@ -6707,6 +6845,7 @@ async function applyTemplatingToCommand(command, targetName, validAgents, runtim
|
|
|
6707
6845
|
const templatedContents = applyAgentTemplating({
|
|
6708
6846
|
content: withScripts,
|
|
6709
6847
|
target: targetName,
|
|
6848
|
+
targetAliases,
|
|
6710
6849
|
validAgents,
|
|
6711
6850
|
sourcePath: command.sourcePath
|
|
6712
6851
|
});
|
|
@@ -6974,7 +7113,8 @@ async function syncSlashCommands(request) {
|
|
|
6974
7113
|
command,
|
|
6975
7114
|
target.id,
|
|
6976
7115
|
validAgents,
|
|
6977
|
-
templateScriptRuntime
|
|
7116
|
+
templateScriptRuntime,
|
|
7117
|
+
target.aliases
|
|
6978
7118
|
);
|
|
6979
7119
|
const writer = resolveWriter(commandDef.writer, writerRegistry);
|
|
6980
7120
|
const converter = resolveConverter(commandDef.converter, converterRegistry);
|
|
@@ -7050,6 +7190,7 @@ async function syncSlashCommands(request) {
|
|
|
7050
7190
|
agentsDir: agentsDirPath,
|
|
7051
7191
|
homeDir,
|
|
7052
7192
|
targetId: target.id,
|
|
7193
|
+
targetAliases: target.aliases,
|
|
7053
7194
|
outputType: "commands",
|
|
7054
7195
|
commandLocation: selected.location,
|
|
7055
7196
|
validAgents
|
|
@@ -7111,6 +7252,7 @@ async function syncSlashCommands(request) {
|
|
|
7111
7252
|
agentsDir: agentsDirPath,
|
|
7112
7253
|
homeDir,
|
|
7113
7254
|
targetId: target.id,
|
|
7255
|
+
targetAliases: target.aliases,
|
|
7114
7256
|
outputType: "commands",
|
|
7115
7257
|
commandLocation: selected.location,
|
|
7116
7258
|
validAgents,
|
|
@@ -8027,6 +8169,7 @@ async function syncSubagents(request) {
|
|
|
8027
8169
|
agentsDir: agentsDirPath,
|
|
8028
8170
|
homeDir,
|
|
8029
8171
|
targetId: target.id,
|
|
8172
|
+
targetAliases: target.aliases,
|
|
8030
8173
|
outputType: "subagents",
|
|
8031
8174
|
validAgents
|
|
8032
8175
|
});
|
|
@@ -8087,6 +8230,7 @@ async function syncSubagents(request) {
|
|
|
8087
8230
|
agentsDir: agentsDirPath,
|
|
8088
8231
|
homeDir,
|
|
8089
8232
|
targetId: target.id,
|
|
8233
|
+
targetAliases: target.aliases,
|
|
8090
8234
|
outputType: "subagents",
|
|
8091
8235
|
validAgents,
|
|
8092
8236
|
templateScriptRuntime
|
|
@@ -8474,7 +8618,9 @@ async function checkTargetAvailability(target) {
|
|
|
8474
8618
|
checks
|
|
8475
8619
|
};
|
|
8476
8620
|
}
|
|
8477
|
-
const DEFAULT_SUPPORTED_TARGETS = BUILTIN_TARGETS.map(
|
|
8621
|
+
const DEFAULT_SUPPORTED_TARGETS = BUILTIN_TARGETS.map(
|
|
8622
|
+
(target) => target.aliases?.length ? `${target.id} (alias: ${target.aliases.join(", ")})` : target.id
|
|
8623
|
+
).join(", ");
|
|
8478
8624
|
const LOCAL_CATEGORIES = ["skills", "commands", "agents", "instructions"];
|
|
8479
8625
|
const LOCAL_CATEGORY_SET = new Set(LOCAL_CATEGORIES);
|
|
8480
8626
|
const utf8Decoder = new TextDecoder("utf-8", { fatal: true });
|
|
@@ -10377,6 +10523,7 @@ function makeUsageLimit(options) {
|
|
|
10377
10523
|
modelLabel: options.modelLabel,
|
|
10378
10524
|
percentUsed: options.percentUsed,
|
|
10379
10525
|
percentRemaining: options.percentRemaining,
|
|
10526
|
+
remainingText: emptyToNull(options.remainingText) ?? void 0,
|
|
10380
10527
|
resetAt: parseResetAt(resetText, {
|
|
10381
10528
|
now: options.now,
|
|
10382
10529
|
sourceTimeZone: options.resetSourceTimeZone ?? "local"
|
|
@@ -10554,6 +10701,13 @@ function emptyToNull(value) {
|
|
|
10554
10701
|
function escapeRegExp(value) {
|
|
10555
10702
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10556
10703
|
}
|
|
10704
|
+
class UsageExtractionError extends Error {
|
|
10705
|
+
constructor(code, message) {
|
|
10706
|
+
super(message);
|
|
10707
|
+
this.code = code;
|
|
10708
|
+
this.name = "UsageExtractionError";
|
|
10709
|
+
}
|
|
10710
|
+
}
|
|
10557
10711
|
const USAGE_BAR_WIDTH = 12;
|
|
10558
10712
|
const ANSI = {
|
|
10559
10713
|
reset: "\x1B[0m",
|
|
@@ -10588,6 +10742,12 @@ class UsageExtractionTimeoutError extends Error {
|
|
|
10588
10742
|
this.timeoutMs = timeoutMs;
|
|
10589
10743
|
}
|
|
10590
10744
|
}
|
|
10745
|
+
class UsageCommandInterruptedError extends Error {
|
|
10746
|
+
constructor() {
|
|
10747
|
+
super("Usage cancelled.");
|
|
10748
|
+
this.name = "UsageCommandInterruptedError";
|
|
10749
|
+
}
|
|
10750
|
+
}
|
|
10591
10751
|
function normalizeOptionalWindow(value) {
|
|
10592
10752
|
if (value == null) {
|
|
10593
10753
|
return null;
|
|
@@ -10658,6 +10818,68 @@ function uniqueNormalizedWindows(values) {
|
|
|
10658
10818
|
}
|
|
10659
10819
|
return result;
|
|
10660
10820
|
}
|
|
10821
|
+
class UsageConfirmationPrompter {
|
|
10822
|
+
rl = null;
|
|
10823
|
+
queue = Promise.resolve();
|
|
10824
|
+
closed = false;
|
|
10825
|
+
interrupt;
|
|
10826
|
+
constructor(interrupt) {
|
|
10827
|
+
this.interrupt = interrupt;
|
|
10828
|
+
}
|
|
10829
|
+
confirm = (request, signal) => {
|
|
10830
|
+
const confirmation = this.queue.then(() => this.ask(request, signal));
|
|
10831
|
+
this.queue = confirmation.then(
|
|
10832
|
+
() => void 0,
|
|
10833
|
+
() => void 0
|
|
10834
|
+
);
|
|
10835
|
+
return confirmation;
|
|
10836
|
+
};
|
|
10837
|
+
close() {
|
|
10838
|
+
this.closed = true;
|
|
10839
|
+
this.rl?.close();
|
|
10840
|
+
this.rl = null;
|
|
10841
|
+
}
|
|
10842
|
+
async ask(request, signal) {
|
|
10843
|
+
if (this.closed) {
|
|
10844
|
+
throw new Error("Usage confirmation is no longer available.");
|
|
10845
|
+
}
|
|
10846
|
+
if (signal.aborted) {
|
|
10847
|
+
throw signal.reason instanceof Error ? signal.reason : new Error("Usage confirmation was cancelled.");
|
|
10848
|
+
}
|
|
10849
|
+
const scope = request.managed ? "managed usage directory" : "project directory";
|
|
10850
|
+
const question = `${request.displayName} needs to trust this ${scope}:
|
|
10851
|
+
${request.path}
|
|
10852
|
+
|
|
10853
|
+
Allow this? [y/N] `;
|
|
10854
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
10855
|
+
this.rl = rl;
|
|
10856
|
+
const handleInterrupt = () => this.interrupt();
|
|
10857
|
+
rl.once("SIGINT", handleInterrupt);
|
|
10858
|
+
try {
|
|
10859
|
+
while (true) {
|
|
10860
|
+
const answer = (await rl.question(question, { signal })).trim().toLowerCase();
|
|
10861
|
+
if (!answer || answer === "n" || answer === "no") {
|
|
10862
|
+
return false;
|
|
10863
|
+
}
|
|
10864
|
+
if (answer === "y" || answer === "yes") {
|
|
10865
|
+
return true;
|
|
10866
|
+
}
|
|
10867
|
+
console.error("Please enter yes or no.");
|
|
10868
|
+
}
|
|
10869
|
+
} catch (error) {
|
|
10870
|
+
if (signal.aborted && signal.reason instanceof Error) {
|
|
10871
|
+
throw signal.reason;
|
|
10872
|
+
}
|
|
10873
|
+
throw error;
|
|
10874
|
+
} finally {
|
|
10875
|
+
rl.removeListener("SIGINT", handleInterrupt);
|
|
10876
|
+
rl.close();
|
|
10877
|
+
if (this.rl === rl) {
|
|
10878
|
+
this.rl = null;
|
|
10879
|
+
}
|
|
10880
|
+
}
|
|
10881
|
+
}
|
|
10882
|
+
}
|
|
10661
10883
|
function formatUsageTargetLabel(targets) {
|
|
10662
10884
|
return buildSupportedTargetLabel(targets);
|
|
10663
10885
|
}
|
|
@@ -10668,6 +10890,13 @@ function formatSupportedUsageTargetsMessage(targets) {
|
|
|
10668
10890
|
function getUsageCommand(target) {
|
|
10669
10891
|
return target.usage?.launch?.command;
|
|
10670
10892
|
}
|
|
10893
|
+
function supportsUsageConfirmation(target) {
|
|
10894
|
+
if (target.id.trim().toLowerCase() === "agy") {
|
|
10895
|
+
return true;
|
|
10896
|
+
}
|
|
10897
|
+
const builtInAgyExtractor = BUILTIN_TARGETS.find((candidate) => candidate.id === "agy")?.usage?.extract;
|
|
10898
|
+
return builtInAgyExtractor != null && target.usage?.extract === builtInAgyExtractor;
|
|
10899
|
+
}
|
|
10671
10900
|
async function checkUsageCommandAvailability(target) {
|
|
10672
10901
|
const command = getUsageCommand(target)?.trim();
|
|
10673
10902
|
if (!command) {
|
|
@@ -10725,6 +10954,7 @@ function validateCodexCommand(candidate) {
|
|
|
10725
10954
|
}
|
|
10726
10955
|
function buildContext(options) {
|
|
10727
10956
|
const windows = uniqueNormalizedWindows(options.target.usage?.windows ?? []);
|
|
10957
|
+
const confirm = options.confirm;
|
|
10728
10958
|
const launch = {
|
|
10729
10959
|
...options.target.usage?.launch ?? {},
|
|
10730
10960
|
timeoutMs: options.timeoutMs
|
|
@@ -10741,6 +10971,7 @@ function buildContext(options) {
|
|
|
10741
10971
|
homeDir: options.homeDir,
|
|
10742
10972
|
launch,
|
|
10743
10973
|
signal: options.signal,
|
|
10974
|
+
confirm: confirm == null ? void 0 : (request) => confirm(request, options.signal),
|
|
10744
10975
|
debug: {
|
|
10745
10976
|
enabled: options.debug,
|
|
10746
10977
|
includeRawOutput: options.debug,
|
|
@@ -10754,7 +10985,11 @@ function filterTargetResult(target, result, selectedWindow) {
|
|
|
10754
10985
|
window: normalizeUsageWindow(limit.window)
|
|
10755
10986
|
}));
|
|
10756
10987
|
const filteredLimits = selectedWindow == null ? normalizedLimits : normalizedLimits.filter((limit) => limit.window === selectedWindow);
|
|
10757
|
-
const
|
|
10988
|
+
const resultNotes = result.notes ?? [];
|
|
10989
|
+
const notes = selectedWindow != null && filteredLimits.length === 0 ? [
|
|
10990
|
+
...resultNotes,
|
|
10991
|
+
`${target.displayName} reported no usage rows for window "${selectedWindow}".`
|
|
10992
|
+
] : resultNotes;
|
|
10758
10993
|
return {
|
|
10759
10994
|
result: {
|
|
10760
10995
|
targetId: result.targetId,
|
|
@@ -10789,10 +11024,14 @@ async function extractUsageForTarget(options) {
|
|
|
10789
11024
|
debug: []
|
|
10790
11025
|
};
|
|
10791
11026
|
}
|
|
10792
|
-
const result = await withUsageTimeout(
|
|
10793
|
-
|
|
10794
|
-
|
|
10795
|
-
|
|
11027
|
+
const result = await withUsageTimeout(
|
|
11028
|
+
(signal) => {
|
|
11029
|
+
const context = buildContext({ ...options, signal });
|
|
11030
|
+
return extractor(context);
|
|
11031
|
+
},
|
|
11032
|
+
options.timeoutMs,
|
|
11033
|
+
options.commandSignal
|
|
11034
|
+
);
|
|
10796
11035
|
const filtered = filterTargetResult(options.target, result, options.selectedWindow);
|
|
10797
11036
|
return {
|
|
10798
11037
|
status: "success",
|
|
@@ -10804,7 +11043,7 @@ async function extractUsageForTarget(options) {
|
|
|
10804
11043
|
};
|
|
10805
11044
|
} catch (error) {
|
|
10806
11045
|
const message = error instanceof Error ? error.message : String(error);
|
|
10807
|
-
const code = isUsageTimeoutError(error) ? "usage_extraction_timeout" :
|
|
11046
|
+
const code = isUsageTimeoutError(error) ? "usage_extraction_timeout" : getUsageExtractionErrorCode(error);
|
|
10808
11047
|
return {
|
|
10809
11048
|
status: "error",
|
|
10810
11049
|
target: options.target,
|
|
@@ -10813,6 +11052,21 @@ async function extractUsageForTarget(options) {
|
|
|
10813
11052
|
};
|
|
10814
11053
|
}
|
|
10815
11054
|
}
|
|
11055
|
+
function getUsageExtractionErrorCode(error) {
|
|
11056
|
+
if (error instanceof UsageExtractionError) {
|
|
11057
|
+
return error.code;
|
|
11058
|
+
}
|
|
11059
|
+
if (error && typeof error === "object") {
|
|
11060
|
+
const code = error.code;
|
|
11061
|
+
if (typeof code === "string") {
|
|
11062
|
+
const normalized = code.trim();
|
|
11063
|
+
if (/^[a-z][a-z0-9_]*$/.test(normalized)) {
|
|
11064
|
+
return normalized;
|
|
11065
|
+
}
|
|
11066
|
+
}
|
|
11067
|
+
}
|
|
11068
|
+
return "usage_extraction_failed";
|
|
11069
|
+
}
|
|
10816
11070
|
function isUsageTimeoutError(error) {
|
|
10817
11071
|
if (error instanceof UsageExtractionTimeoutError) {
|
|
10818
11072
|
return true;
|
|
@@ -10836,18 +11090,25 @@ function isDebugArtifact(value) {
|
|
|
10836
11090
|
const artifact = value;
|
|
10837
11091
|
return (artifact.type === "raw-output" || artifact.type === "screen-snapshot") && typeof artifact.label === "string";
|
|
10838
11092
|
}
|
|
10839
|
-
function withUsageTimeout(run, timeoutMs) {
|
|
11093
|
+
function withUsageTimeout(run, timeoutMs, commandSignal) {
|
|
10840
11094
|
return new Promise((resolve, reject) => {
|
|
10841
11095
|
const controller = new AbortController();
|
|
10842
11096
|
let settled = false;
|
|
10843
11097
|
let timeoutFired = false;
|
|
10844
|
-
let timeout;
|
|
11098
|
+
let timeout = null;
|
|
11099
|
+
let removeCommandAbortListener = null;
|
|
11100
|
+
const cleanup = () => {
|
|
11101
|
+
if (timeout != null) {
|
|
11102
|
+
clearTimeout(timeout);
|
|
11103
|
+
}
|
|
11104
|
+
removeCommandAbortListener?.();
|
|
11105
|
+
};
|
|
10845
11106
|
const settleResolve = (value) => {
|
|
10846
11107
|
if (settled) {
|
|
10847
11108
|
return;
|
|
10848
11109
|
}
|
|
10849
11110
|
settled = true;
|
|
10850
|
-
|
|
11111
|
+
cleanup();
|
|
10851
11112
|
resolve(value);
|
|
10852
11113
|
};
|
|
10853
11114
|
const settleReject = (error) => {
|
|
@@ -10855,7 +11116,7 @@ function withUsageTimeout(run, timeoutMs) {
|
|
|
10855
11116
|
return;
|
|
10856
11117
|
}
|
|
10857
11118
|
settled = true;
|
|
10858
|
-
|
|
11119
|
+
cleanup();
|
|
10859
11120
|
reject(error);
|
|
10860
11121
|
};
|
|
10861
11122
|
timeout = setTimeout(() => {
|
|
@@ -10866,6 +11127,19 @@ function withUsageTimeout(run, timeoutMs) {
|
|
|
10866
11127
|
settleReject(error);
|
|
10867
11128
|
});
|
|
10868
11129
|
}, timeoutMs);
|
|
11130
|
+
if (commandSignal) {
|
|
11131
|
+
const abortFromCommand = () => {
|
|
11132
|
+
const reason = commandSignal.reason instanceof Error ? commandSignal.reason : new UsageCommandInterruptedError();
|
|
11133
|
+
controller.abort(reason);
|
|
11134
|
+
settleReject(reason);
|
|
11135
|
+
};
|
|
11136
|
+
if (commandSignal.aborted) {
|
|
11137
|
+
abortFromCommand();
|
|
11138
|
+
return;
|
|
11139
|
+
}
|
|
11140
|
+
commandSignal.addEventListener("abort", abortFromCommand, { once: true });
|
|
11141
|
+
removeCommandAbortListener = () => commandSignal.removeEventListener("abort", abortFromCommand);
|
|
11142
|
+
}
|
|
10869
11143
|
let promise;
|
|
10870
11144
|
try {
|
|
10871
11145
|
promise = run(controller.signal);
|
|
@@ -11142,6 +11416,9 @@ function leftCellText(row) {
|
|
|
11142
11416
|
if (row.status === "error") {
|
|
11143
11417
|
return "-";
|
|
11144
11418
|
}
|
|
11419
|
+
if (row.limit.percentRemaining == null && row.limit.remainingText) {
|
|
11420
|
+
return row.limit.remainingText;
|
|
11421
|
+
}
|
|
11145
11422
|
return percentText(row.limit.percentRemaining);
|
|
11146
11423
|
}
|
|
11147
11424
|
function resetCellText(row) {
|
|
@@ -11481,9 +11758,17 @@ async function runUsageCommand(argv) {
|
|
|
11481
11758
|
}
|
|
11482
11759
|
}
|
|
11483
11760
|
const now = /* @__PURE__ */ new Date();
|
|
11484
|
-
const
|
|
11485
|
-
|
|
11486
|
-
|
|
11761
|
+
const commandController = new AbortController();
|
|
11762
|
+
const confirmationPrompter = !jsonOutput && Boolean(process.stdin.isTTY) && Boolean(process.stderr.isTTY) ? new UsageConfirmationPrompter(() => {
|
|
11763
|
+
if (!commandController.signal.aborted) {
|
|
11764
|
+
commandController.abort(new UsageCommandInterruptedError());
|
|
11765
|
+
}
|
|
11766
|
+
}) : null;
|
|
11767
|
+
let outcomes;
|
|
11768
|
+
try {
|
|
11769
|
+
let confirmationTargetChain = Promise.resolve();
|
|
11770
|
+
const outcomePromises = selectedTargets.map((target) => {
|
|
11771
|
+
const extract = () => extractUsageForTarget({
|
|
11487
11772
|
target,
|
|
11488
11773
|
repoRoot,
|
|
11489
11774
|
agentsDir,
|
|
@@ -11492,10 +11777,29 @@ async function runUsageCommand(argv) {
|
|
|
11492
11777
|
timeoutMs: resolveTargetTimeoutMs(target, cliTimeoutMs),
|
|
11493
11778
|
debug: debugOutput,
|
|
11494
11779
|
now,
|
|
11495
|
-
command: resolvedUsageCommands.get(target.id)
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11780
|
+
command: resolvedUsageCommands.get(target.id),
|
|
11781
|
+
confirm: supportsUsageConfirmation(target) ? confirmationPrompter?.confirm : void 0,
|
|
11782
|
+
commandSignal: commandController.signal
|
|
11783
|
+
});
|
|
11784
|
+
if (confirmationPrompter == null || !supportsUsageConfirmation(target)) {
|
|
11785
|
+
return extract();
|
|
11786
|
+
}
|
|
11787
|
+
const outcome = confirmationTargetChain.then(extract);
|
|
11788
|
+
confirmationTargetChain = outcome.then(
|
|
11789
|
+
() => void 0,
|
|
11790
|
+
() => void 0
|
|
11791
|
+
);
|
|
11792
|
+
return outcome;
|
|
11793
|
+
});
|
|
11794
|
+
outcomes = await Promise.all(outcomePromises);
|
|
11795
|
+
} finally {
|
|
11796
|
+
confirmationPrompter?.close();
|
|
11797
|
+
}
|
|
11798
|
+
if (commandController.signal.reason instanceof UsageCommandInterruptedError) {
|
|
11799
|
+
console.error(commandController.signal.reason.message);
|
|
11800
|
+
process.exit(130);
|
|
11801
|
+
return null;
|
|
11802
|
+
}
|
|
11499
11803
|
const targets = [];
|
|
11500
11804
|
const errors = [];
|
|
11501
11805
|
const notes = [];
|
|
@@ -11581,7 +11885,7 @@ const usageCommand = {
|
|
|
11581
11885
|
type: "boolean",
|
|
11582
11886
|
describe: "Print JSON and include extractor debug artifacts when available."
|
|
11583
11887
|
}).epilog(
|
|
11584
|
-
"Usage extraction may launch agent TUIs and may incur cost if an agent reads repo context on startup.
|
|
11888
|
+
"Usage extraction may launch agent TUIs and may incur cost if an agent reads repo context on startup. Interactive runs may ask before forwarding directory trust; JSON, debug, and non-interactive runs never prompt."
|
|
11585
11889
|
),
|
|
11586
11890
|
handler: async (argv) => {
|
|
11587
11891
|
await runUsageCommand(argv);
|
|
@@ -11708,6 +12012,9 @@ function translateInvocation(invocation, cli, options = {}) {
|
|
|
11708
12012
|
args.push(...mapped);
|
|
11709
12013
|
}
|
|
11710
12014
|
}
|
|
12015
|
+
if (invocation.structuredOutput) {
|
|
12016
|
+
args.push(...invocation.structuredOutput.args);
|
|
12017
|
+
}
|
|
11711
12018
|
if (mode === "one-shot" && base.args?.includes("exec")) {
|
|
11712
12019
|
const searchIndex = args.indexOf("--search");
|
|
11713
12020
|
if (searchIndex > -1) {
|
|
@@ -11765,9 +12072,344 @@ function buildAgentArgs(invocation) {
|
|
|
11765
12072
|
warnings: translated.warnings
|
|
11766
12073
|
};
|
|
11767
12074
|
}
|
|
12075
|
+
const PREVIOUS_OUTPUT_LIMIT = 4e3;
|
|
12076
|
+
const RESPONSE_RULES = "Respond with only the JSON value - no explanations, no markdown code fences, no additional text.";
|
|
12077
|
+
function schemaBlock(schemaJson) {
|
|
12078
|
+
return `Your entire response must be a single JSON value that conforms to this JSON Schema:
|
|
12079
|
+
${schemaJson}`;
|
|
12080
|
+
}
|
|
12081
|
+
function truncate(text, limit) {
|
|
12082
|
+
if (text.length <= limit) {
|
|
12083
|
+
return text;
|
|
12084
|
+
}
|
|
12085
|
+
return `${text.slice(0, limit)}
|
|
12086
|
+
[truncated]`;
|
|
12087
|
+
}
|
|
12088
|
+
function buildFallbackPrompt(prompt, schemaJson) {
|
|
12089
|
+
const base = prompt.trim().length > 0 ? `${prompt}
|
|
12090
|
+
|
|
12091
|
+
` : "";
|
|
12092
|
+
return `${base}${schemaBlock(schemaJson)}
|
|
12093
|
+
|
|
12094
|
+
${RESPONSE_RULES}`;
|
|
12095
|
+
}
|
|
12096
|
+
function buildRetryPrompt(prompt, schemaJson, previousOutput, errors) {
|
|
12097
|
+
const base = prompt.trim().length > 0 ? `${prompt}
|
|
12098
|
+
|
|
12099
|
+
` : "";
|
|
12100
|
+
const previous = previousOutput.trim().length > 0 ? truncate(previousOutput.trim(), PREVIOUS_OUTPUT_LIMIT) : "(empty response)";
|
|
12101
|
+
const errorLines = errors.map((error) => `- ${error}`).join("\n");
|
|
12102
|
+
return [
|
|
12103
|
+
`${base}${schemaBlock(schemaJson)}`,
|
|
12104
|
+
`Your previous response failed validation.
|
|
12105
|
+
|
|
12106
|
+
Previous response:
|
|
12107
|
+
${previous}`,
|
|
12108
|
+
`Validation errors:
|
|
12109
|
+
${errorLines}`,
|
|
12110
|
+
`Respond again with only the corrected JSON value. ${RESPONSE_RULES}`
|
|
12111
|
+
].join("\n\n");
|
|
12112
|
+
}
|
|
12113
|
+
function tryParse(text) {
|
|
12114
|
+
try {
|
|
12115
|
+
return { ok: true, value: JSON.parse(text) };
|
|
12116
|
+
} catch {
|
|
12117
|
+
return null;
|
|
12118
|
+
}
|
|
12119
|
+
}
|
|
12120
|
+
function extractJsonPayload(text) {
|
|
12121
|
+
const trimmed = text.trim();
|
|
12122
|
+
if (trimmed.length === 0) {
|
|
12123
|
+
return { ok: false, error: "the response was empty" };
|
|
12124
|
+
}
|
|
12125
|
+
const whole = tryParse(trimmed);
|
|
12126
|
+
if (whole) {
|
|
12127
|
+
return whole;
|
|
12128
|
+
}
|
|
12129
|
+
const fenced = trimmed.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
12130
|
+
if (fenced?.[1]) {
|
|
12131
|
+
const parsed = tryParse(fenced[1].trim());
|
|
12132
|
+
if (parsed) {
|
|
12133
|
+
return parsed;
|
|
12134
|
+
}
|
|
12135
|
+
}
|
|
12136
|
+
for (const [open, close] of [
|
|
12137
|
+
["{", "}"],
|
|
12138
|
+
["[", "]"]
|
|
12139
|
+
]) {
|
|
12140
|
+
const start = trimmed.indexOf(open);
|
|
12141
|
+
const end = trimmed.lastIndexOf(close);
|
|
12142
|
+
if (start !== -1 && end > start) {
|
|
12143
|
+
const parsed = tryParse(trimmed.slice(start, end + 1));
|
|
12144
|
+
if (parsed) {
|
|
12145
|
+
return parsed;
|
|
12146
|
+
}
|
|
12147
|
+
}
|
|
12148
|
+
}
|
|
12149
|
+
return { ok: false, error: "the response did not contain parseable JSON" };
|
|
12150
|
+
}
|
|
12151
|
+
function withPipedStdout(stdio) {
|
|
12152
|
+
if (Array.isArray(stdio)) {
|
|
12153
|
+
return [stdio[0] ?? "inherit", "pipe", stdio[2] ?? "inherit"];
|
|
12154
|
+
}
|
|
12155
|
+
return [stdio, "pipe", stdio];
|
|
12156
|
+
}
|
|
12157
|
+
function mapExitCode(code) {
|
|
12158
|
+
if (code === 0) {
|
|
12159
|
+
return { exitCode: 0, reason: "success" };
|
|
12160
|
+
}
|
|
12161
|
+
if (code === 2) {
|
|
12162
|
+
return { exitCode: 2, reason: "invalid-usage" };
|
|
12163
|
+
}
|
|
12164
|
+
if (code === 3) {
|
|
12165
|
+
return { exitCode: 3, reason: "blocked" };
|
|
12166
|
+
}
|
|
12167
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12168
|
+
}
|
|
12169
|
+
async function finalizeStructuredOutput(options) {
|
|
12170
|
+
const { plan, agentId, code, captured, stdout, stderr } = options;
|
|
12171
|
+
if (code !== 0) {
|
|
12172
|
+
if (plan.capture.type === "json-envelope" && captured.length > 0) {
|
|
12173
|
+
stderr.write(captured);
|
|
12174
|
+
}
|
|
12175
|
+
return mapExitCode(code);
|
|
12176
|
+
}
|
|
12177
|
+
if (plan.capture.type === "json-envelope") {
|
|
12178
|
+
let envelope;
|
|
12179
|
+
try {
|
|
12180
|
+
envelope = JSON.parse(captured);
|
|
12181
|
+
} catch {
|
|
12182
|
+
envelope = void 0;
|
|
12183
|
+
}
|
|
12184
|
+
if (typeof envelope !== "object" || envelope === null || Array.isArray(envelope)) {
|
|
12185
|
+
stderr.write(captured);
|
|
12186
|
+
stderr.write(`Error: ${agentId} did not return a JSON envelope.
|
|
12187
|
+
`);
|
|
12188
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12189
|
+
}
|
|
12190
|
+
const record = envelope;
|
|
12191
|
+
if (record.is_error === true) {
|
|
12192
|
+
stderr.write(captured);
|
|
12193
|
+
stderr.write(`Error: ${agentId} reported an error result.
|
|
12194
|
+
`);
|
|
12195
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12196
|
+
}
|
|
12197
|
+
const payload = record[plan.capture.field];
|
|
12198
|
+
if (payload === void 0 || payload === null) {
|
|
12199
|
+
stderr.write(captured);
|
|
12200
|
+
stderr.write(`Error: ${agentId} response is missing ${plan.capture.field}.
|
|
12201
|
+
`);
|
|
12202
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12203
|
+
}
|
|
12204
|
+
stdout.write(`${JSON.stringify(payload)}
|
|
12205
|
+
`);
|
|
12206
|
+
return { exitCode: 0, reason: "success" };
|
|
12207
|
+
}
|
|
12208
|
+
if (plan.capture.type === "fallback") {
|
|
12209
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12210
|
+
}
|
|
12211
|
+
let contents;
|
|
12212
|
+
try {
|
|
12213
|
+
contents = await readFile(plan.capture.path, "utf8");
|
|
12214
|
+
} catch {
|
|
12215
|
+
contents = "";
|
|
12216
|
+
}
|
|
12217
|
+
const trimmed = contents.trim();
|
|
12218
|
+
if (!trimmed) {
|
|
12219
|
+
stderr.write(`Error: ${agentId} did not produce a structured output message.
|
|
12220
|
+
`);
|
|
12221
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12222
|
+
}
|
|
12223
|
+
stdout.write(`${trimmed}
|
|
12224
|
+
`);
|
|
12225
|
+
return { exitCode: 0, reason: "success" };
|
|
12226
|
+
}
|
|
12227
|
+
function runCapturedAttempt(params) {
|
|
12228
|
+
return new Promise((resolve) => {
|
|
12229
|
+
let settled = false;
|
|
12230
|
+
const settle = (value) => {
|
|
12231
|
+
if (!settled) {
|
|
12232
|
+
settled = true;
|
|
12233
|
+
resolve(value);
|
|
12234
|
+
}
|
|
12235
|
+
};
|
|
12236
|
+
const child = params.spawn(params.command, params.args, { stdio: params.stdio });
|
|
12237
|
+
const chunks = [];
|
|
12238
|
+
const childStdout = child.stdout;
|
|
12239
|
+
if (childStdout) {
|
|
12240
|
+
childStdout.on("data", (chunk) => {
|
|
12241
|
+
chunks.push(Buffer.from(chunk));
|
|
12242
|
+
});
|
|
12243
|
+
}
|
|
12244
|
+
child.on("error", (error) => {
|
|
12245
|
+
params.stderr.write(`Error: ${error.message}
|
|
12246
|
+
`);
|
|
12247
|
+
settle({ kind: "spawn-error" });
|
|
12248
|
+
});
|
|
12249
|
+
child.on("close", (code) => {
|
|
12250
|
+
if (!childStdout) {
|
|
12251
|
+
params.stderr.write(`Error: ${params.agentId} stdout was not captured.
|
|
12252
|
+
`);
|
|
12253
|
+
settle({ kind: "spawn-error" });
|
|
12254
|
+
return;
|
|
12255
|
+
}
|
|
12256
|
+
settle({ kind: "closed", code, captured: Buffer.concat(chunks).toString("utf8") });
|
|
12257
|
+
});
|
|
12258
|
+
});
|
|
12259
|
+
}
|
|
12260
|
+
function extractEnvelopeText(params) {
|
|
12261
|
+
const { captured, field, agentId, stderr } = params;
|
|
12262
|
+
let envelope;
|
|
12263
|
+
try {
|
|
12264
|
+
envelope = JSON.parse(captured);
|
|
12265
|
+
} catch {
|
|
12266
|
+
envelope = void 0;
|
|
12267
|
+
}
|
|
12268
|
+
if (typeof envelope !== "object" || envelope === null || Array.isArray(envelope)) {
|
|
12269
|
+
if (captured.length > 0) {
|
|
12270
|
+
stderr.write(captured);
|
|
12271
|
+
}
|
|
12272
|
+
stderr.write(`Error: ${agentId} did not return a JSON envelope.
|
|
12273
|
+
`);
|
|
12274
|
+
return { ok: false };
|
|
12275
|
+
}
|
|
12276
|
+
const record = envelope;
|
|
12277
|
+
if (record.error !== void 0 && record.error !== null) {
|
|
12278
|
+
stderr.write(captured);
|
|
12279
|
+
stderr.write(`Error: ${agentId} reported an error result.
|
|
12280
|
+
`);
|
|
12281
|
+
return { ok: false };
|
|
12282
|
+
}
|
|
12283
|
+
const payload = record[field];
|
|
12284
|
+
if (payload === void 0 || payload === null) {
|
|
12285
|
+
stderr.write(captured);
|
|
12286
|
+
stderr.write(`Error: ${agentId} response is missing ${field}.
|
|
12287
|
+
`);
|
|
12288
|
+
return { ok: false };
|
|
12289
|
+
}
|
|
12290
|
+
return { ok: true, text: typeof payload === "string" ? payload : JSON.stringify(payload) };
|
|
12291
|
+
}
|
|
12292
|
+
async function runFallbackAttempts(params) {
|
|
12293
|
+
const { invocation, plan, capture, options, stdout, stderr } = params;
|
|
12294
|
+
const agentId = invocation.agent.id;
|
|
12295
|
+
const spawn$1 = options.spawn ?? spawn;
|
|
12296
|
+
const stdio = withPipedStdout(options.stdio ?? "inherit");
|
|
12297
|
+
const originalPrompt = invocation.prompt ?? "";
|
|
12298
|
+
const validate = plan.validate ?? (() => ({ valid: true, errors: [] }));
|
|
12299
|
+
let feedback = null;
|
|
12300
|
+
for (let attempt = 1; attempt <= capture.maxAttempts; attempt += 1) {
|
|
12301
|
+
const attemptPrompt = feedback ? buildRetryPrompt(originalPrompt, plan.schemaJson, feedback.output, feedback.errors) : buildFallbackPrompt(originalPrompt, plan.schemaJson);
|
|
12302
|
+
const built = buildAgentArgs({ ...invocation, prompt: attemptPrompt });
|
|
12303
|
+
if (attempt === 1) {
|
|
12304
|
+
if (options.traceTranslate) {
|
|
12305
|
+
const trace = {
|
|
12306
|
+
agent: agentId,
|
|
12307
|
+
mode: invocation.mode,
|
|
12308
|
+
command: built.command,
|
|
12309
|
+
args: built.args,
|
|
12310
|
+
shimArgs: built.shimArgs,
|
|
12311
|
+
passthroughArgs: built.passthroughArgs,
|
|
12312
|
+
warnings: built.warnings,
|
|
12313
|
+
requests: invocation.requests,
|
|
12314
|
+
structuredOutput: { capture: capture.type, maxAttempts: capture.maxAttempts }
|
|
12315
|
+
};
|
|
12316
|
+
stderr.write(`OA_TRANSLATION=${JSON.stringify(trace)}
|
|
12317
|
+
`);
|
|
12318
|
+
}
|
|
12319
|
+
for (const warning of built.warnings) {
|
|
12320
|
+
stderr.write(`${warning}
|
|
12321
|
+
`);
|
|
12322
|
+
}
|
|
12323
|
+
for (const notice of plan.notices ?? []) {
|
|
12324
|
+
stderr.write(`${notice}
|
|
12325
|
+
`);
|
|
12326
|
+
}
|
|
12327
|
+
}
|
|
12328
|
+
const attemptResult = await runCapturedAttempt({
|
|
12329
|
+
spawn: spawn$1,
|
|
12330
|
+
command: built.command,
|
|
12331
|
+
args: built.args,
|
|
12332
|
+
stdio,
|
|
12333
|
+
agentId,
|
|
12334
|
+
stderr
|
|
12335
|
+
});
|
|
12336
|
+
if (attemptResult.kind === "spawn-error") {
|
|
12337
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12338
|
+
}
|
|
12339
|
+
if (attemptResult.code !== 0) {
|
|
12340
|
+
if (attemptResult.captured.length > 0) {
|
|
12341
|
+
stderr.write(attemptResult.captured);
|
|
12342
|
+
}
|
|
12343
|
+
return mapExitCode(attemptResult.code);
|
|
12344
|
+
}
|
|
12345
|
+
let responseText = attemptResult.captured;
|
|
12346
|
+
if (capture.extraction.type === "json-envelope") {
|
|
12347
|
+
const outcome = extractEnvelopeText({
|
|
12348
|
+
captured: attemptResult.captured,
|
|
12349
|
+
field: capture.extraction.field,
|
|
12350
|
+
agentId,
|
|
12351
|
+
stderr
|
|
12352
|
+
});
|
|
12353
|
+
if (!outcome.ok) {
|
|
12354
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12355
|
+
}
|
|
12356
|
+
responseText = outcome.text;
|
|
12357
|
+
}
|
|
12358
|
+
const extracted = extractJsonPayload(responseText);
|
|
12359
|
+
if (extracted.ok) {
|
|
12360
|
+
const result = validate(extracted.value);
|
|
12361
|
+
if (result.valid) {
|
|
12362
|
+
stdout.write(`${JSON.stringify(extracted.value)}
|
|
12363
|
+
`);
|
|
12364
|
+
return { exitCode: 0, reason: "success" };
|
|
12365
|
+
}
|
|
12366
|
+
feedback = { output: responseText, errors: result.errors };
|
|
12367
|
+
} else {
|
|
12368
|
+
feedback = { output: responseText, errors: [extracted.error] };
|
|
12369
|
+
}
|
|
12370
|
+
if (attempt < capture.maxAttempts) {
|
|
12371
|
+
stderr.write(
|
|
12372
|
+
`Attempt ${attempt} failed schema validation; retrying (${attempt + 1}/${capture.maxAttempts}).
|
|
12373
|
+
`
|
|
12374
|
+
);
|
|
12375
|
+
for (const error of feedback.errors) {
|
|
12376
|
+
stderr.write(`- ${error}
|
|
12377
|
+
`);
|
|
12378
|
+
}
|
|
12379
|
+
}
|
|
12380
|
+
}
|
|
12381
|
+
if (feedback) {
|
|
12382
|
+
const lastOutput = feedback.output.trim();
|
|
12383
|
+
if (lastOutput.length > 0) {
|
|
12384
|
+
stderr.write(`${lastOutput}
|
|
12385
|
+
`);
|
|
12386
|
+
}
|
|
12387
|
+
for (const error of feedback.errors) {
|
|
12388
|
+
stderr.write(`- ${error}
|
|
12389
|
+
`);
|
|
12390
|
+
}
|
|
12391
|
+
}
|
|
12392
|
+
stderr.write(
|
|
12393
|
+
`Error: ${agentId} response failed schema validation after ${capture.maxAttempts} attempts.
|
|
12394
|
+
`
|
|
12395
|
+
);
|
|
12396
|
+
return { exitCode: 1, reason: "execution-error" };
|
|
12397
|
+
}
|
|
11768
12398
|
async function executeInvocation(invocation, options = {}) {
|
|
11769
|
-
const { command, args, warnings, shimArgs, passthroughArgs } = buildAgentArgs(invocation);
|
|
11770
12399
|
const stderr = options.stderr ?? process.stderr;
|
|
12400
|
+
const stdout = options.stdout ?? process.stdout;
|
|
12401
|
+
const plan = invocation.structuredOutput;
|
|
12402
|
+
if (plan && plan.capture.type === "fallback") {
|
|
12403
|
+
return runFallbackAttempts({
|
|
12404
|
+
invocation,
|
|
12405
|
+
plan,
|
|
12406
|
+
capture: plan.capture,
|
|
12407
|
+
options,
|
|
12408
|
+
stdout,
|
|
12409
|
+
stderr
|
|
12410
|
+
});
|
|
12411
|
+
}
|
|
12412
|
+
const { command, args, warnings, shimArgs, passthroughArgs } = buildAgentArgs(invocation);
|
|
11771
12413
|
if (options.traceTranslate) {
|
|
11772
12414
|
const trace = {
|
|
11773
12415
|
agent: invocation.agent.id,
|
|
@@ -11777,17 +12419,23 @@ async function executeInvocation(invocation, options = {}) {
|
|
|
11777
12419
|
shimArgs,
|
|
11778
12420
|
passthroughArgs,
|
|
11779
12421
|
warnings,
|
|
11780
|
-
requests: invocation.requests
|
|
12422
|
+
requests: invocation.requests,
|
|
12423
|
+
...plan ? { structuredOutput: { capture: plan.capture.type } } : {}
|
|
11781
12424
|
};
|
|
11782
12425
|
stderr.write(`OA_TRANSLATION=${JSON.stringify(trace)}
|
|
11783
12426
|
`);
|
|
11784
12427
|
}
|
|
11785
12428
|
for (const warning of warnings) {
|
|
11786
12429
|
stderr.write(`${warning}
|
|
12430
|
+
`);
|
|
12431
|
+
}
|
|
12432
|
+
for (const notice of plan?.notices ?? []) {
|
|
12433
|
+
stderr.write(`${notice}
|
|
11787
12434
|
`);
|
|
11788
12435
|
}
|
|
11789
12436
|
const spawn$1 = options.spawn ?? spawn;
|
|
11790
|
-
const
|
|
12437
|
+
const baseStdio = options.stdio ?? "inherit";
|
|
12438
|
+
const stdio = plan ? withPipedStdout(baseStdio) : baseStdio;
|
|
11791
12439
|
return await new Promise((resolve) => {
|
|
11792
12440
|
const child = spawn$1(command, args, { stdio });
|
|
11793
12441
|
child.on("error", (error) => {
|
|
@@ -11795,20 +12443,40 @@ async function executeInvocation(invocation, options = {}) {
|
|
|
11795
12443
|
`);
|
|
11796
12444
|
resolve({ exitCode: 1, reason: "execution-error" });
|
|
11797
12445
|
});
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
resolve(
|
|
11801
|
-
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
|
|
11805
|
-
|
|
12446
|
+
if (!plan) {
|
|
12447
|
+
child.on("exit", (code) => {
|
|
12448
|
+
resolve(mapExitCode(code));
|
|
12449
|
+
});
|
|
12450
|
+
return;
|
|
12451
|
+
}
|
|
12452
|
+
const chunks = [];
|
|
12453
|
+
const childStdout = child.stdout;
|
|
12454
|
+
if (childStdout) {
|
|
12455
|
+
if (plan.capture.type === "json-envelope") {
|
|
12456
|
+
childStdout.on("data", (chunk) => {
|
|
12457
|
+
chunks.push(Buffer.from(chunk));
|
|
12458
|
+
});
|
|
12459
|
+
} else {
|
|
12460
|
+
childStdout.on("data", (chunk) => {
|
|
12461
|
+
stderr.write(chunk);
|
|
12462
|
+
});
|
|
11806
12463
|
}
|
|
11807
|
-
|
|
11808
|
-
|
|
12464
|
+
}
|
|
12465
|
+
child.on("close", (code) => {
|
|
12466
|
+
if (!childStdout) {
|
|
12467
|
+
stderr.write(`Error: ${invocation.agent.id} stdout was not captured.
|
|
12468
|
+
`);
|
|
12469
|
+
resolve({ exitCode: 1, reason: "execution-error" });
|
|
11809
12470
|
return;
|
|
11810
12471
|
}
|
|
11811
|
-
|
|
12472
|
+
void finalizeStructuredOutput({
|
|
12473
|
+
plan,
|
|
12474
|
+
agentId: invocation.agent.id,
|
|
12475
|
+
code,
|
|
12476
|
+
captured: Buffer.concat(chunks).toString("utf8"),
|
|
12477
|
+
stdout,
|
|
12478
|
+
stderr
|
|
12479
|
+
}).then(resolve);
|
|
11812
12480
|
});
|
|
11813
12481
|
});
|
|
11814
12482
|
}
|
|
@@ -11846,6 +12514,16 @@ function readFlagValue(args, index, label) {
|
|
|
11846
12514
|
}
|
|
11847
12515
|
return [value, index + 1];
|
|
11848
12516
|
}
|
|
12517
|
+
function parseRetriesValue(value) {
|
|
12518
|
+
const normalized = normalizeValue(value, "--output-schema-retries");
|
|
12519
|
+
const parsed = Number(normalized);
|
|
12520
|
+
if (!Number.isInteger(parsed) || parsed < 0 || parsed > 10) {
|
|
12521
|
+
throw new InvalidUsageError(
|
|
12522
|
+
"Invalid value for --output-schema-retries. Provide an integer between 0 and 10."
|
|
12523
|
+
);
|
|
12524
|
+
}
|
|
12525
|
+
return parsed;
|
|
12526
|
+
}
|
|
11849
12527
|
function parseBooleanValue(label, value) {
|
|
11850
12528
|
const normalized = normalizeValue(value, label).toLowerCase();
|
|
11851
12529
|
if (["on", "true", "1"].includes(normalized)) {
|
|
@@ -11874,6 +12552,9 @@ function parseShimFlags(argv) {
|
|
|
11874
12552
|
let webExplicit = false;
|
|
11875
12553
|
let agent = null;
|
|
11876
12554
|
let agentExplicit = false;
|
|
12555
|
+
let outputSchema = null;
|
|
12556
|
+
let outputSchemaExplicit = false;
|
|
12557
|
+
let outputSchemaRetries = null;
|
|
11877
12558
|
let traceTranslate = false;
|
|
11878
12559
|
let help = false;
|
|
11879
12560
|
let version = false;
|
|
@@ -12011,6 +12692,28 @@ function parseShimFlags(argv) {
|
|
|
12011
12692
|
agentExplicit = true;
|
|
12012
12693
|
continue;
|
|
12013
12694
|
}
|
|
12695
|
+
if (arg === "--output-schema-retries") {
|
|
12696
|
+
const [value, nextIndex] = readFlagValue(preArgs, index, "--output-schema-retries");
|
|
12697
|
+
outputSchemaRetries = parseRetriesValue(value);
|
|
12698
|
+
index = nextIndex;
|
|
12699
|
+
continue;
|
|
12700
|
+
}
|
|
12701
|
+
if (arg.startsWith("--output-schema-retries=")) {
|
|
12702
|
+
outputSchemaRetries = parseRetriesValue(arg.slice("--output-schema-retries=".length));
|
|
12703
|
+
continue;
|
|
12704
|
+
}
|
|
12705
|
+
if (arg === "--output-schema") {
|
|
12706
|
+
const [value, nextIndex] = readFlagValue(preArgs, index, "--output-schema");
|
|
12707
|
+
outputSchema = normalizeValue(value, "--output-schema");
|
|
12708
|
+
outputSchemaExplicit = true;
|
|
12709
|
+
index = nextIndex;
|
|
12710
|
+
continue;
|
|
12711
|
+
}
|
|
12712
|
+
if (arg.startsWith("--output-schema=")) {
|
|
12713
|
+
outputSchema = normalizeValue(arg.slice("--output-schema=".length), "--output-schema");
|
|
12714
|
+
outputSchemaExplicit = true;
|
|
12715
|
+
continue;
|
|
12716
|
+
}
|
|
12014
12717
|
if (arg === "--trace-translate") {
|
|
12015
12718
|
traceTranslate = true;
|
|
12016
12719
|
continue;
|
|
@@ -12029,6 +12732,14 @@ function parseShimFlags(argv) {
|
|
|
12029
12732
|
if (outputSelections.length > 0) {
|
|
12030
12733
|
output = outputSelections[outputSelections.length - 1];
|
|
12031
12734
|
}
|
|
12735
|
+
if (outputSchema !== null && outputExplicit) {
|
|
12736
|
+
throw new InvalidUsageError(
|
|
12737
|
+
"--output-schema cannot be combined with --output, --json, or --stream-json."
|
|
12738
|
+
);
|
|
12739
|
+
}
|
|
12740
|
+
if (outputSchemaRetries !== null && outputSchema === null) {
|
|
12741
|
+
throw new InvalidUsageError("--output-schema-retries requires --output-schema.");
|
|
12742
|
+
}
|
|
12032
12743
|
if (approval === "yolo" && !sandboxExplicit) {
|
|
12033
12744
|
sandbox = "off";
|
|
12034
12745
|
}
|
|
@@ -12047,6 +12758,9 @@ function parseShimFlags(argv) {
|
|
|
12047
12758
|
webExplicit,
|
|
12048
12759
|
agent,
|
|
12049
12760
|
agentExplicit,
|
|
12761
|
+
outputSchema,
|
|
12762
|
+
outputSchemaExplicit,
|
|
12763
|
+
outputSchemaRetries,
|
|
12050
12764
|
traceTranslate,
|
|
12051
12765
|
help,
|
|
12052
12766
|
version,
|
|
@@ -12145,6 +12859,157 @@ async function resolveAgentSelection(flags, repoRoot, agentsDir) {
|
|
|
12145
12859
|
}
|
|
12146
12860
|
return { resolution: { selection, targetId: resolvedId }, targetMap };
|
|
12147
12861
|
}
|
|
12862
|
+
const AJV_OPTIONS = { allErrors: true, strict: false, validateFormats: false };
|
|
12863
|
+
const instances = /* @__PURE__ */ new Map();
|
|
12864
|
+
function resolveDialect(schema) {
|
|
12865
|
+
const declared = typeof schema.$schema === "string" ? schema.$schema : "";
|
|
12866
|
+
if (declared.includes("2020-12")) {
|
|
12867
|
+
return "2020-12";
|
|
12868
|
+
}
|
|
12869
|
+
if (declared.includes("2019-09")) {
|
|
12870
|
+
return "2019-09";
|
|
12871
|
+
}
|
|
12872
|
+
return "draft-07";
|
|
12873
|
+
}
|
|
12874
|
+
function ajvForDialect(dialect) {
|
|
12875
|
+
let instance = instances.get(dialect);
|
|
12876
|
+
if (!instance) {
|
|
12877
|
+
instance = dialect === "2020-12" ? new Ajv2020(AJV_OPTIONS) : dialect === "2019-09" ? new Ajv2019(AJV_OPTIONS) : new Ajv(AJV_OPTIONS);
|
|
12878
|
+
instances.set(dialect, instance);
|
|
12879
|
+
}
|
|
12880
|
+
return instance;
|
|
12881
|
+
}
|
|
12882
|
+
function compileSchemaValidator(schemaJson) {
|
|
12883
|
+
let compiled;
|
|
12884
|
+
try {
|
|
12885
|
+
const schema = JSON.parse(schemaJson);
|
|
12886
|
+
compiled = ajvForDialect(resolveDialect(schema)).compile(schema);
|
|
12887
|
+
} catch (error) {
|
|
12888
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12889
|
+
throw new InvalidUsageError(`Invalid value for --output-schema: ${message}.`);
|
|
12890
|
+
}
|
|
12891
|
+
return (data) => {
|
|
12892
|
+
const valid = compiled(data) === true;
|
|
12893
|
+
const errors = (compiled.errors ?? []).map(
|
|
12894
|
+
(error) => `${error.instancePath || "/"}: ${error.message ?? "is invalid"}`
|
|
12895
|
+
);
|
|
12896
|
+
return { valid, errors };
|
|
12897
|
+
};
|
|
12898
|
+
}
|
|
12899
|
+
const SCHEMA_LABEL = "--output-schema";
|
|
12900
|
+
const DEFAULT_SCHEMA_RETRIES = 2;
|
|
12901
|
+
function isPlainObject(value) {
|
|
12902
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12903
|
+
}
|
|
12904
|
+
function parseSchemaJson(text, sourceLabel) {
|
|
12905
|
+
let parsed;
|
|
12906
|
+
try {
|
|
12907
|
+
parsed = JSON.parse(text);
|
|
12908
|
+
} catch {
|
|
12909
|
+
throw new InvalidUsageError(`Invalid value for ${SCHEMA_LABEL}: ${sourceLabel}.`);
|
|
12910
|
+
}
|
|
12911
|
+
if (!isPlainObject(parsed)) {
|
|
12912
|
+
throw new InvalidUsageError(`Invalid value for ${SCHEMA_LABEL}: schema must be a JSON object.`);
|
|
12913
|
+
}
|
|
12914
|
+
return JSON.stringify(parsed);
|
|
12915
|
+
}
|
|
12916
|
+
async function resolveOutputSchema(raw) {
|
|
12917
|
+
const trimmed = raw.trim();
|
|
12918
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
12919
|
+
return parseSchemaJson(trimmed, "schema is not valid JSON");
|
|
12920
|
+
}
|
|
12921
|
+
let contents;
|
|
12922
|
+
try {
|
|
12923
|
+
contents = await readFile(trimmed, "utf8");
|
|
12924
|
+
} catch {
|
|
12925
|
+
throw new InvalidUsageError(
|
|
12926
|
+
`Invalid value for ${SCHEMA_LABEL}: cannot read schema file ${trimmed}.`
|
|
12927
|
+
);
|
|
12928
|
+
}
|
|
12929
|
+
return parseSchemaJson(contents, `schema file ${trimmed} is not valid JSON`);
|
|
12930
|
+
}
|
|
12931
|
+
async function planStructuredOutput(options) {
|
|
12932
|
+
const { rawSchema, mode, agentId, spec } = options;
|
|
12933
|
+
if (rawSchema === null) {
|
|
12934
|
+
return null;
|
|
12935
|
+
}
|
|
12936
|
+
if (mode !== "one-shot") {
|
|
12937
|
+
throw new InvalidUsageError(
|
|
12938
|
+
`${SCHEMA_LABEL} requires one-shot mode; provide -p/--prompt or pipe stdin.`
|
|
12939
|
+
);
|
|
12940
|
+
}
|
|
12941
|
+
if (!spec) {
|
|
12942
|
+
return planFallback(options);
|
|
12943
|
+
}
|
|
12944
|
+
const notices = [];
|
|
12945
|
+
if (options.retries !== null && options.retries !== void 0) {
|
|
12946
|
+
notices.push(
|
|
12947
|
+
`Warning: ${agentId} uses native ${SCHEMA_LABEL} support; ignoring ${SCHEMA_LABEL}-retries.`
|
|
12948
|
+
);
|
|
12949
|
+
}
|
|
12950
|
+
const schemaJson = await resolveOutputSchema(rawSchema);
|
|
12951
|
+
const needsTempDir = spec.delivery === "file" || spec.extraction.type === "last-message-file";
|
|
12952
|
+
const tempPaths = [];
|
|
12953
|
+
let tempDirPath = null;
|
|
12954
|
+
if (needsTempDir) {
|
|
12955
|
+
tempDirPath = await mkdtemp(path.join(options.tempDir ?? os.tmpdir(), "omniagent-schema-"));
|
|
12956
|
+
tempPaths.push(tempDirPath);
|
|
12957
|
+
}
|
|
12958
|
+
let deliveryValue = schemaJson;
|
|
12959
|
+
if (spec.delivery === "file" && tempDirPath) {
|
|
12960
|
+
deliveryValue = path.join(tempDirPath, "schema.json");
|
|
12961
|
+
await writeFile(deliveryValue, schemaJson, "utf8");
|
|
12962
|
+
}
|
|
12963
|
+
const args = [...spec.flag, deliveryValue, ...spec.companionArgs ?? []];
|
|
12964
|
+
let capture;
|
|
12965
|
+
if (spec.extraction.type === "json-envelope") {
|
|
12966
|
+
capture = { type: "json-envelope", field: spec.extraction.field };
|
|
12967
|
+
} else {
|
|
12968
|
+
const lastMessagePath = path.join(tempDirPath ?? os.tmpdir(), "last-message.txt");
|
|
12969
|
+
args.push(...spec.extraction.flag, lastMessagePath);
|
|
12970
|
+
capture = { type: "last-message-file", path: lastMessagePath };
|
|
12971
|
+
}
|
|
12972
|
+
return { schemaJson, args, capture, tempPaths, notices };
|
|
12973
|
+
}
|
|
12974
|
+
async function planFallback(options) {
|
|
12975
|
+
const { rawSchema, agentId, fallbackSpec } = options;
|
|
12976
|
+
if (rawSchema === null) {
|
|
12977
|
+
return null;
|
|
12978
|
+
}
|
|
12979
|
+
if (options.promptDeliverable === false) {
|
|
12980
|
+
throw new InvalidUsageError(
|
|
12981
|
+
`${agentId} cannot use the ${SCHEMA_LABEL} fallback: target defines no prompt flag.`
|
|
12982
|
+
);
|
|
12983
|
+
}
|
|
12984
|
+
const schemaJson = await resolveOutputSchema(rawSchema);
|
|
12985
|
+
const validate = compileSchemaValidator(schemaJson);
|
|
12986
|
+
const maxAttempts = (options.retries ?? DEFAULT_SCHEMA_RETRIES) + 1;
|
|
12987
|
+
return {
|
|
12988
|
+
schemaJson,
|
|
12989
|
+
args: [...fallbackSpec?.args ?? []],
|
|
12990
|
+
capture: {
|
|
12991
|
+
type: "fallback",
|
|
12992
|
+
extraction: fallbackSpec?.extraction ?? { type: "text" },
|
|
12993
|
+
maxAttempts
|
|
12994
|
+
},
|
|
12995
|
+
tempPaths: [],
|
|
12996
|
+
validate,
|
|
12997
|
+
notices: [
|
|
12998
|
+
`Notice: ${agentId} lacks native ${SCHEMA_LABEL} support; using prompt-based fallback with client-side validation.`
|
|
12999
|
+
]
|
|
13000
|
+
};
|
|
13001
|
+
}
|
|
13002
|
+
async function cleanupStructuredOutput(plan) {
|
|
13003
|
+
if (!plan) {
|
|
13004
|
+
return;
|
|
13005
|
+
}
|
|
13006
|
+
for (const tempPath of plan.tempPaths) {
|
|
13007
|
+
try {
|
|
13008
|
+
await rm(tempPath, { recursive: true, force: true });
|
|
13009
|
+
} catch {
|
|
13010
|
+
}
|
|
13011
|
+
}
|
|
13012
|
+
}
|
|
12148
13013
|
function normalizeKey(value) {
|
|
12149
13014
|
return value.trim().toLowerCase();
|
|
12150
13015
|
}
|
|
@@ -12165,6 +13030,16 @@ async function resolveInvocationFromFlags(options) {
|
|
|
12165
13030
|
const agent = resolution.selection;
|
|
12166
13031
|
const session = buildSession(flags);
|
|
12167
13032
|
const requests = buildRequests(flags);
|
|
13033
|
+
const structuredOutput = await planStructuredOutput({
|
|
13034
|
+
rawSchema: flags.outputSchema,
|
|
13035
|
+
mode,
|
|
13036
|
+
agentId: agent.id,
|
|
13037
|
+
spec: target.cli?.flags?.structuredOutput,
|
|
13038
|
+
fallbackSpec: target.cli?.flags?.structuredOutputFallback,
|
|
13039
|
+
retries: flags.outputSchemaRetries,
|
|
13040
|
+
promptDeliverable: Boolean(target.cli?.prompt),
|
|
13041
|
+
tempDir: options.tempDir
|
|
13042
|
+
});
|
|
12168
13043
|
return {
|
|
12169
13044
|
mode,
|
|
12170
13045
|
prompt,
|
|
@@ -12176,7 +13051,8 @@ async function resolveInvocationFromFlags(options) {
|
|
|
12176
13051
|
passthrough: {
|
|
12177
13052
|
hasDelimiter: flags.hasDelimiter,
|
|
12178
13053
|
args: flags.passthroughArgs
|
|
12179
|
-
}
|
|
13054
|
+
},
|
|
13055
|
+
structuredOutput
|
|
12180
13056
|
};
|
|
12181
13057
|
}
|
|
12182
13058
|
async function readStreamText(stream) {
|
|
@@ -12195,6 +13071,7 @@ async function runShim(argv, runtime = {}) {
|
|
|
12195
13071
|
const stdin = runtime.stdin ?? process.stdin;
|
|
12196
13072
|
const repoRoot = runtime.repoRoot ?? await findRepoRoot(process.cwd()) ?? process.cwd();
|
|
12197
13073
|
const stdinIsTTY = runtime.stdinIsTTY ?? stdin.isTTY ?? false;
|
|
13074
|
+
let invocation = null;
|
|
12198
13075
|
try {
|
|
12199
13076
|
const flags = parseShimFlags(argv);
|
|
12200
13077
|
let stdinText = runtime.stdinText ?? null;
|
|
@@ -12210,16 +13087,18 @@ async function runShim(argv, runtime = {}) {
|
|
|
12210
13087
|
}
|
|
12211
13088
|
}
|
|
12212
13089
|
const stdio = !stdinIsTTY && flags.promptExplicit ? ["ignore", "inherit", "inherit"] : "inherit";
|
|
12213
|
-
|
|
13090
|
+
invocation = await resolveInvocationFromFlags({
|
|
12214
13091
|
flags,
|
|
12215
13092
|
stdinIsTTY,
|
|
12216
13093
|
stdinText,
|
|
12217
13094
|
repoRoot,
|
|
12218
|
-
agentsDir: runtime.agentsDir
|
|
13095
|
+
agentsDir: runtime.agentsDir,
|
|
13096
|
+
tempDir: runtime.tempDir
|
|
12219
13097
|
});
|
|
12220
13098
|
const result = await executeInvocation(invocation, {
|
|
12221
13099
|
spawn: runtime.spawn,
|
|
12222
13100
|
stderr,
|
|
13101
|
+
stdout: runtime.stdout,
|
|
12223
13102
|
stdio,
|
|
12224
13103
|
traceTranslate: flags.traceTranslate
|
|
12225
13104
|
});
|
|
@@ -12234,6 +13113,8 @@ async function runShim(argv, runtime = {}) {
|
|
|
12234
13113
|
stderr.write(`Error: ${message}
|
|
12235
13114
|
`);
|
|
12236
13115
|
return exitCodeFor("execution-error");
|
|
13116
|
+
} finally {
|
|
13117
|
+
await cleanupStructuredOutput(invocation?.structuredOutput);
|
|
12237
13118
|
}
|
|
12238
13119
|
}
|
|
12239
13120
|
function resolveVersion() {
|
|
@@ -12260,11 +13141,13 @@ const VERSION = resolveVersion();
|
|
|
12260
13141
|
const KNOWN_COMMANDS = /* @__PURE__ */ new Set(["hello", "greet", "echo", "sync", "dev", "profiles", "usage"]);
|
|
12261
13142
|
const SHIM_CAPABILITIES = [
|
|
12262
13143
|
"Capabilities by agent:",
|
|
12263
|
-
" codex: approval, sandbox, output, model, web",
|
|
12264
|
-
" claude: approval, output, model",
|
|
12265
|
-
"
|
|
12266
|
-
" copilot: approval, model",
|
|
12267
|
-
"Unsupported shared flags for a selected agent emit a warning and are ignored."
|
|
13144
|
+
" codex: approval, sandbox, output, model, web, output-schema",
|
|
13145
|
+
" claude: approval, output, model, output-schema",
|
|
13146
|
+
" agy: approval, sandbox, model, output-schema (fallback) (alias: gemini)",
|
|
13147
|
+
" copilot: approval, model, output-schema (fallback)",
|
|
13148
|
+
"Unsupported shared flags for a selected agent emit a warning and are ignored.",
|
|
13149
|
+
"--output-schema is one-shot only; agents without native support use a prompt-based",
|
|
13150
|
+
"fallback with client-side validation and retries (--output-schema-retries, default 2)."
|
|
12268
13151
|
].join("\n");
|
|
12269
13152
|
function formatError(message, args) {
|
|
12270
13153
|
if (message.startsWith("Unknown command:")) {
|
|
@@ -12345,6 +13228,12 @@ function runCli(argv = process.argv, options = {}) {
|
|
|
12345
13228
|
}).option("agent", {
|
|
12346
13229
|
type: "string",
|
|
12347
13230
|
describe: "Select the agent (built-in id or configured alias)."
|
|
13231
|
+
}).option("output-schema", {
|
|
13232
|
+
type: "string",
|
|
13233
|
+
describe: "JSON schema file path or inline JSON; emit the final response as schema-conforming JSON (one-shot only)."
|
|
13234
|
+
}).option("output-schema-retries", {
|
|
13235
|
+
type: "number",
|
|
13236
|
+
describe: "Max retries when a prompt-based --output-schema fallback response fails validation (0-10, default 2)."
|
|
12348
13237
|
}).option("trace-translate", {
|
|
12349
13238
|
type: "boolean",
|
|
12350
13239
|
describe: "Emit a JSON line to stderr with the translated agent command/args."
|
|
@@ -12367,11 +13256,12 @@ if (!entry) {
|
|
|
12367
13256
|
}
|
|
12368
13257
|
}
|
|
12369
13258
|
export {
|
|
13259
|
+
UsageExtractionError as U,
|
|
12370
13260
|
compactLines as a,
|
|
12371
|
-
|
|
13261
|
+
parsePercentUsed as b,
|
|
12372
13262
|
cleanControlOutput as c,
|
|
12373
13263
|
parseResetText as d,
|
|
12374
13264
|
makeUsageLimit as m,
|
|
12375
|
-
|
|
13265
|
+
parsePercentRemaining as p,
|
|
12376
13266
|
runCli
|
|
12377
13267
|
};
|