@moda-ai/cli 1.55.39 → 1.55.41

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.
Files changed (38) hide show
  1. package/dist/{agent-bhe95ae8.js → agent-ck6y31n2.js} +8 -8
  2. package/dist/{cli-qzag917n.js → cli-0xc5htv7.js} +1 -1
  3. package/dist/{cli-39617gab.js → cli-1z1sx8dg.js} +3 -3
  4. package/dist/{cli-jmbt1hf9.js → cli-4tg0hkbz.js} +8 -8
  5. package/dist/{cli-4hkesrkq.js → cli-77ekrx7d.js} +1 -1
  6. package/dist/{cli-6gtgm2gx.js → cli-7bn406mt.js} +4 -4
  7. package/dist/{cli-msgp78ag.js → cli-a8nxbtpk.js} +5 -5
  8. package/dist/{cli-c7vj8tq1.js → cli-azage7s0.js} +5 -5
  9. package/dist/{cli-2h2nvq6w.js → cli-daqkdnm1.js} +1 -1
  10. package/dist/{cli-k9se46y4.js → cli-f1jfrqgf.js} +21 -4
  11. package/dist/{cli-1vqq24qh.js → cli-gt3yq1y5.js} +2 -2
  12. package/dist/{cli-ptm7pwqg.js → cli-pmzh2qjy.js} +1 -1
  13. package/dist/{cli-wr6f0kyw.js → cli-t0pb7qbs.js} +1 -0
  14. package/dist/{cli-jkza0bj6.js → cli-xddtv3yn.js} +1 -1
  15. package/dist/{cli-as4c1xwm.js → cli-ypqwcf9n.js} +5 -5
  16. package/dist/cli.js +313 -26
  17. package/dist/{doctor-3v20hc26.js → doctor-p8sp6cbk.js} +7 -7
  18. package/dist/{fix-s3zkjt69.js → fix-0r974yge.js} +4 -4
  19. package/dist/{harness-n4569wbm.js → harness-72ejenza.js} +5 -5
  20. package/dist/{harness-github-actions-mcy21e4d.js → harness-github-actions-2qc4gg2w.js} +5 -5
  21. package/dist/{index-2qm3h7v2.js → index-w7v472w4.js} +11 -11
  22. package/dist/{production-intelligence-z2cad1hv.js → production-intelligence-e5vsc6cw.js} +143 -30
  23. package/dist/{profile-commands-7ck1tqfv.js → profile-commands-se9947c1.js} +3 -3
  24. package/dist/{prompt-attribution-dm50am6e.js → prompt-attribution-3987hhqz.js} +5 -5
  25. package/dist/prompt-source-mcp.js +5 -5
  26. package/dist/{prompts-ab-9e0dsmce.js → prompts-ab-gmd10n5d.js} +7 -7
  27. package/dist/{prompts-propose-91qrjpd0.js → prompts-propose-q626zmm4.js} +7 -7
  28. package/dist/{prompts-p9hhxx0c.js → prompts-ysm9ra72.js} +5 -5
  29. package/dist/{provision-x4wkyw60.js → provision-cya5rpxa.js} +5 -5
  30. package/dist/{registry-nq8qsqtv.js → registry-7xz09ry0.js} +3 -3
  31. package/dist/{skills-rk2pmwx8.js → skills-x6yszxxn.js} +5 -5
  32. package/dist/{sync-xxbfjcz5.js → sync-trjzvam9.js} +7 -7
  33. package/package.json +1 -1
  34. package/skills/integration/index.json +2 -2
  35. package/skills/moda-cli/SKILL.md +8 -4
  36. package/skills/moda-cli/references/commands.md +1 -0
  37. package/skills/moda-cli/references/detections.md +29 -0
  38. package/skills/moda-cli/references/production-intelligence.md +5 -1
package/dist/cli.js CHANGED
@@ -13,6 +13,8 @@ import {
13
13
  frustrationsFromEmotions,
14
14
  mapWithConcurrency,
15
15
  parseBatchTarget,
16
+ parseTargetLines,
17
+ readIdsFrom,
16
18
  shapeToolCatalogDetail,
17
19
  toolCatalogGetCommand,
18
20
  toolFailureExamplesCommand,
@@ -20,7 +22,7 @@ import {
20
22
  withFrustrationAnchors,
21
23
  withToolFailureAnchors,
22
24
  withoutDetectionWindows
23
- } from "./cli-1vqq24qh.js";
25
+ } from "./cli-gt3yq1y5.js";
24
26
  import {
25
27
  createCommandContext,
26
28
  envOptOutSet,
@@ -28,7 +30,7 @@ import {
28
30
  optOutFlagSet,
29
31
  parseBooleanFlagValue,
30
32
  withoutFlag
31
- } from "./cli-jkza0bj6.js";
33
+ } from "./cli-xddtv3yn.js";
32
34
  import {
33
35
  AuditSchema,
34
36
  BOOK_PROBLEM_SORTS,
@@ -41,6 +43,7 @@ import {
41
43
  FEEDBACK_USAGE,
42
44
  FalsePositiveSchema,
43
45
  LAZINESS_FAMILIES,
46
+ MAX_CONVERSATION_IDS_FILTER,
44
47
  PROBLEMS_DEFAULT_LIMIT,
45
48
  PROBLEMS_MAX_LIMIT,
46
49
  PROBLEM_FEEDBACK_ACTIONS,
@@ -52,6 +55,7 @@ import {
52
55
  SignalLabelSchema,
53
56
  StepScoresSchema,
54
57
  TRACE_GRAIN_FLAGS,
58
+ TraceFindingsSchema,
55
59
  UUID_RE,
56
60
  assertFlags,
57
61
  assertPositionals,
@@ -75,12 +79,12 @@ import {
75
79
  unknownSignalsSubcommandError,
76
80
  usageLine,
77
81
  writeDryRun
78
- } from "./cli-k9se46y4.js";
82
+ } from "./cli-f1jfrqgf.js";
79
83
  import {
80
84
  ApiError,
81
85
  callControlAPI,
82
86
  callDataAPI
83
- } from "./cli-qzag917n.js";
87
+ } from "./cli-0xc5htv7.js";
84
88
  import {
85
89
  AGENT_ERROR_CODES,
86
90
  EXIT_AUTH_REQUIRED,
@@ -117,7 +121,7 @@ import {
117
121
  shellArg,
118
122
  validateConfig,
119
123
  wasOutputCancelled
120
- } from "./cli-wr6f0kyw.js";
124
+ } from "./cli-t0pb7qbs.js";
121
125
  import {
122
126
  CliAccessError,
123
127
  CliAuthError,
@@ -140,6 +144,175 @@ import {
140
144
  import { randomUUID as randomUUID3 } from "node:crypto";
141
145
  import { z } from "zod";
142
146
 
147
+ // src/trace-findings.ts
148
+ var FINDINGS_FAMILIES = ["emotion", "laziness", "hallucination", "tool_failure", "custom_signal"];
149
+ var FINDINGS_DEFAULT_LIMIT = 3;
150
+ var NEXT_COMMANDS_SINGLE = 8;
151
+ var NEXT_COMMANDS_BATCH = 2;
152
+ var TEXT_CHARS = 160;
153
+ function familyState(entry) {
154
+ const count = asNumber(entry.count) ?? 0;
155
+ if (count > 0)
156
+ return "found";
157
+ const enabled = asRecord(entry.detector)?.enabled;
158
+ if (enabled === false || entry.processed === false)
159
+ return "not_run";
160
+ if (entry.processed === true)
161
+ return "none";
162
+ return "unknown";
163
+ }
164
+ function clip(value, max = TEXT_CHARS) {
165
+ const text = asString(value);
166
+ if (!text)
167
+ return;
168
+ return text.length <= max ? text : `${text.slice(0, max - 3)}...`;
169
+ }
170
+ function stripUndefined(row) {
171
+ return Object.fromEntries(Object.entries(row).filter(([, value]) => value !== undefined && value !== ""));
172
+ }
173
+ function compactRow(family, row) {
174
+ const msgIndex = asNumber(row.msg_index);
175
+ switch (family) {
176
+ case "emotion": {
177
+ const quote = asRecord(Array.isArray(row.user_quotes) ? row.user_quotes[0] : undefined);
178
+ return stripUndefined({
179
+ msg_index: msgIndex,
180
+ family: row.family,
181
+ polarity: row.polarity,
182
+ score: row.score,
183
+ trajectory: row.trajectory,
184
+ cause: clip(row.primary_cause),
185
+ quote: clip(quote?.quote)
186
+ });
187
+ }
188
+ case "laziness":
189
+ return stripUndefined({ msg_index: msgIndex, family: row.family, pattern: row.pattern_id, confidence: row.confidence, snippet: clip(row.snippet) });
190
+ case "hallucination":
191
+ return stripUndefined({ msg_index: msgIndex, rule: row.rule_id, confidence: row.confidence, claim: clip(row.offending_substring), evidence: clip(row.evidence_quote) });
192
+ case "tool_failure":
193
+ return stripUndefined({ msg_index: msgIndex, tool: row.tool_name, tool_use_id: row.tool_use_id, category: row.category, error: clip(row.error_message) });
194
+ case "custom_signal":
195
+ return stripUndefined({ msg_index: msgIndex, signal: row.signal_name, signal_id: row.signal_id, confidence: row.confidence, rationale: clip(row.rationale) });
196
+ }
197
+ }
198
+ function anchorCommand(conversationId, msgIndex) {
199
+ return `moda traces get ${shellArg(contextTarget(conversationId))} --msg-index=${msgIndex} --window=2`;
200
+ }
201
+ function compactFindings(raw, opts) {
202
+ const record = asRecord(raw) ?? {};
203
+ const conversationId = asString(record.conversation_id) ?? "";
204
+ const families = asRecord(record.families) ?? {};
205
+ const out = {};
206
+ const anchors = [];
207
+ const byFamily = {};
208
+ const states = {};
209
+ for (const family of FINDINGS_FAMILIES) {
210
+ const entry = asRecord(families[family]);
211
+ if (!entry)
212
+ continue;
213
+ const rows = (Array.isArray(entry.detections) ? entry.detections : []).map((row) => asRecord(row)).filter((row) => row !== null);
214
+ const count = asNumber(entry.count) ?? rows.length;
215
+ const state = familyState(entry);
216
+ const detector = asRecord(entry.detector) ?? {};
217
+ const top = rows.slice(0, opts.limit).map((row) => compactRow(family, row));
218
+ for (const row of top) {
219
+ const msgIndex = asNumber(row.msg_index);
220
+ if (msgIndex !== null)
221
+ anchors.push({ family, msgIndex, label: String(row.family ?? row.tool ?? row.signal ?? row.rule ?? family) });
222
+ }
223
+ byFamily[family] = count;
224
+ states[family] = state;
225
+ out[family] = stripUndefined({
226
+ state,
227
+ count,
228
+ ...opts.batch ? {} : { enabled: detector.enabled ?? null, processed: entry.processed ?? null },
229
+ ...family === "hallucination" && asNumber(entry.verified_claims) ? { verified_claims: entry.verified_claims } : {},
230
+ top: opts.batch && top.length === 0 ? undefined : top,
231
+ more: count > top.length ? count - top.length : undefined
232
+ });
233
+ }
234
+ const problemsBlock = asRecord(record.problems) ?? {};
235
+ const problemRows = (Array.isArray(problemsBlock.problems) ? problemsBlock.problems : []).map((row) => asRecord(row)).filter((row) => row !== null);
236
+ const problemCount = asNumber(problemsBlock.count) ?? problemRows.length;
237
+ const problems = stripUndefined({
238
+ count: problemCount,
239
+ processed: problemsBlock.processed ?? null,
240
+ top: problemRows.slice(0, opts.limit).map((row) => stripUndefined({
241
+ problem_id: row.problem_id,
242
+ title: clip(row.title),
243
+ attribution_count: row.attribution_count,
244
+ lifecycle: row.lifecycle ?? undefined,
245
+ in_book: row.in_book
246
+ })),
247
+ more: problemCount > Math.min(problemRows.length, opts.limit) ? problemCount - Math.min(problemRows.length, opts.limit) : undefined
248
+ });
249
+ const total = Object.values(byFamily).reduce((sum, value) => sum + value, 0);
250
+ const data = opts.batch ? { detections: total, families: out, problems } : {
251
+ conversation_id: conversationId,
252
+ window: "all",
253
+ summary: { detections: total, by_family: byFamily, problems: problemCount },
254
+ families: out,
255
+ problems
256
+ };
257
+ const nextCommands = [];
258
+ const seen = new Set;
259
+ for (const anchor of anchors) {
260
+ if (seen.has(anchor.msgIndex))
261
+ continue;
262
+ seen.add(anchor.msgIndex);
263
+ nextCommands.push({
264
+ command: anchorCommand(conversationId, anchor.msgIndex),
265
+ purpose: `Read message ${anchor.msgIndex} (${anchor.family}: ${anchor.label}) with 2 messages either side.`,
266
+ mutability: "read",
267
+ requires_approval: false
268
+ });
269
+ if (nextCommands.length >= (opts.batch ? NEXT_COMMANDS_BATCH : NEXT_COMMANDS_SINGLE))
270
+ break;
271
+ }
272
+ if (!opts.batch) {
273
+ const topProblem = asString(problemRows[0]?.problem_id);
274
+ if (topProblem) {
275
+ nextCommands.push({
276
+ command: `moda problems get ${shellArg(topProblem)}`,
277
+ purpose: "Open the Problem this trace is most evidence for.",
278
+ mutability: "read",
279
+ requires_approval: false
280
+ });
281
+ }
282
+ }
283
+ const notRun = FINDINGS_FAMILIES.filter((family) => states[family] === "not_run");
284
+ const unknown = FINDINGS_FAMILIES.filter((family) => states[family] === "unknown");
285
+ const found = FINDINGS_FAMILIES.filter((family) => states[family] === "found").map((family) => `${byFamily[family]} ${family}`);
286
+ const summary = `${conversationId}: ${total} detection${total === 1 ? "" : "s"}` + (found.length > 0 ? ` (${found.join(", ")})` : "") + `, evidence for ${problemCount} Problem${problemCount === 1 ? "" : "s"}. No time window.`;
287
+ const warnings = [];
288
+ if (notRun.length > 0) {
289
+ warnings.push(`Not run on this trace (detector off or not processed yet): ${notRun.join(", ")}. No detections there does not mean clean.`);
290
+ }
291
+ if (unknown.length > 0 && total === 0) {
292
+ warnings.push(`Nothing flagged, and ${unknown.join(", ")} record nothing for a clean trace, so whether they ran is not known.`);
293
+ }
294
+ return {
295
+ data,
296
+ options: {
297
+ summary,
298
+ ...warnings.length > 0 && !opts.batch ? { warnings } : {},
299
+ ...nextCommands.length > 0 ? { nextCommands } : {}
300
+ }
301
+ };
302
+ }
303
+ function batchNotRunWarning(results) {
304
+ const notRun = results.flatMap((result) => {
305
+ const families = asRecord(asRecord(result.data)?.families);
306
+ if (!result.ok || !families)
307
+ return [];
308
+ const names = FINDINGS_FAMILIES.filter((family) => asRecord(families[family])?.state === "not_run");
309
+ return names.length > 0 ? [`${result.target} (${names.join(", ")})`] : [];
310
+ });
311
+ if (notRun.length === 0)
312
+ return [];
313
+ return [`Families not run (detector off or trace not processed yet), so no detections there does not mean clean: ${notRun.join("; ")}.`];
314
+ }
315
+
143
316
  // src/replays.ts
144
317
  var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
145
318
  var PLAYOUT_ID_RE = /^[0-9a-f]{64}$/i;
@@ -1145,6 +1318,18 @@ var CANONICAL_LEAVES = [
1145
1318
  summary: "A trace's world state (slots, threads, events)",
1146
1319
  examples: ["moda traces state <conversation_id> --summary-only", "moda traces state <conversation_id> --snapshot --msg-index=12"]
1147
1320
  },
1321
+ {
1322
+ noun: "traces",
1323
+ verb: "findings",
1324
+ path: "traces findings",
1325
+ args: "<conversation_id>...",
1326
+ handler: "trace-findings",
1327
+ summary: "Everything flagged on a trace (every detector family and its Problems), no time window; up to 25 ids per call",
1328
+ examples: [
1329
+ "moda traces findings <conversation_id>",
1330
+ "moda traces findings <id1> <id2> <id3> # batch: up to 25 ids (or --ids-from=-|<file>)"
1331
+ ]
1332
+ },
1148
1333
  {
1149
1334
  noun: "traces",
1150
1335
  verb: "spans",
@@ -1303,7 +1488,7 @@ var CANONICAL_LEAVES = [
1303
1488
  ];
1304
1489
  var CANONICAL_NOUNS = ["traces", "problems", "detections", "tools", "review", "reviews", "skills"];
1305
1490
  var NOUN_SUMMARIES = {
1306
- traces: "Traces (agent runs): list, search, read, world state, raw spans",
1491
+ traces: "Traces (agent runs): list, search, read, findings, world state, raw spans",
1307
1492
  problems: "Problems ranked by root cause, their evidence, impact and lifecycle",
1308
1493
  detections: "Detections of every family, and the tool failure leaderboard",
1309
1494
  tools: "The Tool catalog: every tool with calls and success rate, and one tool's schema, usage and failure categories",
@@ -1414,6 +1599,10 @@ function routeDetectionsList(leaf, rest, flags) {
1414
1599
  throw inputError(`'moda detections list' takes no arguments, but got '${rest.join(" ")}'.`, DETECTIONS_LIST_USAGE, "unexpected_positional");
1415
1600
  }
1416
1601
  const label = `detections list --family=${family}`;
1602
+ const severalTraces = ["conversation-ids", "conversation_ids", "ids-from", "ids_from"].find((key) => flags[key] !== undefined);
1603
+ if (severalTraces && (family === "custom_signal" || family === "tool_failure")) {
1604
+ throw inputError(`--${severalTraces.replace(/_/g, "-")} is not available with --family=${family}. Read several traces' ${family === "custom_signal" ? "custom signal hits" : "tool failures"} with 'moda traces findings <id> <id> ...' (up to 25 ids).`, DETECTIONS_LIST_USAGE, `inapplicable_flag:${severalTraces.replace(/_/g, "-")}`, { field: `--${severalTraces.replace(/_/g, "-")}`, suggestedCommands: ["moda traces findings --help"] });
1605
+ }
1417
1606
  if (family === "custom_signal") {
1418
1607
  const signalId = flags["signal-id"];
1419
1608
  const traceId = flags["conversation-id"];
@@ -2986,46 +3175,46 @@ function leafManifestFields(leaf, commands) {
2986
3175
  import { fileURLToPath } from "url";
2987
3176
  import { realpathSync } from "fs";
2988
3177
  async function runPromptsCommand(...args) {
2989
- return (await import("./prompts-p9hhxx0c.js")).runPromptsCommand(...args);
3178
+ return (await import("./prompts-ysm9ra72.js")).runPromptsCommand(...args);
2990
3179
  }
2991
3180
  async function runSkillsCommand(...args) {
2992
- return (await import("./skills-rk2pmwx8.js")).runSkillsCommand(...args);
3181
+ return (await import("./skills-x6yszxxn.js")).runSkillsCommand(...args);
2993
3182
  }
2994
3183
  async function runFixCommand(...args) {
2995
- return (await import("./fix-s3zkjt69.js")).runFixCommand(...args);
3184
+ return (await import("./fix-0r974yge.js")).runFixCommand(...args);
2996
3185
  }
2997
3186
  async function runFixesCommand(...args) {
2998
- return (await import("./fix-s3zkjt69.js")).runFixesCommand(...args);
3187
+ return (await import("./fix-0r974yge.js")).runFixesCommand(...args);
2999
3188
  }
3000
3189
  async function runHarnessCommand(...args) {
3001
- return (await import("./harness-n4569wbm.js")).runHarnessCommand(...args);
3190
+ return (await import("./harness-72ejenza.js")).runHarnessCommand(...args);
3002
3191
  }
3003
3192
  async function runSyncCommand(...args) {
3004
- return (await import("./sync-xxbfjcz5.js")).runSyncCommand(...args);
3193
+ return (await import("./sync-trjzvam9.js")).runSyncCommand(...args);
3005
3194
  }
3006
3195
  async function runRegistryCommand(...args) {
3007
- return (await import("./registry-nq8qsqtv.js")).runRegistryCommand(...args);
3196
+ return (await import("./registry-7xz09ry0.js")).runRegistryCommand(...args);
3008
3197
  }
3009
3198
  async function runDoctorCommand(...args) {
3010
- return (await import("./doctor-3v20hc26.js")).runDoctorCommand(...args);
3199
+ return (await import("./doctor-p8sp6cbk.js")).runDoctorCommand(...args);
3011
3200
  }
3012
3201
  async function runStatusCommand(...args) {
3013
- return (await import("./doctor-3v20hc26.js")).runStatusCommand(...args);
3202
+ return (await import("./doctor-p8sp6cbk.js")).runStatusCommand(...args);
3014
3203
  }
3015
3204
  async function runAuthCommand(...args) {
3016
- return (await import("./profile-commands-7ck1tqfv.js")).runAuthCommand(...args);
3205
+ return (await import("./profile-commands-se9947c1.js")).runAuthCommand(...args);
3017
3206
  }
3018
3207
  async function runConfigCommand(...args) {
3019
- return (await import("./profile-commands-7ck1tqfv.js")).runConfigCommand(...args);
3208
+ return (await import("./profile-commands-se9947c1.js")).runConfigCommand(...args);
3020
3209
  }
3021
3210
  async function runProfilesCommand(...args) {
3022
- return (await import("./profile-commands-7ck1tqfv.js")).runProfilesCommand(...args);
3211
+ return (await import("./profile-commands-se9947c1.js")).runProfilesCommand(...args);
3023
3212
  }
3024
3213
  async function runAgentCommand(...args) {
3025
- return (await import("./agent-bhe95ae8.js")).runAgentCommand(...args);
3214
+ return (await import("./agent-ck6y31n2.js")).runAgentCommand(...args);
3026
3215
  }
3027
3216
  async function runProductionCommand(...args) {
3028
- return (await import("./production-intelligence-z2cad1hv.js")).runProductionCommand(...args);
3217
+ return (await import("./production-intelligence-e5vsc6cw.js")).runProductionCommand(...args);
3029
3218
  }
3030
3219
  function parseArgs(argv) {
3031
3220
  const args = argv.slice(2);
@@ -4451,7 +4640,7 @@ function rejectInapplicableFlags(command, params, keys, why) {
4451
4640
  const shown = canonicalCommandText(`moda ${command}`);
4452
4641
  throw new CliInputError(`${names.join(", ")} ${given.length > 1 ? "do" : "does"} not apply ${why}, so nothing was sent.`, `Drop ${names.join(", ")}, or pick the mode that uses ${given.length > 1 ? "them" : "it"}. See '${shown} --help'.`, `inapplicable_flag:${names[0].slice(2)}`, { field: names[0], suggestedCommands: [`${shown} --help`] });
4453
4642
  }
4454
- var BATCH_POSITIONAL_COMMANDS = new Set(["context", "audit", "trace"]);
4643
+ var BATCH_POSITIONAL_COMMANDS = new Set(["context", "audit", "trace", "trace-findings"]);
4455
4644
  function assertPositionalArity(command, positionals) {
4456
4645
  const spec = flagSpecFor(command);
4457
4646
  const expected = spec?.positionals ?? [];
@@ -5410,6 +5599,79 @@ async function runContextBatch(command, positionals, flags, context) {
5410
5599
  });
5411
5600
  return writeBatchResult(command, context, targets, results, inputWarnings, rest);
5412
5601
  }
5602
+ var CONVERSATION_IDS_USAGE = `Usage: moda detections list --family=emotion|frustration|laziness|hallucination --conversation-ids=<id>,<id>,... | --ids-from=-|<file> (up to ${MAX_CONVERSATION_IDS_FILTER} ids)`;
5603
+ async function conversationIdsFilter(params, context) {
5604
+ if (params.conversation_ids === undefined && params.ids_from === undefined)
5605
+ return;
5606
+ if (params.conversation_ids !== undefined && params.ids_from !== undefined) {
5607
+ throw new CliInputError("Pass --conversation-ids or --ids-from, not both.", CONVERSATION_IDS_USAGE, "flag_conflict");
5608
+ }
5609
+ if (params.conversation_id !== undefined) {
5610
+ throw new CliInputError("--conversation-id reads one trace and --conversation-ids/--ids-from several; pass one of them.", CONVERSATION_IDS_USAGE, "flag_conflict");
5611
+ }
5612
+ let ids;
5613
+ if (params.ids_from !== undefined) {
5614
+ ids = parseTargetLines(await readIdsFrom(params.ids_from, CONVERSATION_IDS_USAGE), false, CONVERSATION_IDS_USAGE).map((target) => target.id);
5615
+ } else {
5616
+ const text = params.conversation_ids.trim();
5617
+ let parsed = undefined;
5618
+ if (text.startsWith("[")) {
5619
+ try {
5620
+ parsed = JSON.parse(text);
5621
+ } catch {
5622
+ throw new CliInputError("--conversation-ids starts with [ but is not a JSON array of ids.", CONVERSATION_IDS_USAGE, "bad_value:conversation-ids");
5623
+ }
5624
+ }
5625
+ ids = Array.isArray(parsed) ? parsed.map((id) => String(id).trim()) : text.split(",").map((id) => id.trim());
5626
+ }
5627
+ const unique = [...new Set(ids.filter((id) => id !== ""))];
5628
+ if (unique.length === 0) {
5629
+ throw new CliInputError("No trace ids: --conversation-ids/--ids-from gave none.", CONVERSATION_IDS_USAGE, "missing_value:conversation-ids");
5630
+ }
5631
+ if (unique.length > MAX_CONVERSATION_IDS_FILTER) {
5632
+ throw new CliInputError(`Got ${unique.length} trace ids; the detection lists take at most ${MAX_CONVERSATION_IDS_FILTER} per call, so nothing was read. Split them into calls of ${MAX_CONVERSATION_IDS_FILTER} or fewer.`, CONVERSATION_IDS_USAGE, "batch_too_large");
5633
+ }
5634
+ const withComma = unique.find((id) => id.includes(","));
5635
+ if (withComma !== undefined) {
5636
+ throw new CliInputError(`Trace id ${JSON.stringify(withComma)} has a comma, which the several-trace filter cannot carry. Read it with --conversation-id instead.`, CONVERSATION_IDS_USAGE, "bad_value:conversation-ids");
5637
+ }
5638
+ if (params.ids_from !== undefined && context.invocation) {
5639
+ for (const key of IDS_FROM_KEYS)
5640
+ delete context.invocation.flags[key];
5641
+ context.invocation.flags["conversation-ids"] = unique.join(",");
5642
+ }
5643
+ return unique;
5644
+ }
5645
+ var TRACE_FINDINGS_USAGE = `Usage: moda traces findings <conversation_id> [<conversation_id> ...] | --ids-from=-|<file> [--limit=N] (max ${BATCH_MAX_TARGETS} ids)`;
5646
+ async function runTraceFindings(command, positionals, flags, context) {
5647
+ const { idsFrom, rest } = splitIdsFrom(flags);
5648
+ if (positionals.length === 0 && idsFrom === undefined) {
5649
+ throw new CliInputError("<conversation_id> is required", TRACE_FINDINGS_USAGE, "missing_positional");
5650
+ }
5651
+ const targets = await collectBatchTargets(positionals, idsFrom, { anchors: false, usage: TRACE_FINDINGS_USAGE, command });
5652
+ const base = parseCommandFlags(TraceFindingsSchema, flagsToArgs(rest, "conversation_id", targets[0].id), command, { positionalKey: "conversation_id" });
5653
+ const limit = base.limit ?? FINDINGS_DEFAULT_LIMIT;
5654
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
5655
+ const full = context.output.mode === "json";
5656
+ const batch = isBatchRead(positionals, flags);
5657
+ const read = async (id, budget) => {
5658
+ const raw = await callDataAPI(`/conversations/${encodeURIComponent(id)}/findings`);
5659
+ if (full)
5660
+ return { data: raw, options: {} };
5661
+ let item = compactFindings(raw, { limit, batch });
5662
+ for (let shown = limit - 1;budget && shown >= 0 && !budget.fits(item.data, item.options); shown -= 1) {
5663
+ item = compactFindings(raw, { limit: shown, batch });
5664
+ }
5665
+ return item;
5666
+ };
5667
+ if (!batch) {
5668
+ const item = await read(targets[0].id, agentMode ? { fits: (data, options) => agentEnvelopeFits(command, data, options), maxBytes: agentMaxOutputBytes() } : undefined);
5669
+ context.output.writeData(item.data, item.options);
5670
+ return 0;
5671
+ }
5672
+ const results = await readBatchTargets(targets, agentMode, (target, budget) => read(target.id, budget));
5673
+ return writeBatchResult("traces findings", context, targets, results, full ? [] : batchNotRunWarning(results), rest);
5674
+ }
5413
5675
  async function runAuditBatch(command, positionals, flags, context) {
5414
5676
  const { idsFrom, rest } = splitIdsFrom(flags);
5415
5677
  if (rest.cursor !== undefined || Object.keys(rest).some((key) => key.replace(/_/g, "-") === "span-offset")) {
@@ -5681,6 +5943,8 @@ async function runCommand(command, positional, flags, positionals = positional ?
5681
5943
  context.output.writeData(item.data, item.options);
5682
5944
  break;
5683
5945
  }
5946
+ case "trace-findings":
5947
+ return runTraceFindings(command, positionals, flags, context);
5684
5948
  case "audit":
5685
5949
  case "trace": {
5686
5950
  if (isBatchRead(positionals, flags))
@@ -5705,7 +5969,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5705
5969
  query2.set("limit", params.limit.toString());
5706
5970
  if (params.offset !== undefined)
5707
5971
  query2.set("offset", params.offset.toString());
5708
- if (readsPerTrace("frustrations", params, ["user_id", "conversation_id", "include_window"])) {
5972
+ if (readsPerTrace("frustrations", params, ["user_id", "conversation_id", "conversation_ids", "ids_from", "include_window"])) {
5709
5973
  query2.set("family", "frustration");
5710
5974
  setTraceFilters(query2, params, TRACE_GRAIN_FLAGS.frustrations);
5711
5975
  const data2 = await callDataAPI(`/emotions?${query2.toString()}`);
@@ -5718,6 +5982,9 @@ async function runCommand(command, positional, flags, positionals = positional ?
5718
5982
  query2.set("user_id", params.user_id);
5719
5983
  if (params.conversation_id)
5720
5984
  query2.set("conversation_id", params.conversation_id);
5985
+ const frustrationIds = await conversationIdsFilter(params, context);
5986
+ if (frustrationIds)
5987
+ query2.set("conversation_ids", frustrationIds.join(","));
5721
5988
  query2.set("family", "frustration");
5722
5989
  const includeWindow = params.include_window === true;
5723
5990
  const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
@@ -6378,7 +6645,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
6378
6645
  query2.set("offset", params.offset.toString());
6379
6646
  if (params.family)
6380
6647
  query2.set("family", params.family);
6381
- if (readsPerTrace("emotions", params, ["user_id", "conversation_id", "include_window"])) {
6648
+ if (readsPerTrace("emotions", params, ["user_id", "conversation_id", "conversation_ids", "ids_from", "include_window"])) {
6382
6649
  setTraceFilters(query2, params, TRACE_GRAIN_FLAGS.emotions);
6383
6650
  const data2 = await callDataAPI(`/emotions?${query2.toString()}`);
6384
6651
  const warnings = processingDisabledWarning(data2, "emotion");
@@ -6390,6 +6657,9 @@ async function runCommand(command, positional, flags, positionals = positional ?
6390
6657
  query2.set("user_id", params.user_id);
6391
6658
  if (params.conversation_id)
6392
6659
  query2.set("conversation_id", params.conversation_id);
6660
+ const emotionIds = await conversationIdsFilter(params, context);
6661
+ if (emotionIds)
6662
+ query2.set("conversation_ids", emotionIds.join(","));
6393
6663
  const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
6394
6664
  if (agentMode && params.include_window !== true)
6395
6665
  query2.set("include_context", "0");
@@ -6414,6 +6684,9 @@ async function runCommand(command, positional, flags, positionals = positional ?
6414
6684
  query2.set("offset", params.offset.toString());
6415
6685
  if (params.conversation_id)
6416
6686
  query2.set("conversation_id", params.conversation_id);
6687
+ const lazinessIds = await conversationIdsFilter(params, context);
6688
+ if (lazinessIds)
6689
+ query2.set("conversation_ids", lazinessIds.join(","));
6417
6690
  if (params.family)
6418
6691
  query2.set("family", params.family);
6419
6692
  if (params.conversation_id) {
@@ -6443,11 +6716,14 @@ async function runCommand(command, positional, flags, positionals = positional ?
6443
6716
  query2.set("limit", params.limit.toString());
6444
6717
  if (params.offset !== undefined)
6445
6718
  query2.set("offset", params.offset.toString());
6446
- if (readsPerTrace("hallucinations", params, ["conversation_id", "kind"])) {
6719
+ if (readsPerTrace("hallucinations", params, ["conversation_id", "conversation_ids", "ids_from", "kind"])) {
6447
6720
  setTraceFilters(query2, params, TRACE_GRAIN_FLAGS.hallucinations);
6448
6721
  } else {
6449
6722
  if (params.conversation_id)
6450
6723
  query2.set("conversation_id", params.conversation_id);
6724
+ const hallucinationIds = await conversationIdsFilter(params, context);
6725
+ if (hallucinationIds)
6726
+ query2.set("conversation_ids", hallucinationIds.join(","));
6451
6727
  if (params.kind)
6452
6728
  query2.set("kind", params.kind);
6453
6729
  }
@@ -6643,7 +6919,7 @@ var commandRegistry = createCommandRegistry([
6643
6919
  resetApiRequestCountBeforeRun: true,
6644
6920
  telemetry: "result-and-error",
6645
6921
  handler: async (context) => {
6646
- const { runInit } = await import("./index-2qm3h7v2.js");
6922
+ const { runInit } = await import("./index-w7v472w4.js");
6647
6923
  if (context.outputMode === "agent-stream") {
6648
6924
  context.output.writeEvent({
6649
6925
  event: "started",
@@ -6693,7 +6969,7 @@ var commandRegistry = createCommandRegistry([
6693
6969
  resetApiRequestCountBeforeRun: true,
6694
6970
  telemetry: "result-and-error",
6695
6971
  handler: async (context) => {
6696
- const { runProvision } = await import("./provision-x4wkyw60.js");
6972
+ const { runProvision } = await import("./provision-cya5rpxa.js");
6697
6973
  return runProvision(context, {
6698
6974
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
6699
6975
  });
@@ -7181,6 +7457,17 @@ var commandRegistry = createCommandRegistry([
7181
7457
  ],
7182
7458
  ...dataApiDefaults
7183
7459
  }),
7460
+ legacyCommand({
7461
+ name: "trace-findings",
7462
+ description: "Everything flagged on a trace: every detector family with its message anchors, and the Problems it is evidence for (no time window)",
7463
+ examples: [
7464
+ "moda traces findings <conversation_id>",
7465
+ "moda traces findings <conversation_id> --limit=10 # more rows per family (counts always cover all)",
7466
+ "moda traces findings <id1> <id2> <id3> # batch: up to 25 ids, one envelope (or --ids-from=-|<file>)"
7467
+ ],
7468
+ hidden: true,
7469
+ ...dataApiDefaults
7470
+ }),
7184
7471
  legacyCommand({
7185
7472
  name: "frustrations",
7186
7473
  description: "User frustration detections: the frustration family of `emotions` (same data as the dashboard), legacy field names",
@@ -3,15 +3,15 @@ import {
3
3
  promptsDiscoveredCheck,
4
4
  runDoctorCommand,
5
5
  runStatusCommand
6
- } from "./cli-msgp78ag.js";
7
- import"./cli-ptm7pwqg.js";
8
- import"./cli-jmbt1hf9.js";
6
+ } from "./cli-a8nxbtpk.js";
7
+ import"./cli-pmzh2qjy.js";
8
+ import"./cli-4tg0hkbz.js";
9
9
  import"./cli-mm48br00.js";
10
10
  import"./cli-xq45etg1.js";
11
- import"./cli-jkza0bj6.js";
12
- import"./cli-k9se46y4.js";
13
- import"./cli-qzag917n.js";
14
- import"./cli-wr6f0kyw.js";
11
+ import"./cli-xddtv3yn.js";
12
+ import"./cli-f1jfrqgf.js";
13
+ import"./cli-0xc5htv7.js";
14
+ import"./cli-t0pb7qbs.js";
15
15
  import"./cli-k4tqwah4.js";
16
16
  import"./cli-9kfxkxmk.js";
17
17
  import"./cli-ns5fcnkz.js";
@@ -2,13 +2,13 @@ import {
2
2
  DEFAULT_POLL_INTERVAL_MS,
3
3
  DEFAULT_WAIT_TIMEOUT_MS,
4
4
  fetchLatestRun
5
- } from "./cli-2h2nvq6w.js";
5
+ } from "./cli-daqkdnm1.js";
6
6
  import {
7
7
  assertFlags
8
- } from "./cli-k9se46y4.js";
8
+ } from "./cli-f1jfrqgf.js";
9
9
  import {
10
10
  callControlAPI
11
- } from "./cli-qzag917n.js";
11
+ } from "./cli-0xc5htv7.js";
12
12
  import {
13
13
  EXIT_DEGRADED,
14
14
  EXIT_ERROR,
@@ -17,7 +17,7 @@ import {
17
17
  resolveApiTenantId,
18
18
  shellArg,
19
19
  validateConfig
20
- } from "./cli-wr6f0kyw.js";
20
+ } from "./cli-t0pb7qbs.js";
21
21
  import {
22
22
  CliInputError
23
23
  } from "./cli-k4tqwah4.js";
@@ -40,17 +40,17 @@ import {
40
40
  writeHarnessAnalyzeResult,
41
41
  writeHarnessArtifacts,
42
42
  writeHumanProgress
43
- } from "./cli-c7vj8tq1.js";
43
+ } from "./cli-azage7s0.js";
44
44
  import"./cli-xq45etg1.js";
45
45
  import"./cli-97fnztpy.js";
46
46
  import {
47
47
  HARNESS_ANALYZE_CONCERNS
48
48
  } from "./cli-cesds766.js";
49
49
  import"./cli-qpq84eee.js";
50
- import"./cli-jkza0bj6.js";
51
- import"./cli-k9se46y4.js";
52
- import"./cli-qzag917n.js";
53
- import"./cli-wr6f0kyw.js";
50
+ import"./cli-xddtv3yn.js";
51
+ import"./cli-f1jfrqgf.js";
52
+ import"./cli-0xc5htv7.js";
53
+ import"./cli-t0pb7qbs.js";
54
54
  import"./cli-k4tqwah4.js";
55
55
  import"./cli-9kfxkxmk.js";
56
56
  import"./cli-ns5fcnkz.js";
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-c7vj8tq1.js";
3
+ } from "./cli-azage7s0.js";
4
4
  import"./cli-xq45etg1.js";
5
5
  import"./cli-97fnztpy.js";
6
6
  import"./cli-cesds766.js";
7
7
  import"./cli-qpq84eee.js";
8
- import"./cli-jkza0bj6.js";
9
- import"./cli-k9se46y4.js";
10
- import"./cli-qzag917n.js";
8
+ import"./cli-xddtv3yn.js";
9
+ import"./cli-f1jfrqgf.js";
10
+ import"./cli-0xc5htv7.js";
11
11
  import {
12
12
  recordApiRequest
13
- } from "./cli-wr6f0kyw.js";
13
+ } from "./cli-t0pb7qbs.js";
14
14
  import"./cli-k4tqwah4.js";
15
15
  import"./cli-9kfxkxmk.js";
16
16
  import"./cli-ns5fcnkz.js";