@moda-ai/cli 1.55.22 → 1.55.24
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/{agent-mj622k8s.js → agent-b4tdzy9q.js} +8 -9
- package/dist/{cli-9x9adrtj.js → cli-0wr3483h.js} +1 -1
- package/dist/{cli-a5c9te95.js → cli-7xc585hc.js} +5 -5
- package/dist/{cli-rqk6f6n6.js → cli-9btx12wp.js} +24 -5
- package/dist/cli-9hc5bg2r.js +61 -0
- package/dist/{cli-cehskjde.js → cli-dn91fb56.js} +13 -15
- package/dist/{cli-5ke3xe6y.js → cli-dve50x7p.js} +258 -28
- package/dist/{cli-569hj0bj.js → cli-qvg26twp.js} +5 -4
- package/dist/{cli-033n2mpb.js → cli-qycsmxev.js} +6 -9
- package/dist/{cli-0ef72tqx.js → cli-rt26sbz7.js} +14 -14
- package/dist/{cli-pc5cw7mx.js → cli-vg88mg20.js} +5 -5
- package/dist/{cli-wf7gfa1e.js → cli-y2ty9vtv.js} +8 -10
- package/dist/cli.js +1310 -346
- package/dist/{doctor-mx6jf435.js → doctor-3r19ry92.js} +8 -9
- package/dist/{fix-9fmy6p2x.js → fix-exvxzvtz.js} +6 -7
- package/dist/{harness-github-actions-c826bfxs.js → harness-github-actions-atc5bbkj.js} +5 -6
- package/dist/{harness-xvg6ws6x.js → harness-vzy7n7ea.js} +5 -6
- package/dist/{index-1wbjz3jc.js → index-e1pf1qz2.js} +17 -17
- package/dist/{production-intelligence-dbe9dmc5.js → production-intelligence-c8e0xw3n.js} +17 -16
- package/dist/{profile-commands-kmmd9y86.js → profile-commands-6e2dgv72.js} +7 -48
- package/dist/prompt-source-mcp.js +5 -6
- package/dist/{prompts-1tkhrxkq.js → prompts-cvzt994j.js} +6 -7
- package/dist/{provision-wzttap58.js → provision-q86phh4a.js} +5 -4
- package/dist/{registry-atqyb5fa.js → registry-s2vdsfw8.js} +3 -4
- package/dist/{skills-gejdvjak.js → skills-tadh1jss.js} +5 -6
- package/dist/{sync-57ercmh9.js → sync-g8wtecz1.js} +7 -8
- package/package.json +1 -1
- package/skills/integration/index.json +2 -2
- package/skills/moda-cli/SKILL.md +31 -29
- package/skills/moda-cli/references/commands.md +22 -22
- package/skills/moda-cli/references/dashboard-parity.md +4 -4
- package/skills/moda-cli/references/detections.md +10 -10
- package/skills/moda-cli/references/feedback.md +2 -2
- package/skills/moda-cli/references/output-protocol.md +2 -2
- package/skills/moda-cli/references/production-intelligence.md +10 -10
- package/skills/moda-cli/references/recipes.md +14 -14
- package/skills/moda-cli/references/search-and-traces.md +32 -32
- package/skills/moda-cli/references/signals-and-false-positives.md +29 -29
- package/skills/moda-cli/references/troubleshooting.md +4 -4
- package/dist/cli-7ea02wca.js +0 -30
|
@@ -972,7 +972,7 @@ function trimToolFailureConversations(response, opts) {
|
|
|
972
972
|
const msgIndex = asNumber(asRecord(row.anchor)?.msg_index) ?? asNumber(row.msg_index);
|
|
973
973
|
return {
|
|
974
974
|
...rest,
|
|
975
|
-
...conversationId && msgIndex !== null ? { context_command: `moda
|
|
975
|
+
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex} --window=${TOOL_FAILURE_CONTEXT_RADIUS}` } : {},
|
|
976
976
|
...opts.drop ? {} : { conversation: trimFailureWindow(conversation, TOOL_FAILURE_CONTEXT_RADIUS, msgIndex) },
|
|
977
977
|
..."window" in row ? { window: trimFailureWindow(window, opts.windowRadius ?? TOOL_FAILURE_CONTEXT_RADIUS, msgIndex) } : {}
|
|
978
978
|
};
|
|
@@ -1019,7 +1019,7 @@ function withoutDetectionWindows(response, listKey, windowKey) {
|
|
|
1019
1019
|
const msgIndex = asNumber(asRecord(row.anchor)?.msg_index) ?? frustrationAnchorIndex(row);
|
|
1020
1020
|
return {
|
|
1021
1021
|
...rest,
|
|
1022
|
-
...conversationId && msgIndex !== null ? { context_command: `moda
|
|
1022
|
+
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex} --window=${DETECTION_CONTEXT_RADIUS}` } : {}
|
|
1023
1023
|
};
|
|
1024
1024
|
});
|
|
1025
1025
|
return { ...response, [listKey]: rows };
|
|
@@ -1057,7 +1057,7 @@ function compactProblemDossier(response, problemId) {
|
|
|
1057
1057
|
causal_rationale: row.causal_rationale ?? null,
|
|
1058
1058
|
door: row.door ?? null,
|
|
1059
1059
|
replay_verified: row.replay_verified ?? null,
|
|
1060
|
-
...conversationId && msgIndex !== null ? { context_command: `moda
|
|
1060
|
+
...conversationId && msgIndex !== null ? { context_command: `moda traces get ${shellWord(contextTarget(conversationId))} --msg-index=${msgIndex}` } : {}
|
|
1061
1061
|
};
|
|
1062
1062
|
});
|
|
1063
1063
|
const reportsBlock = asRecord(response.investigation_reports);
|
|
@@ -1095,13 +1095,13 @@ function compactProblemDossier(response, problemId) {
|
|
|
1095
1095
|
reports_has_more: reportsBlock?.has_more === true,
|
|
1096
1096
|
blocks: PROBLEM_COMPACT_OMITTED_BLOCKS.filter((key) => (key in response))
|
|
1097
1097
|
},
|
|
1098
|
-
full_command: `moda
|
|
1098
|
+
full_command: `moda problems get ${id} --full`
|
|
1099
1099
|
};
|
|
1100
1100
|
const nextCommands = [
|
|
1101
|
-
readCommand(`moda
|
|
1102
|
-
readCommand(`moda
|
|
1103
|
-
readCommand(`moda
|
|
1104
|
-
readCommand(`moda
|
|
1101
|
+
readCommand(`moda problems get ${id} --evidence --limit=20`, "Page every evidence row with its anchor (follow next_cursor)."),
|
|
1102
|
+
readCommand(`moda problems get ${id} --reports`, "Page investigation reports with narratives and citations."),
|
|
1103
|
+
readCommand(`moda problems get ${id} --traces`, "Page affected traces with their latest anchor."),
|
|
1104
|
+
readCommand(`moda problems get ${id} --full`, "The complete dossier, every block (large).")
|
|
1105
1105
|
];
|
|
1106
1106
|
const first = topEvidence.find((row) => typeof row.context_command === "string");
|
|
1107
1107
|
if (first?.context_command) {
|
|
@@ -1450,11 +1450,206 @@ function packSnapshot(inputs, opts) {
|
|
|
1450
1450
|
skips
|
|
1451
1451
|
};
|
|
1452
1452
|
}
|
|
1453
|
+
// src/legacy-names.ts
|
|
1454
|
+
var LEGACY_NAMES = [
|
|
1455
|
+
{ legacy: "conversations", use: "moda traces list", canonical: { command: "traces", subcommand: "list" }, silent: true },
|
|
1456
|
+
{ legacy: "search", use: 'moda traces search "<query>"', canonical: { command: "traces", subcommand: "search" } },
|
|
1457
|
+
{ legacy: "context", use: "moda traces get <conversation_id>", canonical: { command: "traces", subcommand: "get" } },
|
|
1458
|
+
{ legacy: "world-state", use: "moda traces state <conversation_id>", canonical: { command: "traces", subcommand: "state" } },
|
|
1459
|
+
{ legacy: "audit", use: "moda traces spans <conversation_id|trace_id>", canonical: { command: "traces", subcommand: "spans" } },
|
|
1460
|
+
{ legacy: "trace", use: "moda traces spans <conversation_id|trace_id>", canonical: { command: "traces", subcommand: "spans" } },
|
|
1461
|
+
{ legacy: "problem", use: "moda problems get <problem_id>", canonical: { command: "problems", subcommand: "get" } },
|
|
1462
|
+
{ legacy: "problems remainder", use: "moda problems unexplained", canonical: { command: "problems", subcommand: "unexplained" } },
|
|
1463
|
+
{ legacy: "problem-impact", use: "moda problems impact", canonical: { command: "problems", subcommand: "impact" } },
|
|
1464
|
+
{ legacy: "problem-feedback", use: "moda problems feedback <problem_id>", canonical: { command: "problems", subcommand: "feedback" } },
|
|
1465
|
+
{ legacy: "problem-reopen", use: "moda problems reopen <problem_id>", canonical: { command: "problems", subcommand: "reopen" } },
|
|
1466
|
+
{ legacy: "problem-linear", use: "moda problems linear <problem_id>", canonical: { command: "problems", subcommand: "linear" } },
|
|
1467
|
+
{ legacy: "problem-linear-file", use: "moda problems link <problem_id>", canonical: { command: "problems", subcommand: "link" } },
|
|
1468
|
+
{ legacy: "emotions", use: "moda detections list --family=emotion[:<family>]", canonical: { command: "detections", subcommand: "list" } },
|
|
1469
|
+
{ legacy: "frustrations", use: "moda detections list --family=frustration", canonical: { command: "detections", subcommand: "list" } },
|
|
1470
|
+
{ legacy: "laziness", use: "moda detections list --family=laziness[:<family>]", canonical: { command: "detections", subcommand: "list" } },
|
|
1471
|
+
{ legacy: "hallucinations", use: "moda detections list --family=hallucination", canonical: { command: "detections", subcommand: "list" } },
|
|
1472
|
+
{ legacy: "tool-failures", use: "moda detections tools", canonical: { command: "detections", subcommand: "tools" } },
|
|
1473
|
+
{ legacy: "tool-failure-detail", use: "moda detections tools <tool_name>", canonical: { command: "detections", subcommand: "tools" } },
|
|
1474
|
+
{ legacy: "signal --detections", use: "moda detections list --family=custom_signal --signal-id=<signal_id>", canonical: { command: "detections", subcommand: "list" } },
|
|
1475
|
+
{ legacy: "trace-signals", use: "moda detections list --family=custom_signal --conversation-id=<conversation_id>", canonical: { command: "detections", subcommand: "list" } },
|
|
1476
|
+
{ legacy: "false-positive", use: "moda review <kind> <target>", canonical: { command: "review" } },
|
|
1477
|
+
{ legacy: "detection-review", use: "moda review problem-detection <problem_id> --verdict=<verdict>", canonical: { command: "review", subcommand: "problem-detection" } },
|
|
1478
|
+
{ legacy: "signal-label", use: "moda review custom-signal <signal_id> --verdict=correct|false_positive", canonical: { command: "review", subcommand: "custom-signal" } },
|
|
1479
|
+
{ legacy: "false-positives", use: "moda reviews list", canonical: { command: "reviews", subcommand: "list" } },
|
|
1480
|
+
{ legacy: "detection-reviews", use: "moda reviews list <conversation_id> --kind=problem-detection", canonical: { command: "reviews", subcommand: "list" } },
|
|
1481
|
+
{ legacy: "skills sync", use: "moda skills push", canonical: { command: "skills", subcommand: "push" }, note: "It uploads local SKILL.md files ('moda sync skills' downloads; that is 'moda skills pull')." },
|
|
1482
|
+
{ legacy: "sync skills", use: "moda skills pull", canonical: { command: "skills", subcommand: "pull" }, note: "It downloads skills, while 'moda skills sync' uploads; use 'moda skills pull' (download) or 'moda skills push' (upload)." }
|
|
1483
|
+
];
|
|
1484
|
+
var byLegacy = new Map(LEGACY_NAMES.map((entry) => [entry.legacy, entry]));
|
|
1485
|
+
var LEGACY_PATTERN = new RegExp(`moda (${[...LEGACY_NAMES.map((entry) => entry.legacy.replace(/ --detections$/, "")), "signal"].filter((name, index, all) => all.indexOf(name) === index).sort((left, right) => right.length - left.length).map((name) => name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})(?![\\w-])`, "g");
|
|
1486
|
+
var WORD = /(?:'[^']*'|"(?:[^"\\]|\\.)*"|\\.|[^\s'"]|['"])+/g;
|
|
1487
|
+
function commandEnd(text, from, opener) {
|
|
1488
|
+
let quote = "";
|
|
1489
|
+
for (let index = from;index < text.length; index += 1) {
|
|
1490
|
+
const char = text[index];
|
|
1491
|
+
const next = text[index + 1] ?? "";
|
|
1492
|
+
if (char === `
|
|
1493
|
+
` || char === "`")
|
|
1494
|
+
return index;
|
|
1495
|
+
if ((opener === '"' || opener === "'") && char === opener && !quote)
|
|
1496
|
+
return index;
|
|
1497
|
+
if (char === '"' || char === "'") {
|
|
1498
|
+
if (!quote)
|
|
1499
|
+
quote = char;
|
|
1500
|
+
else if (quote === char)
|
|
1501
|
+
quote = "";
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
if (quote)
|
|
1505
|
+
continue;
|
|
1506
|
+
if (opener === "(" && char === ")")
|
|
1507
|
+
return index;
|
|
1508
|
+
if (char === "|" || char === ";")
|
|
1509
|
+
return index;
|
|
1510
|
+
if ((char === "," || char === ".") && (next === " " || next === ""))
|
|
1511
|
+
return index;
|
|
1512
|
+
if (char === " " && (next === "(" || next === "#" || text.startsWith("moda ", index + 1) || text.startsWith("&&", index + 1)))
|
|
1513
|
+
return index;
|
|
1514
|
+
}
|
|
1515
|
+
return text.length;
|
|
1516
|
+
}
|
|
1517
|
+
function isPlaceholder(token) {
|
|
1518
|
+
return /^"?<[^>]+>"?$/.test(token);
|
|
1519
|
+
}
|
|
1520
|
+
function quotedArgumentSpans(text) {
|
|
1521
|
+
const spans = [];
|
|
1522
|
+
for (const match of text.matchAll(/moda (?=[a-z])/g)) {
|
|
1523
|
+
const start = match.index ?? 0;
|
|
1524
|
+
if (spans.some(([from, to]) => start > from && start < to))
|
|
1525
|
+
continue;
|
|
1526
|
+
const end = commandEnd(text, start + match[0].length, start > 0 ? text[start - 1] : "");
|
|
1527
|
+
let open = -1;
|
|
1528
|
+
for (let index = start;index < end; index += 1) {
|
|
1529
|
+
const char = text[index];
|
|
1530
|
+
if (char !== '"' && char !== "'")
|
|
1531
|
+
continue;
|
|
1532
|
+
if (open === -1)
|
|
1533
|
+
open = index;
|
|
1534
|
+
else if (text[open] === char) {
|
|
1535
|
+
spans.push([open, index]);
|
|
1536
|
+
open = -1;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
if (open !== -1)
|
|
1540
|
+
spans.push([open, end]);
|
|
1541
|
+
}
|
|
1542
|
+
return spans;
|
|
1543
|
+
}
|
|
1544
|
+
function canonicalInvocation(entry, rest) {
|
|
1545
|
+
let words = [...rest];
|
|
1546
|
+
const takeFlag = (pattern) => {
|
|
1547
|
+
const index = words.findIndex((word2) => pattern.test(word2));
|
|
1548
|
+
if (index === -1)
|
|
1549
|
+
return;
|
|
1550
|
+
const [word] = words.splice(index, 1);
|
|
1551
|
+
return word;
|
|
1552
|
+
};
|
|
1553
|
+
let familySuffix = "";
|
|
1554
|
+
switch (entry.legacy) {
|
|
1555
|
+
case "emotions":
|
|
1556
|
+
case "laziness": {
|
|
1557
|
+
const family = takeFlag(/^--family=/);
|
|
1558
|
+
if (family)
|
|
1559
|
+
familySuffix = `:${family.slice("--family=".length)}`;
|
|
1560
|
+
break;
|
|
1561
|
+
}
|
|
1562
|
+
case "signal --detections":
|
|
1563
|
+
takeFlag(/^--detections(=true)?$/);
|
|
1564
|
+
break;
|
|
1565
|
+
case "false-positive":
|
|
1566
|
+
words = words.map((word) => /^--undo(=true)?$/.test(word) ? "--verdict=clear" : word);
|
|
1567
|
+
break;
|
|
1568
|
+
case "signal-label":
|
|
1569
|
+
words = words.map((word) => word.replace(/^--label=fits$/, "--verdict=correct").replace(/^--label=does_not_fit$/, "--verdict=false_positive").replace(/^--label=.*$/, "--verdict=correct|false_positive"));
|
|
1570
|
+
break;
|
|
1571
|
+
default:
|
|
1572
|
+
break;
|
|
1573
|
+
}
|
|
1574
|
+
const positionals = [];
|
|
1575
|
+
while (words.length > 0 && !words[0].startsWith("-"))
|
|
1576
|
+
positionals.push(words.shift());
|
|
1577
|
+
const out = [];
|
|
1578
|
+
for (const token of entry.use.replace(/\[[^\]]*\]/g, "").split(" ")) {
|
|
1579
|
+
const flag = /^(--[a-z-]+=)(.*)$/.exec(token);
|
|
1580
|
+
if (isPlaceholder(token) || flag && isPlaceholder(flag[2])) {
|
|
1581
|
+
const value = positionals.shift();
|
|
1582
|
+
if (value !== undefined)
|
|
1583
|
+
out.push(flag ? `${flag[1]}${value}` : value);
|
|
1584
|
+
} else if (token.includes("|")) {} else {
|
|
1585
|
+
out.push(token.startsWith("--family=") ? `${token}${familySuffix}` : token);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
return [...out, ...positionals, ...words].join(" ");
|
|
1589
|
+
}
|
|
1590
|
+
function canonicalCommandText(text) {
|
|
1591
|
+
if (!text.includes("moda "))
|
|
1592
|
+
return text;
|
|
1593
|
+
const quoted = quotedArgumentSpans(text);
|
|
1594
|
+
let out = "";
|
|
1595
|
+
let cursor = 0;
|
|
1596
|
+
for (const match of text.matchAll(LEGACY_PATTERN)) {
|
|
1597
|
+
const start = match.index ?? 0;
|
|
1598
|
+
if (start < cursor)
|
|
1599
|
+
continue;
|
|
1600
|
+
if (quoted.some(([from, to]) => start > from && start < to))
|
|
1601
|
+
continue;
|
|
1602
|
+
const afterName = start + match[0].length;
|
|
1603
|
+
const end = text[afterName] === " " ? commandEnd(text, afterName, start > 0 ? text[start - 1] : "") : afterName;
|
|
1604
|
+
const rest = text.slice(afterName, end).match(WORD) ?? [];
|
|
1605
|
+
const name = match[1];
|
|
1606
|
+
const entry = name === "signal" ? rest.some((word) => /^--detections(=true)?$/.test(word)) ? byLegacy.get("signal --detections") : undefined : byLegacy.get(name);
|
|
1607
|
+
if (!entry)
|
|
1608
|
+
continue;
|
|
1609
|
+
out += `${text.slice(cursor, start)}${canonicalInvocation(entry, rest)}`;
|
|
1610
|
+
const trailing = /\s*$/.exec(text.slice(afterName, end))?.[0] ?? "";
|
|
1611
|
+
out += trailing;
|
|
1612
|
+
cursor = end;
|
|
1613
|
+
}
|
|
1614
|
+
return out + text.slice(cursor);
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1453
1617
|
// src/output.ts
|
|
1454
1618
|
import { randomUUID } from "node:crypto";
|
|
1455
1619
|
import { lstatSync, mkdirSync as mkdirSync2, readdirSync, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
|
|
1456
1620
|
import { tmpdir } from "node:os";
|
|
1457
1621
|
import { join as join2 } from "node:path";
|
|
1622
|
+
var SUGGESTION_KEY = /(_commands?|^hints?|^suggestions?)$/i;
|
|
1623
|
+
function canonicalDeep(value, rewriteStrings) {
|
|
1624
|
+
if (typeof value === "string")
|
|
1625
|
+
return rewriteStrings ? canonicalCommandText(value) : value;
|
|
1626
|
+
if (Array.isArray(value)) {
|
|
1627
|
+
let changed2 = false;
|
|
1628
|
+
const next = value.map((item) => {
|
|
1629
|
+
const rewritten = canonicalDeep(item, rewriteStrings);
|
|
1630
|
+
if (rewritten !== item)
|
|
1631
|
+
changed2 = true;
|
|
1632
|
+
return rewritten;
|
|
1633
|
+
});
|
|
1634
|
+
return changed2 ? next : value;
|
|
1635
|
+
}
|
|
1636
|
+
if (value === null || typeof value !== "object")
|
|
1637
|
+
return value;
|
|
1638
|
+
let changed = false;
|
|
1639
|
+
const entries = Object.entries(value).map(([key, entry]) => {
|
|
1640
|
+
const rewritten = canonicalDeep(entry, rewriteStrings || SUGGESTION_KEY.test(key));
|
|
1641
|
+
if (rewritten !== entry)
|
|
1642
|
+
changed = true;
|
|
1643
|
+
return [key, rewritten];
|
|
1644
|
+
});
|
|
1645
|
+
return changed ? Object.fromEntries(entries) : value;
|
|
1646
|
+
}
|
|
1647
|
+
function canonicalSuggestionFields(value) {
|
|
1648
|
+
return canonicalDeep(value, false);
|
|
1649
|
+
}
|
|
1650
|
+
function canonicalSuggestions(value) {
|
|
1651
|
+
return canonicalDeep(value, true);
|
|
1652
|
+
}
|
|
1458
1653
|
var agentUpdateNotice;
|
|
1459
1654
|
function setAgentUpdateNotice(notice) {
|
|
1460
1655
|
agentUpdateNotice = notice;
|
|
@@ -1608,6 +1803,8 @@ function resolveOutputMode(flags, opts = {}) {
|
|
|
1608
1803
|
return "human";
|
|
1609
1804
|
}
|
|
1610
1805
|
function createCliOutput(options) {
|
|
1806
|
+
const deprecatedMeta = options.deprecation ? { deprecated: { legacy: options.deprecation.legacy, use: options.deprecation.use } } : {};
|
|
1807
|
+
const deprecationWarnings = options.deprecation ? [options.deprecation.message] : [];
|
|
1611
1808
|
const state = {
|
|
1612
1809
|
runId: options.runId ?? randomUUID(),
|
|
1613
1810
|
seq: 0,
|
|
@@ -1657,6 +1854,7 @@ function createCliOutput(options) {
|
|
|
1657
1854
|
data,
|
|
1658
1855
|
meta: {
|
|
1659
1856
|
...writeOptions.meta ?? {},
|
|
1857
|
+
...deprecatedMeta,
|
|
1660
1858
|
run_id: state.runId,
|
|
1661
1859
|
...options.command === "feedback" ? {} : { tip: FEEDBACK_TIP },
|
|
1662
1860
|
...((update) => update ? { update } : {})(resolveAgentUpdateNotice())
|
|
@@ -1668,6 +1866,7 @@ function createCliOutput(options) {
|
|
|
1668
1866
|
nextCommands: writeOptions.nextCommands,
|
|
1669
1867
|
artifacts: writeOptions.artifacts,
|
|
1670
1868
|
warnings: writeOptions.warnings,
|
|
1869
|
+
extraWarnings: deprecationWarnings,
|
|
1671
1870
|
errors: writeOptions.errors,
|
|
1672
1871
|
invocation: options.invocation
|
|
1673
1872
|
});
|
|
@@ -1706,10 +1905,10 @@ function createCliOutput(options) {
|
|
|
1706
1905
|
}
|
|
1707
1906
|
return;
|
|
1708
1907
|
}
|
|
1709
|
-
safeWriteStdout(`${JSON.stringify(redactDeep(data), null, 2)}
|
|
1908
|
+
safeWriteStdout(`${JSON.stringify(canonicalSuggestionFields(redactDeep(data)), null, 2)}
|
|
1710
1909
|
`);
|
|
1711
1910
|
for (const warning of writeOptions.warnings ?? []) {
|
|
1712
|
-
safeWriteStderr(`Warning: ${warning}
|
|
1911
|
+
safeWriteStderr(`Warning: ${canonicalCommandText(warning)}
|
|
1713
1912
|
`);
|
|
1714
1913
|
}
|
|
1715
1914
|
},
|
|
@@ -1718,6 +1917,7 @@ function createCliOutput(options) {
|
|
|
1718
1917
|
return;
|
|
1719
1918
|
if (options.mode !== "agent-stream")
|
|
1720
1919
|
return;
|
|
1920
|
+
event = canonicalSuggestions(event);
|
|
1721
1921
|
if (event.event === "started") {
|
|
1722
1922
|
startHeartbeat(options.command, state);
|
|
1723
1923
|
emitEvent(event);
|
|
@@ -1729,8 +1929,8 @@ function createCliOutput(options) {
|
|
|
1729
1929
|
writeError(error) {
|
|
1730
1930
|
if (state.terminal)
|
|
1731
1931
|
return;
|
|
1732
|
-
const agentError = errorToAgentError(error);
|
|
1733
|
-
const envelope = createAgentErrorEnvelope(options.command || "unknown", agentError, state.runId, errorWarnings(error));
|
|
1932
|
+
const agentError = canonicalSuggestions(errorToAgentError(error));
|
|
1933
|
+
const envelope = createAgentErrorEnvelope(options.command || "unknown", agentError, state.runId, errorWarnings(error), options.deprecation ? deprecatedMeta : undefined, deprecationWarnings);
|
|
1734
1934
|
if (options.mode === "agent-stream") {
|
|
1735
1935
|
ensureStarted({ bypassQuiet: true });
|
|
1736
1936
|
if (error instanceof CliInputRequiredError) {
|
|
@@ -1796,7 +1996,7 @@ function createCliOutput(options) {
|
|
|
1796
1996
|
return output;
|
|
1797
1997
|
}
|
|
1798
1998
|
function createAgentEnvelope(options) {
|
|
1799
|
-
const safeData = redactDeep(options.data);
|
|
1999
|
+
const safeData = canonicalSuggestionFields(redactDeep(options.data));
|
|
1800
2000
|
const maxBytes = agentMaxOutputBytes();
|
|
1801
2001
|
let fullOutput;
|
|
1802
2002
|
let saveFailed = false;
|
|
@@ -1808,13 +2008,16 @@ function createAgentEnvelope(options) {
|
|
|
1808
2008
|
return fullOutput.path;
|
|
1809
2009
|
};
|
|
1810
2010
|
let text = redactDeep({
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
2011
|
+
...canonicalSuggestions({
|
|
2012
|
+
summary: normalizeSummary(options.summary, options.command, options.status, safeData),
|
|
2013
|
+
findings: options.findings ?? [],
|
|
2014
|
+
evidence_refs: options.evidenceRefs ?? [],
|
|
2015
|
+
recommended_actions: options.recommendedActions ?? [],
|
|
2016
|
+
next_commands: normalizeNextCommands(options.nextCommands ?? [])
|
|
2017
|
+
}),
|
|
2018
|
+
warnings: [...canonicalSuggestions(options.warnings ?? inferWarnings(safeData)), ...options.extraWarnings ?? []]
|
|
1817
2019
|
});
|
|
2020
|
+
const errors = canonicalSuggestions(options.errors ?? []);
|
|
1818
2021
|
let moved;
|
|
1819
2022
|
const build = (bounded) => ({
|
|
1820
2023
|
schema_version: AGENT_SCHEMA_VERSION,
|
|
@@ -1826,7 +2029,7 @@ function createAgentEnvelope(options) {
|
|
|
1826
2029
|
findings: text.findings,
|
|
1827
2030
|
evidence_refs: text.evidence_refs,
|
|
1828
2031
|
recommended_actions: text.recommended_actions,
|
|
1829
|
-
next_commands: [...text.next_commands, ...bounded.nextCommands ?? []],
|
|
2032
|
+
next_commands: [...text.next_commands, ...canonicalSuggestions(bounded.nextCommands ?? [])],
|
|
1830
2033
|
artifacts: [
|
|
1831
2034
|
...options.artifacts ?? [],
|
|
1832
2035
|
...bounded.fullOutputPath ? [{ kind: "full_output", path: bounded.fullOutputPath, description: "Complete command output (the same JSON --json prints); data in this envelope was bounded." }] : [],
|
|
@@ -1834,10 +2037,10 @@ function createAgentEnvelope(options) {
|
|
|
1834
2037
|
],
|
|
1835
2038
|
warnings: [
|
|
1836
2039
|
...text.warnings,
|
|
1837
|
-
...bounded.warning ? [bounded.warning] : [],
|
|
2040
|
+
...bounded.warning ? [canonicalCommandText(bounded.warning)] : [],
|
|
1838
2041
|
...moved ? [movedTextWarning(moved)] : []
|
|
1839
2042
|
],
|
|
1840
|
-
errors
|
|
2043
|
+
errors,
|
|
1841
2044
|
data: bounded.data,
|
|
1842
2045
|
...options.meta ? { meta: options.meta } : {},
|
|
1843
2046
|
...bounded.truncation || moved ? { truncation: {
|
|
@@ -1996,13 +2199,14 @@ function errorWarnings(error) {
|
|
|
1996
2199
|
const warnings = error?.warnings;
|
|
1997
2200
|
return Array.isArray(warnings) && warnings.length ? warnings.filter((w) => typeof w === "string") : undefined;
|
|
1998
2201
|
}
|
|
1999
|
-
function createAgentErrorEnvelope(command, error, runId, warnings) {
|
|
2202
|
+
function createAgentErrorEnvelope(command, error, runId, warnings, meta, extraWarnings) {
|
|
2000
2203
|
return createAgentEnvelope({
|
|
2001
2204
|
command,
|
|
2002
2205
|
status: "error",
|
|
2003
2206
|
data: null,
|
|
2004
2207
|
warnings: warnings ?? [],
|
|
2005
|
-
|
|
2208
|
+
...extraWarnings?.length ? { extraWarnings } : {},
|
|
2209
|
+
meta: runId || meta ? { ...meta ?? {}, ...runId ? { run_id: runId } : {} } : undefined,
|
|
2006
2210
|
summary: {
|
|
2007
2211
|
text: error.message,
|
|
2008
2212
|
confidence: "high"
|
|
@@ -2423,7 +2627,7 @@ function continuationCommand(invocation, overrides) {
|
|
|
2423
2627
|
}
|
|
2424
2628
|
for (const [key, value] of Object.entries(overrides))
|
|
2425
2629
|
parts.push(`--${normalize2(key)}=${shellWord(String(value))}`);
|
|
2426
|
-
return parts.join(" ");
|
|
2630
|
+
return canonicalCommandText(parts.join(" "));
|
|
2427
2631
|
}
|
|
2428
2632
|
var PAGED_LIST_BY_COMMAND = {
|
|
2429
2633
|
"tool-failure-detail": "examples",
|
|
@@ -2432,8 +2636,9 @@ var PAGED_LIST_BY_COMMAND = {
|
|
|
2432
2636
|
"problems remainder": "groups"
|
|
2433
2637
|
};
|
|
2434
2638
|
function pagedListFor(invocation) {
|
|
2435
|
-
const
|
|
2436
|
-
|
|
2639
|
+
const { command, positionals } = invocation.routedAs ?? invocation;
|
|
2640
|
+
const subcommand = positionals[0];
|
|
2641
|
+
return (subcommand !== undefined ? PAGED_LIST_BY_COMMAND[`${command} ${subcommand}`] : undefined) ?? PAGED_LIST_BY_COMMAND[command];
|
|
2437
2642
|
}
|
|
2438
2643
|
var MAX_PAGE_OFFSET = 1e4;
|
|
2439
2644
|
function rewritePagination(list, isTopLevel, invocation) {
|
|
@@ -2622,4 +2827,29 @@ function extractSuggestedCommands(text) {
|
|
|
2622
2827
|
return commands.length > 0 ? commands : undefined;
|
|
2623
2828
|
}
|
|
2624
2829
|
|
|
2625
|
-
|
|
2830
|
+
// src/api-key-headers.ts
|
|
2831
|
+
var PLATFORM_API_KEY_PREFIX = "moda_pk_";
|
|
2832
|
+
var TENANT_HEADER = "x-moda-tenant-id";
|
|
2833
|
+
function isPlatformApiKey(key) {
|
|
2834
|
+
return Boolean(key?.startsWith(PLATFORM_API_KEY_PREFIX));
|
|
2835
|
+
}
|
|
2836
|
+
var platformTenantOverride;
|
|
2837
|
+
function setPlatformTenantOverride(tenantId) {
|
|
2838
|
+
platformTenantOverride = tenantId;
|
|
2839
|
+
}
|
|
2840
|
+
var TENANT_PATH = /\/tenants\/([^/?#]+)/;
|
|
2841
|
+
function tenantFromUrl(url) {
|
|
2842
|
+
const match = url ? TENANT_PATH.exec(url) : null;
|
|
2843
|
+
return match ? decodeURIComponent(match[1]) : undefined;
|
|
2844
|
+
}
|
|
2845
|
+
function apiKeyHeaders(key, options = {}, url) {
|
|
2846
|
+
const headers = { "x-api-key": key };
|
|
2847
|
+
if (isPlatformApiKey(key)) {
|
|
2848
|
+
const tenantId = tenantFromUrl(url) || platformTenantOverride || resolveTenantId(options);
|
|
2849
|
+
if (tenantId)
|
|
2850
|
+
headers[TENANT_HEADER] = tenantId;
|
|
2851
|
+
}
|
|
2852
|
+
return headers;
|
|
2853
|
+
}
|
|
2854
|
+
|
|
2855
|
+
export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, attachInputDetails, inputDetailsOf, CliAccessError, CliInputRequiredError, CliAuthError, CliNotFoundError, CliCancellationError, isNetworkLikeError, isApiLikeError, apiErrorStatus, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, recordApiRequest, getApiRequestCount, resetApiRequestCount, BATCH_MAX_TARGETS, BATCH_CONCURRENCY, parseBatchTarget, collectBatchTargets, mapWithConcurrency, contextTarget, asRecord, asString, asNumber, frustrationAnchorIndex, frustrationsFromEmotions, withFrustrationAnchors, shellWord, trimToolFailureConversations, withToolFailureAnchors, embeddedWindowSize, withoutDetectionWindows, compactProblemDossier, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, LEGACY_NAMES, canonicalCommandText, setAgentUpdateNotice, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, outputModeFromFlags, resolveOutputMode, createCliOutput, agentEnvelopeFits, errorToAgentError, agentMaxOutputBytes };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createCliOutput,
|
|
3
3
|
outputModeFromFlags
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-dve50x7p.js";
|
|
5
5
|
|
|
6
6
|
// src/command-context.ts
|
|
7
7
|
function flagEnabled(flags, key) {
|
|
@@ -48,15 +48,16 @@ function createCommandContext(input, options = {}) {
|
|
|
48
48
|
env: options.env ?? process.env,
|
|
49
49
|
outputMode,
|
|
50
50
|
output: createCliOutput({
|
|
51
|
-
command: options.commandName ?? input.command,
|
|
51
|
+
command: options.outputCommand ?? options.commandName ?? input.command,
|
|
52
52
|
mode: outputMode,
|
|
53
53
|
quiet,
|
|
54
|
-
invocation: {
|
|
54
|
+
invocation: options.invocation ?? {
|
|
55
55
|
command: options.commandName ?? input.command,
|
|
56
56
|
positionals: input.positionals,
|
|
57
57
|
flags: rawFlags,
|
|
58
58
|
...input.bareFlags ? { bareFlags: input.bareFlags } : {}
|
|
59
|
-
}
|
|
59
|
+
},
|
|
60
|
+
...options.deprecation ? { deprecation: options.deprecation } : {}
|
|
60
61
|
}),
|
|
61
62
|
profile: flags.profile,
|
|
62
63
|
dryRun: flagEnabled(flags, "dry-run"),
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
fetchApiKeyProbe
|
|
3
|
+
} from "./cli-9hc5bg2r.js";
|
|
1
4
|
import {
|
|
2
5
|
authFetch,
|
|
3
6
|
getCachedLoginContext
|
|
4
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-0wr3483h.js";
|
|
5
8
|
import {
|
|
6
9
|
CliAccessError,
|
|
7
10
|
CliInputError,
|
|
@@ -9,14 +12,13 @@ import {
|
|
|
9
12
|
embeddedTenantIdFromApiKey,
|
|
10
13
|
getModaDir,
|
|
11
14
|
loadCliConfig,
|
|
12
|
-
recordApiRequest,
|
|
13
15
|
resolveApiKeyFromActiveProfile,
|
|
14
16
|
resolveIngestUrl,
|
|
15
17
|
resolveModaBaseUrl,
|
|
16
18
|
resolveTenantIdFromActiveProfile,
|
|
17
19
|
saveCliConfig,
|
|
18
20
|
writeSecretJsonFile
|
|
19
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-dve50x7p.js";
|
|
20
22
|
|
|
21
23
|
// src/init/tenant.ts
|
|
22
24
|
import { randomUUID } from "node:crypto";
|
|
@@ -115,12 +117,7 @@ function bootstrapLabel(custom) {
|
|
|
115
117
|
var embeddedTenantId = embeddedTenantIdFromApiKey;
|
|
116
118
|
async function isStoredKeyLive(key, options = {}) {
|
|
117
119
|
try {
|
|
118
|
-
|
|
119
|
-
const response = await fetch(`${resolveModaBaseUrl(options)}/api/v1/data/overview`, {
|
|
120
|
-
method: "GET",
|
|
121
|
-
headers: { "x-api-key": key },
|
|
122
|
-
signal: AbortSignal.timeout(VALIDATE_TIMEOUT_MS)
|
|
123
|
-
});
|
|
120
|
+
const response = await fetchApiKeyProbe(resolveModaBaseUrl(options), { "x-api-key": key }, VALIDATE_TIMEOUT_MS);
|
|
124
121
|
if (response.status !== 200)
|
|
125
122
|
return false;
|
|
126
123
|
await response.json();
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createCommandContext
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-qvg26twp.js";
|
|
4
4
|
import {
|
|
5
5
|
assertFlags,
|
|
6
6
|
assertPositionals
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-dn91fb56.js";
|
|
8
8
|
import {
|
|
9
9
|
callControlAPI
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-9btx12wp.js";
|
|
11
11
|
import {
|
|
12
12
|
CliInputError,
|
|
13
13
|
recordApiRequest,
|
|
14
14
|
resolveApiKey,
|
|
15
15
|
resolveIngestUrl,
|
|
16
16
|
resolveTenantId
|
|
17
|
-
} from "./cli-
|
|
17
|
+
} from "./cli-dve50x7p.js";
|
|
18
18
|
import {
|
|
19
19
|
SKILL_SOURCE_HARNESS,
|
|
20
20
|
SKILL_SOURCE_INTEGRATION_BUNDLED,
|
|
@@ -56,16 +56,16 @@ function renderFixesBlock() {
|
|
|
56
56
|
"The `moda` CLI needs `MODA_API_KEY` (or `npx -y -p @moda-ai/cli moda ...` when",
|
|
57
57
|
"not installed); `moda <command> --help` lists its flags.",
|
|
58
58
|
"",
|
|
59
|
-
'- Find where something happened in production: `moda search "<words>"`, then',
|
|
60
|
-
" `moda
|
|
59
|
+
'- Find where something happened in production: `moda traces search "<words>"`, then',
|
|
60
|
+
" `moda traces get <conversation_id> --msg-index=<message_index>` to read the turn.",
|
|
61
61
|
"- Find what to fix: `moda investigate` ranks tool failures, user frustrations,",
|
|
62
62
|
" and top Problems with evidence; `moda problems` ranks cross-signal Problems",
|
|
63
63
|
" by root cause; `moda failures` lists tool failures only.",
|
|
64
|
-
"- Read the evidence before editing: `moda
|
|
65
|
-
" `moda
|
|
66
|
-
" `moda
|
|
67
|
-
" `moda
|
|
68
|
-
" `moda
|
|
64
|
+
"- Read the evidence before editing: `moda problems get <problem_id>` (dossier),",
|
|
65
|
+
" `moda problems get <problem_id> --evidence` (attribution rationales and anchors),",
|
|
66
|
+
" `moda problems get <problem_id> --traces` (affected traces),",
|
|
67
|
+
" `moda detections tools <tool_name>` (failing calls in context), and",
|
|
68
|
+
" `moda traces get <conversation_id>` (the messages around a turn; `--all` for",
|
|
69
69
|
" the whole trace).",
|
|
70
70
|
"- Propose the change in the code, prompt, tool definition, or skill that",
|
|
71
71
|
" causes the issue, and cite the Moda problem or trace ids it is based on",
|
|
@@ -74,7 +74,7 @@ function renderFixesBlock() {
|
|
|
74
74
|
" `sources:` mappings for prompts defined in code); after `moda prompts sync`,",
|
|
75
75
|
" pass `prompt: lock.prompts['<key>']` to createThinkTelemetry/createAI7Telemetry.",
|
|
76
76
|
"- After the fix ships, record it with",
|
|
77
|
-
" `moda
|
|
77
|
+
" `moda problems feedback <problem_id> --action=mark_fixed`; if the issue",
|
|
78
78
|
" is detected again, the Problem comes back.",
|
|
79
79
|
FIXES_BLOCK_END
|
|
80
80
|
].join(`
|
|
@@ -111,7 +111,7 @@ function upsertManagedBlock(existing, block) {
|
|
|
111
111
|
const problem = begins === 1 && ends === 1 ? `its ${FIXES_BLOCK_END} marker comes before its ${FIXES_BLOCK_BEGIN} marker` : `it has ${begins} ${FIXES_BLOCK_BEGIN} and ${ends} ${FIXES_BLOCK_END} marker(s) instead of one of each`;
|
|
112
112
|
return {
|
|
113
113
|
ok: false,
|
|
114
|
-
reason: `The Moda block in ${AGENTS_MD_FILENAME} was not updated because ${problem}. ` + "The file was left unchanged so no text is lost. Keep exactly one begin marker followed by one end marker " + "(or delete the stray markers), then rerun `moda skills
|
|
114
|
+
reason: `The Moda block in ${AGENTS_MD_FILENAME} was not updated because ${problem}. ` + "The file was left unchanged so no text is lost. Keep exactly one begin marker followed by one end marker " + "(or delete the stray markers), then rerun `moda skills push`."
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
function writeFileIfChanged(filePath, content) {
|
|
@@ -757,7 +757,7 @@ async function runSkillsCommand(input) {
|
|
|
757
757
|
return runSkillsInstall(context, positionals.slice(1));
|
|
758
758
|
}
|
|
759
759
|
if (sub !== "pull") {
|
|
760
|
-
throw new CliInputError(sub ? `Unknown skills subcommand '${sub}'` : "A skills subcommand is required", "Usage: moda skills gen [--source=all|sdk] [--max-sessions=N (default 200)] [--lookback-hours=N (default 720)] [--max-traces=N] [--improvement-rounds=1-3] [--start-at=ISO] [--end-at=ISO] [--replay] [--replay-set-id=ID] [--reprocess-segments] [--force-reprocess] [--wait] | moda skills status [run-id] | moda skills proposals list [--status=ready_for_pr] | moda skills proposal apply <proposal-id> | moda skills pull [--status=approved|proposed|all] | moda skills
|
|
760
|
+
throw new CliInputError(sub ? `Unknown skills subcommand '${sub}'` : "A skills subcommand is required", "Usage: moda skills gen [--source=all|sdk] [--max-sessions=N (default 200)] [--lookback-hours=N (default 720)] [--max-traces=N] [--improvement-rounds=1-3] [--start-at=ISO] [--end-at=ISO] [--replay] [--replay-set-id=ID] [--reprocess-segments] [--force-reprocess] [--wait] | moda skills status [run-id] | moda skills proposals list [--status=ready_for_pr] | moda skills proposal apply <proposal-id> | moda skills pull [--status=approved|proposed|all] | moda skills push [--dry-run] | moda skills install [--list] <id...>");
|
|
761
761
|
}
|
|
762
762
|
const status = (flags.status ?? "approved").toLowerCase();
|
|
763
763
|
if (!VALID_STATUSES.has(status)) {
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isAuthSessionValid,
|
|
3
3
|
loadAuthSession
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-0wr3483h.js";
|
|
5
5
|
import {
|
|
6
6
|
inspectPromptManifest
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-y2ty9vtv.js";
|
|
8
8
|
import {
|
|
9
9
|
readHarnessSyncState,
|
|
10
10
|
renderDoctorHuman,
|
|
11
11
|
renderStatusHuman,
|
|
12
12
|
scanHarness
|
|
13
|
-
} from "./cli-
|
|
13
|
+
} from "./cli-7xc585hc.js";
|
|
14
14
|
import {
|
|
15
15
|
callDataAPI
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-9btx12wp.js";
|
|
17
17
|
import {
|
|
18
18
|
ensureSecretFilePermissions,
|
|
19
19
|
getActiveProfile,
|
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
resolveSecretReference,
|
|
28
28
|
resolveTenantId,
|
|
29
29
|
secretFilePathFromRef
|
|
30
|
-
} from "./cli-
|
|
30
|
+
} from "./cli-dve50x7p.js";
|
|
31
31
|
|
|
32
32
|
// src/doctor.ts
|
|
33
33
|
import { createHash } from "node:crypto";
|