@moda-ai/cli 1.49.0 → 1.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{cli-bqhs6sk7.js → cli-ac3p2byq.js} +245 -60
- package/dist/{cli-6xndg2h4.js → cli-ha40mgy1.js} +4 -4
- package/dist/{cli-m3bg9yyh.js → cli-he2wb4hd.js} +8 -9
- package/dist/{cli-c64d2jrw.js → cli-kxwm7y62.js} +1 -1
- package/dist/{cli-taf854xx.js → cli-sq6g0tk5.js} +2 -2
- package/dist/cli.js +166 -74
- package/dist/{harness-github-actions-dvq7spqh.js → harness-github-actions-gbty3k66.js} +2 -2
- package/dist/{harness-4ypeg9dh.js → harness-s13wvdxt.js} +2 -2
- package/dist/{index-pdg9t77n.js → index-pykaaezb.js} +5 -5
- package/dist/prompt-source-mcp.js +2 -2
- package/dist/{provision-7fhbgk2d.js → provision-d1dfj6as.js} +3 -3
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +40 -22
|
@@ -534,9 +534,11 @@ function writeSecretJsonFile(path, value) {
|
|
|
534
534
|
// src/errors.ts
|
|
535
535
|
class CliInputError extends Error {
|
|
536
536
|
usage;
|
|
537
|
-
|
|
537
|
+
reason;
|
|
538
|
+
constructor(message, usage, reason) {
|
|
538
539
|
super(message);
|
|
539
540
|
this.usage = usage;
|
|
541
|
+
this.reason = reason;
|
|
540
542
|
this.name = "CliInputError";
|
|
541
543
|
}
|
|
542
544
|
}
|
|
@@ -986,6 +988,9 @@ function packSnapshot(inputs, opts) {
|
|
|
986
988
|
}
|
|
987
989
|
// src/output.ts
|
|
988
990
|
import { randomUUID } from "node:crypto";
|
|
991
|
+
import { lstatSync, mkdirSync as mkdirSync2, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
992
|
+
import { tmpdir } from "node:os";
|
|
993
|
+
import { join as join2 } from "node:path";
|
|
989
994
|
var AGENT_SCHEMA_VERSION = "moda.agent.v1";
|
|
990
995
|
var AGENT_EVENT_SCHEMA_VERSION = "moda.agent_event.v1";
|
|
991
996
|
var FEEDBACK_TIP = 'Help us improve! If a result in this response looks wrong or is missing data, flag it: moda feedback "<describe what looked wrong>" [--category=...] [--conversation-id=... | --cluster-id=... | --tool-name=...]. Only submit genuine observations.';
|
|
@@ -1005,7 +1010,8 @@ var AGENT_ERROR_CODES = [
|
|
|
1005
1010
|
"command_error",
|
|
1006
1011
|
"access_denied",
|
|
1007
1012
|
"unknown_error",
|
|
1008
|
-
"cloud_unavailable"
|
|
1013
|
+
"cloud_unavailable",
|
|
1014
|
+
"output_error"
|
|
1009
1015
|
];
|
|
1010
1016
|
var FALLBACK_RUN_ID = randomUUID();
|
|
1011
1017
|
var fallbackSeq = 0;
|
|
@@ -1116,6 +1122,7 @@ function createCliOutput(options) {
|
|
|
1116
1122
|
seq: 0,
|
|
1117
1123
|
started: false,
|
|
1118
1124
|
terminal: false,
|
|
1125
|
+
outputError: false,
|
|
1119
1126
|
startedAt: Date.now(),
|
|
1120
1127
|
lastEventAt: Date.now()
|
|
1121
1128
|
};
|
|
@@ -1177,6 +1184,8 @@ function createCliOutput(options) {
|
|
|
1177
1184
|
if (state.terminal)
|
|
1178
1185
|
return;
|
|
1179
1186
|
const envelope = writeEnvelope(data, writeOptions);
|
|
1187
|
+
if (envelope.errors.some((error) => error.code === "output_error"))
|
|
1188
|
+
state.outputError = true;
|
|
1180
1189
|
if (options.mode === "agent-stream") {
|
|
1181
1190
|
ensureStarted();
|
|
1182
1191
|
emitEvent({
|
|
@@ -1272,6 +1281,9 @@ function createCliOutput(options) {
|
|
|
1272
1281
|
hasTerminalOutput() {
|
|
1273
1282
|
return state.terminal;
|
|
1274
1283
|
},
|
|
1284
|
+
hasOutputError() {
|
|
1285
|
+
return state.outputError;
|
|
1286
|
+
},
|
|
1275
1287
|
close() {
|
|
1276
1288
|
clearHeartbeat(state);
|
|
1277
1289
|
}
|
|
@@ -1281,41 +1293,198 @@ function createCliOutput(options) {
|
|
|
1281
1293
|
function createAgentEnvelope(options) {
|
|
1282
1294
|
const safeData = redactDeep(options.data);
|
|
1283
1295
|
const maxBytes = agentMaxOutputBytes();
|
|
1296
|
+
let fullOutput;
|
|
1297
|
+
let saveFailed = false;
|
|
1298
|
+
let envelopeTextSaveFailed = false;
|
|
1299
|
+
const writeFullOutput = options.persistFullOutput === false ? undefined : () => {
|
|
1300
|
+
fullOutput ??= { path: writeAgentFullOutput(options.command, safeData) };
|
|
1301
|
+
if (!fullOutput.path)
|
|
1302
|
+
saveFailed = true;
|
|
1303
|
+
return fullOutput.path;
|
|
1304
|
+
};
|
|
1305
|
+
let text = redactDeep({
|
|
1306
|
+
summary: normalizeSummary(options.summary, options.command, options.status, safeData),
|
|
1307
|
+
findings: options.findings ?? [],
|
|
1308
|
+
evidence_refs: options.evidenceRefs ?? [],
|
|
1309
|
+
recommended_actions: options.recommendedActions ?? [],
|
|
1310
|
+
next_commands: normalizeNextCommands(options.nextCommands ?? []),
|
|
1311
|
+
warnings: options.warnings ?? inferWarnings(safeData)
|
|
1312
|
+
});
|
|
1313
|
+
let moved;
|
|
1284
1314
|
const build = (bounded) => ({
|
|
1285
1315
|
schema_version: AGENT_SCHEMA_VERSION,
|
|
1286
1316
|
command: options.command,
|
|
1287
1317
|
status: options.status,
|
|
1288
1318
|
generated_at: new Date().toISOString(),
|
|
1289
1319
|
...options.profile ? { profile: options.profile } : {},
|
|
1290
|
-
summary:
|
|
1291
|
-
findings:
|
|
1292
|
-
evidence_refs:
|
|
1293
|
-
recommended_actions:
|
|
1294
|
-
next_commands:
|
|
1295
|
-
artifacts:
|
|
1320
|
+
summary: text.summary,
|
|
1321
|
+
findings: text.findings,
|
|
1322
|
+
evidence_refs: text.evidence_refs,
|
|
1323
|
+
recommended_actions: text.recommended_actions,
|
|
1324
|
+
next_commands: text.next_commands,
|
|
1325
|
+
artifacts: [
|
|
1326
|
+
...options.artifacts ?? [],
|
|
1327
|
+
...bounded.fullOutputPath ? [{ kind: "full_output", path: bounded.fullOutputPath, description: "Complete command output (the same JSON --json prints); data in this envelope was bounded." }] : [],
|
|
1328
|
+
...moved?.path ? [{ kind: "full_envelope_text", path: moved.path, description: "Whole envelope text (summary, findings, evidence_refs, actions, next_commands, warnings) before oversized fields were moved out of this envelope." }] : []
|
|
1329
|
+
],
|
|
1296
1330
|
warnings: [
|
|
1297
|
-
...
|
|
1298
|
-
...bounded.warning ? [bounded.warning] : []
|
|
1331
|
+
...text.warnings,
|
|
1332
|
+
...bounded.warning ? [bounded.warning] : [],
|
|
1333
|
+
...moved ? [movedTextWarning(moved)] : []
|
|
1299
1334
|
],
|
|
1300
1335
|
errors: options.errors ?? [],
|
|
1301
1336
|
data: bounded.data,
|
|
1302
1337
|
...options.meta ? { meta: options.meta } : {},
|
|
1303
|
-
...bounded.truncation ? { truncation:
|
|
1338
|
+
...bounded.truncation || moved ? { truncation: {
|
|
1339
|
+
...bounded.truncation ?? {},
|
|
1340
|
+
...moved ? { envelope_text: {
|
|
1341
|
+
reason: "agent_output_byte_limit",
|
|
1342
|
+
moved_fields: moved.fields,
|
|
1343
|
+
complete: false,
|
|
1344
|
+
...moved.whole ? { whole_text_moved: true } : {},
|
|
1345
|
+
...moved.path ? { full_envelope_path: moved.path } : {}
|
|
1346
|
+
} } : {}
|
|
1347
|
+
} } : {}
|
|
1304
1348
|
});
|
|
1305
|
-
|
|
1306
|
-
const
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1349
|
+
const sizeOf = (value) => Buffer.byteLength(JSON.stringify(value) ?? "", "utf8");
|
|
1350
|
+
const rebound = (current) => {
|
|
1351
|
+
const overhead = sizeOf(current) - sizeOf(current.data);
|
|
1352
|
+
return build(boundForAgent(safeData, Math.max(1024, maxBytes - overhead - 1024), { writeFullOutput }));
|
|
1353
|
+
};
|
|
1354
|
+
let envelope = build(boundForAgent(safeData, maxBytes, { writeFullOutput }));
|
|
1355
|
+
if (sizeOf(envelope) > maxBytes)
|
|
1356
|
+
envelope = rebound(envelope);
|
|
1357
|
+
if (sizeOf(envelope) > maxBytes && !saveFailed) {
|
|
1358
|
+
const original = text;
|
|
1359
|
+
const savedPath = options.persistFullOutput === false ? undefined : writeAgentFullOutput(`${options.command}-envelope`, original);
|
|
1360
|
+
if (options.persistFullOutput !== false && !savedPath) {
|
|
1361
|
+
saveFailed = true;
|
|
1362
|
+
envelopeTextSaveFailed = true;
|
|
1363
|
+
} else {
|
|
1364
|
+
const slots = envelopeTextSlots(original).sort((left, right) => right.bytes - left.bytes);
|
|
1365
|
+
text = structuredClone(original);
|
|
1366
|
+
moved = { path: savedPath, fields: [] };
|
|
1367
|
+
for (const slot of slots) {
|
|
1368
|
+
if (sizeOf(envelope) <= maxBytes)
|
|
1369
|
+
break;
|
|
1370
|
+
const pointer = movedTextPointer(slot.field, slot.text, savedPath);
|
|
1371
|
+
const added = Buffer.byteLength(JSON.stringify(pointer), "utf8") + 2 * movedFieldNameBytes(slot.field);
|
|
1372
|
+
if (added >= slot.bytes)
|
|
1373
|
+
continue;
|
|
1374
|
+
slot.set(text, pointer);
|
|
1375
|
+
moved.fields.push(slot.field);
|
|
1376
|
+
envelope = rebound(envelope);
|
|
1377
|
+
}
|
|
1378
|
+
if (moved.fields.length === 0)
|
|
1379
|
+
moved = undefined;
|
|
1380
|
+
envelope = rebound(envelope);
|
|
1381
|
+
if (sizeOf(envelope) > maxBytes) {
|
|
1382
|
+
text = {
|
|
1383
|
+
summary: { text: movedWholeTextPointer(savedPath), confidence: original.summary.confidence },
|
|
1384
|
+
findings: [],
|
|
1385
|
+
evidence_refs: [],
|
|
1386
|
+
recommended_actions: [],
|
|
1387
|
+
next_commands: [],
|
|
1388
|
+
warnings: []
|
|
1389
|
+
};
|
|
1390
|
+
moved = { path: savedPath, fields: ["*"], whole: true };
|
|
1391
|
+
envelope = rebound(envelope);
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
if (saveFailed) {
|
|
1396
|
+
envelope = {
|
|
1397
|
+
...envelope,
|
|
1398
|
+
status: "error",
|
|
1399
|
+
errors: [...envelope.errors, saveFailedError(maxBytes, envelopeTextSaveFailed, fullOutput?.path)]
|
|
1400
|
+
};
|
|
1310
1401
|
}
|
|
1311
1402
|
return redactDeep(envelope);
|
|
1312
1403
|
}
|
|
1404
|
+
function saveFailedError(maxBytes, envelopeTextSaveFailed, dataPath) {
|
|
1405
|
+
const where = "(MODA_AGENT_OUTPUT_DIR is unwritable or the disk is full)";
|
|
1406
|
+
const remedy = "Point MODA_AGENT_OUTPUT_DIR at a writable directory, rerun with --json (no byte limit), or narrow the query.";
|
|
1407
|
+
if (!envelopeTextSaveFailed) {
|
|
1408
|
+
return {
|
|
1409
|
+
code: "output_error",
|
|
1410
|
+
cause: "full_output_save_failed",
|
|
1411
|
+
message: `Output is over the ${maxBytes}-byte agent limit and the complete output could not be saved to a file ${where}, ` + `so nothing was moved out: this envelope holds the whole result, over the limit. ${remedy}`,
|
|
1412
|
+
blocking: false
|
|
1413
|
+
};
|
|
1414
|
+
}
|
|
1415
|
+
const dataState = dataPath ? `data is NOT the whole result: it was bounded to fit, and the complete data was saved to ${dataPath} ` + "(truncation.data.full_output_path); read it in line ranges or with jq. " : "data is the whole result. ";
|
|
1416
|
+
return {
|
|
1417
|
+
code: "output_error",
|
|
1418
|
+
cause: "envelope_text_save_failed",
|
|
1419
|
+
message: `Output is over the ${maxBytes}-byte agent limit and the oversized envelope text (summary, findings, evidence_refs, ` + `recommended_actions, next_commands, warnings) could not be saved to a file ${where}, so that text was kept whole ` + `in this envelope, over the limit. ${dataState}${remedy}`,
|
|
1420
|
+
blocking: false
|
|
1421
|
+
};
|
|
1422
|
+
}
|
|
1423
|
+
function envelopeTextSlots(text) {
|
|
1424
|
+
const slots = [
|
|
1425
|
+
{ field: "summary.text", text: text.summary.text, set: (target, value) => {
|
|
1426
|
+
target.summary.text = value;
|
|
1427
|
+
} }
|
|
1428
|
+
];
|
|
1429
|
+
text.findings.forEach((finding, index) => {
|
|
1430
|
+
slots.push({ field: `findings[${index}].title`, text: finding.title, set: (target, value) => {
|
|
1431
|
+
target.findings[index].title = value;
|
|
1432
|
+
} });
|
|
1433
|
+
if (finding.description) {
|
|
1434
|
+
slots.push({ field: `findings[${index}].description`, text: finding.description, set: (target, value) => {
|
|
1435
|
+
target.findings[index].description = value;
|
|
1436
|
+
} });
|
|
1437
|
+
}
|
|
1438
|
+
});
|
|
1439
|
+
text.evidence_refs.forEach((ref, index) => {
|
|
1440
|
+
slots.push({ field: `evidence_refs[${index}].label`, text: ref.label, set: (target, value) => {
|
|
1441
|
+
target.evidence_refs[index].label = value;
|
|
1442
|
+
} });
|
|
1443
|
+
});
|
|
1444
|
+
text.recommended_actions.forEach((action, index) => {
|
|
1445
|
+
slots.push({ field: `recommended_actions[${index}].title`, text: action.title, set: (target, value) => {
|
|
1446
|
+
target.recommended_actions[index].title = value;
|
|
1447
|
+
} });
|
|
1448
|
+
if (action.rationale) {
|
|
1449
|
+
slots.push({ field: `recommended_actions[${index}].rationale`, text: action.rationale, set: (target, value) => {
|
|
1450
|
+
target.recommended_actions[index].rationale = value;
|
|
1451
|
+
} });
|
|
1452
|
+
}
|
|
1453
|
+
});
|
|
1454
|
+
text.next_commands.forEach((command, index) => {
|
|
1455
|
+
slots.push({ field: `next_commands[${index}].purpose`, text: command.purpose, set: (target, value) => {
|
|
1456
|
+
target.next_commands[index].purpose = value;
|
|
1457
|
+
} });
|
|
1458
|
+
});
|
|
1459
|
+
text.warnings.forEach((warning, index) => {
|
|
1460
|
+
slots.push({ field: `warnings[${index}]`, text: warning, set: (target, value) => {
|
|
1461
|
+
target.warnings[index] = value;
|
|
1462
|
+
} });
|
|
1463
|
+
});
|
|
1464
|
+
return slots.map((slot) => ({ ...slot, bytes: Buffer.byteLength(JSON.stringify(slot.text), "utf8") }));
|
|
1465
|
+
}
|
|
1466
|
+
function movedTextPointer(field, value, path) {
|
|
1467
|
+
const chars = Array.from(value).length;
|
|
1468
|
+
return path ? `[${chars} characters moved whole to ${path} at ${field}]` : `[${chars} characters over the agent byte limit; not saved. Rerun with --json or raise MODA_AGENT_MAX_OUTPUT_BYTES]`;
|
|
1469
|
+
}
|
|
1470
|
+
function movedFieldNameBytes(field) {
|
|
1471
|
+
return Buffer.byteLength(JSON.stringify(field), "utf8") + 2;
|
|
1472
|
+
}
|
|
1473
|
+
function movedWholeTextPointer(path) {
|
|
1474
|
+
return path ? `[Envelope text (summary, findings, evidence_refs, recommended_actions, next_commands, warnings) was over the agent byte limit and moved whole to ${path}]` : "[Envelope text was over the agent byte limit; not saved. Rerun with --json or raise MODA_AGENT_MAX_OUTPUT_BYTES]";
|
|
1475
|
+
}
|
|
1476
|
+
function movedTextWarning(moved) {
|
|
1477
|
+
if (moved.whole) {
|
|
1478
|
+
return "Envelope text outside data was over the agent byte limit even after moving its largest fields: all of it was moved whole " + (moved.path ? `to ${moved.path} (read it with jq)` : "(the file could not be saved; rerun with --json or raise MODA_AGENT_MAX_OUTPUT_BYTES)") + ".";
|
|
1479
|
+
}
|
|
1480
|
+
return `Envelope text outside data was over the agent byte limit: ${moved.fields.length} field(s) were moved whole ` + (moved.path ? `to ${moved.path} (same field paths; read it with jq)` : "(the file could not be saved; rerun with --json or raise MODA_AGENT_MAX_OUTPUT_BYTES)") + ` and replaced by pointers: ${moved.fields.join(", ")}.`;
|
|
1481
|
+
}
|
|
1313
1482
|
var AGENT_ENVELOPE_RESERVE_BYTES = 2048;
|
|
1314
1483
|
function agentEnvelopeFits(command, data, options = {}) {
|
|
1315
1484
|
const maxBytes = agentMaxOutputBytes() - AGENT_ENVELOPE_RESERVE_BYTES;
|
|
1316
1485
|
if (Buffer.byteLength(JSON.stringify(data) ?? "", "utf8") > maxBytes)
|
|
1317
1486
|
return false;
|
|
1318
|
-
const envelope = createAgentEnvelope({ command, status: "ok", data, ...options });
|
|
1487
|
+
const envelope = createAgentEnvelope({ command, status: "ok", data, ...options, persistFullOutput: false });
|
|
1319
1488
|
return !envelope.truncation && Buffer.byteLength(JSON.stringify(envelope), "utf8") <= maxBytes;
|
|
1320
1489
|
}
|
|
1321
1490
|
function errorWarnings(error) {
|
|
@@ -1559,41 +1728,61 @@ function inferWarnings(data) {
|
|
|
1559
1728
|
}
|
|
1560
1729
|
return [];
|
|
1561
1730
|
}
|
|
1562
|
-
var AGENT_MAX_STRING_CHARS = 2000;
|
|
1563
|
-
var PROTECTED_STRING_KEY = /(cursor|token|_id$|^id$|url$|href$|^key$|hash$)/i;
|
|
1564
1731
|
function agentMaxOutputBytes() {
|
|
1565
1732
|
return Number(process.env.MODA_AGENT_MAX_OUTPUT_BYTES ?? 200000);
|
|
1566
1733
|
}
|
|
1567
|
-
|
|
1734
|
+
var AGENT_FULL_OUTPUT_FILE = /-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-\d{3}Z-[0-9a-f]{8}\.json$/;
|
|
1735
|
+
function agentOutputRetentionMs() {
|
|
1736
|
+
const hours = Number(process.env.MODA_AGENT_OUTPUT_RETENTION_HOURS ?? 24);
|
|
1737
|
+
return (Number.isFinite(hours) && hours > 0 ? hours : 24) * 3600000;
|
|
1738
|
+
}
|
|
1739
|
+
function pruneAgentFullOutputs(dir, keep, now = Date.now()) {
|
|
1740
|
+
const cutoff = now - agentOutputRetentionMs();
|
|
1741
|
+
let names;
|
|
1742
|
+
try {
|
|
1743
|
+
names = readdirSync(dir);
|
|
1744
|
+
} catch {
|
|
1745
|
+
return;
|
|
1746
|
+
}
|
|
1747
|
+
for (const name of names) {
|
|
1748
|
+
if (!AGENT_FULL_OUTPUT_FILE.test(name))
|
|
1749
|
+
continue;
|
|
1750
|
+
const path = join2(dir, name);
|
|
1751
|
+
if (path === keep)
|
|
1752
|
+
continue;
|
|
1753
|
+
try {
|
|
1754
|
+
const stat = lstatSync(path);
|
|
1755
|
+
if (stat.isFile() && stat.mtimeMs < cutoff)
|
|
1756
|
+
unlinkSync(path);
|
|
1757
|
+
} catch {}
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
function writeAgentFullOutput(command, data) {
|
|
1761
|
+
try {
|
|
1762
|
+
const dir = process.env.MODA_AGENT_OUTPUT_DIR || join2(tmpdir(), "moda-agent-output");
|
|
1763
|
+
mkdirSync2(dir, { recursive: true, mode: 448 });
|
|
1764
|
+
const slug = command.replace(/[^a-zA-Z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "output";
|
|
1765
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
1766
|
+
const path = join2(dir, `${slug}-${stamp}-${randomUUID().slice(0, 8)}.json`);
|
|
1767
|
+
writeFileSync2(path, `${JSON.stringify(data, null, 2)}
|
|
1768
|
+
`, { encoding: "utf8", mode: 384 });
|
|
1769
|
+
pruneAgentFullOutputs(dir, path);
|
|
1770
|
+
return path;
|
|
1771
|
+
} catch {
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
function boundForAgent(data, maxBytes = agentMaxOutputBytes(), options = {}) {
|
|
1568
1776
|
const sizeOf = (value) => Buffer.byteLength(JSON.stringify(value) ?? "", "utf8");
|
|
1569
1777
|
const serialized = JSON.stringify(data) ?? "";
|
|
1570
1778
|
const originalBytes = Buffer.byteLength(serialized, "utf8");
|
|
1571
1779
|
if (originalBytes <= maxBytes)
|
|
1572
1780
|
return { data };
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
return value;
|
|
1578
|
-
shortenedStrings += 1;
|
|
1579
|
-
return `${value.slice(0, limit)}… [truncated ${value.length - limit} chars]`;
|
|
1580
|
-
}
|
|
1581
|
-
if (Array.isArray(value))
|
|
1582
|
-
return value.map((item) => shorten(item, limit));
|
|
1583
|
-
if (value && typeof value === "object") {
|
|
1584
|
-
return Object.fromEntries(Object.entries(value).map(([entryKey, item]) => [entryKey, shorten(item, limit, entryKey)]));
|
|
1585
|
-
}
|
|
1586
|
-
return value;
|
|
1587
|
-
};
|
|
1588
|
-
let bounded = data;
|
|
1781
|
+
const fullOutputPath = options.writeFullOutput?.();
|
|
1782
|
+
if (options.writeFullOutput && !fullOutputPath)
|
|
1783
|
+
return { data, saveFailed: true };
|
|
1784
|
+
const bounded = JSON.parse(serialized);
|
|
1589
1785
|
let boundedBytes = originalBytes;
|
|
1590
|
-
for (const limit of [AGENT_MAX_STRING_CHARS, 500, 200]) {
|
|
1591
|
-
shortenedStrings = 0;
|
|
1592
|
-
bounded = shorten(data, limit);
|
|
1593
|
-
boundedBytes = sizeOf(bounded);
|
|
1594
|
-
if (boundedBytes <= maxBytes)
|
|
1595
|
-
break;
|
|
1596
|
-
}
|
|
1597
1786
|
const droppedItems = {};
|
|
1598
1787
|
const collectArrays = (value, path, out) => {
|
|
1599
1788
|
if (Array.isArray(value)) {
|
|
@@ -1630,39 +1819,35 @@ function boundForAgent(data, maxBytes = agentMaxOutputBytes()) {
|
|
|
1630
1819
|
boundedBytes = sizeOf(bounded);
|
|
1631
1820
|
}
|
|
1632
1821
|
const dropped = Object.entries(droppedItems);
|
|
1633
|
-
const
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
].filter(Boolean);
|
|
1637
|
-
const howToGetMore = "For complete results narrow the query (a smaller --limit, with --offset or --cursor paging where the command supports it), " + "rerun with --json (no byte limit), or raise MODA_AGENT_MAX_OUTPUT_BYTES.";
|
|
1822
|
+
const whereIsTheRest = fullOutputPath ? `The complete output (every item, no text shortened) is in ${fullOutputPath}; read it in line ranges or query it with jq. ` : "The complete output could not be saved to a file. ";
|
|
1823
|
+
const howToGetMore = whereIsTheRest + "Alternatively narrow the query (a smaller --limit, with --offset or --cursor paging where the command supports it), " + "rerun with --json (no byte limit), or raise MODA_AGENT_MAX_OUTPUT_BYTES.";
|
|
1824
|
+
const pathField = fullOutputPath ? { full_output_path: fullOutputPath } : {};
|
|
1638
1825
|
if (boundedBytes > maxBytes) {
|
|
1639
|
-
const stub = { truncated: true, original_bytes: originalBytes, max_bytes: maxBytes, preview: serialized.slice(0, Math.max(0, maxBytes - 256)) };
|
|
1640
|
-
for (let stubBytes = sizeOf(stub);stubBytes > maxBytes && stub.preview.length > 0; stubBytes = sizeOf(stub)) {
|
|
1641
|
-
stub.preview = stub.preview.slice(0, Math.max(0, stub.preview.length - (stubBytes - maxBytes) - 16));
|
|
1642
|
-
}
|
|
1643
1826
|
return {
|
|
1644
|
-
data:
|
|
1645
|
-
warning: `Output was ${originalBytes} bytes, over the ${maxBytes}-byte agent limit, and could not be reduced while keeping its structure; data is a
|
|
1827
|
+
data: { truncated: true, original_bytes: originalBytes, max_bytes: maxBytes, ...pathField },
|
|
1828
|
+
warning: `Output was ${originalBytes} bytes, over the ${maxBytes}-byte agent limit, and could not be reduced while keeping its structure; data is a pointer stub. ${howToGetMore}`,
|
|
1646
1829
|
truncation: {
|
|
1647
|
-
data: { original_bytes: originalBytes, max_bytes: maxBytes, reason: "agent_output_byte_limit", structure_preserved: false, complete: false }
|
|
1648
|
-
}
|
|
1830
|
+
data: { original_bytes: originalBytes, max_bytes: maxBytes, reason: "agent_output_byte_limit", structure_preserved: false, complete: false, ...pathField }
|
|
1831
|
+
},
|
|
1832
|
+
fullOutputPath
|
|
1649
1833
|
};
|
|
1650
1834
|
}
|
|
1651
1835
|
return {
|
|
1652
1836
|
data: bounded,
|
|
1653
|
-
warning: `Output was ${originalBytes} bytes, over the ${maxBytes}-byte agent limit: ${
|
|
1837
|
+
warning: `Output was ${originalBytes} bytes, over the ${maxBytes}-byte agent limit: ${dropped.map(([path, count]) => `dropped the last ${count} item(s) of data.${path}`).join("; ")}. ${howToGetMore}`,
|
|
1654
1838
|
truncation: {
|
|
1655
1839
|
data: {
|
|
1656
1840
|
original_bytes: originalBytes,
|
|
1657
1841
|
bounded_bytes: boundedBytes,
|
|
1658
1842
|
max_bytes: maxBytes,
|
|
1659
1843
|
reason: "agent_output_byte_limit",
|
|
1660
|
-
shortened_strings: shortenedStrings,
|
|
1661
1844
|
dropped_items: droppedItems,
|
|
1662
1845
|
structure_preserved: true,
|
|
1663
|
-
complete: false
|
|
1846
|
+
complete: false,
|
|
1847
|
+
...pathField
|
|
1664
1848
|
}
|
|
1665
|
-
}
|
|
1849
|
+
},
|
|
1850
|
+
fullOutputPath
|
|
1666
1851
|
};
|
|
1667
1852
|
}
|
|
1668
1853
|
function asRecord(value) {
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
resolvePromptSource,
|
|
14
14
|
safePromptEvidencePath,
|
|
15
15
|
scanHarness
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-he2wb4hd.js";
|
|
17
17
|
import {
|
|
18
18
|
SKILL_SOURCE_HARNESS,
|
|
19
19
|
SKILL_SOURCE_INTEGRATION_BUNDLED,
|
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
import {
|
|
27
27
|
isAuthSessionValid,
|
|
28
28
|
loadAuthSession
|
|
29
|
-
} from "./cli-
|
|
29
|
+
} from "./cli-kxwm7y62.js";
|
|
30
30
|
import {
|
|
31
31
|
CliInputError,
|
|
32
32
|
EXIT_ERROR,
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
resolveTenantId,
|
|
46
46
|
secretFilePathFromRef,
|
|
47
47
|
validateConfig
|
|
48
|
-
} from "./cli-
|
|
48
|
+
} from "./cli-ac3p2byq.js";
|
|
49
49
|
import {
|
|
50
50
|
__commonJS,
|
|
51
51
|
__require,
|
|
@@ -6711,7 +6711,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
|
|
|
6711
6711
|
const analyzedDefinitions = new Map;
|
|
6712
6712
|
if (flags["no-analyze"] !== "true") {
|
|
6713
6713
|
options.onProgress?.("Analyzing prompt sources before sync.");
|
|
6714
|
-
const { analyzeHarnessPrompts } = await import("./harness-
|
|
6714
|
+
const { analyzeHarnessPrompts } = await import("./harness-s13wvdxt.js");
|
|
6715
6715
|
const result = await analyzeHarnessPrompts({
|
|
6716
6716
|
rootDir: process.cwd(),
|
|
6717
6717
|
existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
resolveTenantId,
|
|
26
26
|
shouldInventoryFile,
|
|
27
27
|
stringOption
|
|
28
|
-
} from "./cli-
|
|
28
|
+
} from "./cli-ac3p2byq.js";
|
|
29
29
|
import {
|
|
30
30
|
__commonJS,
|
|
31
31
|
__require,
|
|
@@ -180210,7 +180210,7 @@ function citationExcerpt(rootDir, path, line) {
|
|
|
180210
180210
|
const selected = line ? lines[line - 1] : lines.find((candidate) => candidate.trim().length > 0);
|
|
180211
180211
|
if (!selected)
|
|
180212
180212
|
return {};
|
|
180213
|
-
return { excerpt: selected.trim()
|
|
180213
|
+
return { excerpt: selected.trim() };
|
|
180214
180214
|
} catch {
|
|
180215
180215
|
return {};
|
|
180216
180216
|
}
|
|
@@ -181065,7 +181065,6 @@ function enrichScanCaptureMetadata(graph) {
|
|
|
181065
181065
|
// src/harness-candidates.ts
|
|
181066
181066
|
import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
181067
181067
|
import { basename as basename3, dirname as dirname3, extname, resolve as resolve4 } from "node:path";
|
|
181068
|
-
var EXCERPT_MAX_CHARS = 240;
|
|
181069
181068
|
var MAX_CANDIDATES_PER_FILE_PER_SIGNAL = 20;
|
|
181070
181069
|
var MIN_PROMPT_LITERAL_CHARS = 160;
|
|
181071
181070
|
var CONFIDENCE_WEIGHT = {
|
|
@@ -181311,8 +181310,7 @@ function instructionScore(text) {
|
|
|
181311
181310
|
return score;
|
|
181312
181311
|
}
|
|
181313
181312
|
function normalizeExcerpt(text) {
|
|
181314
|
-
|
|
181315
|
-
return collapsed.length > EXCERPT_MAX_CHARS ? `${collapsed.slice(0, EXCERPT_MAX_CHARS - 1)}…` : collapsed;
|
|
181313
|
+
return text.replace(/\s+/g, " ").trim();
|
|
181316
181314
|
}
|
|
181317
181315
|
function buildLineIndex(text) {
|
|
181318
181316
|
const offsets = [0];
|
|
@@ -181423,7 +181421,7 @@ function detectPromptModule(file, out) {
|
|
|
181423
181421
|
`).length),
|
|
181424
181422
|
confidence: "medium",
|
|
181425
181423
|
signal: "prompt_module.name_hint",
|
|
181426
|
-
excerpt: normalizeExcerpt(file.text
|
|
181424
|
+
excerpt: normalizeExcerpt(file.text)
|
|
181427
181425
|
});
|
|
181428
181426
|
}
|
|
181429
181427
|
function detectPromptLiterals(file, out) {
|
|
@@ -181506,7 +181504,7 @@ function detectPromptFile(file, out) {
|
|
|
181506
181504
|
`).length),
|
|
181507
181505
|
confidence,
|
|
181508
181506
|
signal,
|
|
181509
|
-
excerpt: normalizeExcerpt(file.text
|
|
181507
|
+
excerpt: normalizeExcerpt(file.text)
|
|
181510
181508
|
});
|
|
181511
181509
|
}
|
|
181512
181510
|
function detectPromptLoaderReferences(file, filesByPath, out) {
|
|
@@ -184859,7 +184857,7 @@ async function runHarnessCommand(context) {
|
|
|
184859
184857
|
throw new CliInputError("Focused remote prompt analysis is not supported yet.", "Use local --analyst=claude|codex|cursor|local-scan, or drop --concern for a full remote report.");
|
|
184860
184858
|
}
|
|
184861
184859
|
if (context.flags["github-actions"] === "true") {
|
|
184862
|
-
const { runGithubActionsAnalyze } = await import("./harness-github-actions-
|
|
184860
|
+
const { runGithubActionsAnalyze } = await import("./harness-github-actions-gbty3k66.js");
|
|
184863
184861
|
const result = await runGithubActionsAnalyze(rootDir, {
|
|
184864
184862
|
writeReport: (report2) => {
|
|
184865
184863
|
const normalized = normalizeHarnessReport(report2);
|
|
@@ -186605,6 +186603,7 @@ var CONCERN_CANDIDATE_KINDS = {
|
|
|
186605
186603
|
evals: ["model_config"]
|
|
186606
186604
|
};
|
|
186607
186605
|
var MAX_SEED_CANDIDATES_PER_KIND = 40;
|
|
186606
|
+
var MAX_INLINE_CANDIDATE_EXCERPT_CHARS = 500;
|
|
186608
186607
|
var MAX_SEED_READ_PLAN_FILES = 25;
|
|
186609
186608
|
var SEED_CANDIDATE_KIND_LABELS = {
|
|
186610
186609
|
llm_call_site: "LLM call sites",
|
|
@@ -186644,7 +186643,7 @@ function renderAnalystCandidateLines(report, concern) {
|
|
|
186644
186643
|
const shown = bucket.slice(0, MAX_SEED_CANDIDATES_PER_KIND);
|
|
186645
186644
|
lines.push(`${label} (${bucket.length}${bucket.length > shown.length ? `, showing ${shown.length}` : ""}):`);
|
|
186646
186645
|
for (const candidate of shown) {
|
|
186647
|
-
lines.push(`- ${candidate.path}:${candidate.startLine} [${candidate.signal}] ${candidate.excerpt}`);
|
|
186646
|
+
lines.push(candidate.endLine > candidate.startLine ? `- ${candidate.path}:${candidate.startLine}-${candidate.endLine} [${candidate.signal}] (multi-line span; read lines ${candidate.startLine}-${candidate.endLine} of the file)` : candidate.excerpt.length > MAX_INLINE_CANDIDATE_EXCERPT_CHARS ? `- ${candidate.path}:${candidate.startLine} [${candidate.signal}] (${candidate.excerpt.length}-character match; read line ${candidate.startLine} of the file)` : `- ${candidate.path}:${candidate.startLine} [${candidate.signal}] ${candidate.excerpt}`);
|
|
186648
186647
|
}
|
|
186649
186648
|
}
|
|
186650
186649
|
const readPlan = report.files.slice(0, MAX_SEED_READ_PLAN_FILES);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
authFetch,
|
|
3
3
|
getCachedLoginContext
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-kxwm7y62.js";
|
|
5
5
|
import {
|
|
6
6
|
CliAccessError,
|
|
7
7
|
CliInputError,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
resolveTenantIdFromActiveProfile,
|
|
16
16
|
saveCliConfig,
|
|
17
17
|
writeSecretJsonFile
|
|
18
|
-
} from "./cli-
|
|
18
|
+
} from "./cli-ac3p2byq.js";
|
|
19
19
|
|
|
20
20
|
// src/init/tenant.ts
|
|
21
21
|
import { randomUUID } from "node:crypto";
|