@moda-ai/cli 1.55.36 → 1.55.38

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-g07tg64w.js → agent-9r58v0bc.js} +8 -8
  2. package/dist/{cli-e23g9ywa.js → cli-3n040fp2.js} +1 -1
  3. package/dist/{cli-k007ztbs.js → cli-93926afn.js} +4 -4
  4. package/dist/{cli-97jew729.js → cli-9g5kzsg6.js} +1 -1
  5. package/dist/{cli-dr6x0zv7.js → cli-b7nyw498.js} +1 -1
  6. package/dist/{cli-6j8h2ave.js → cli-dmnayt2r.js} +8 -8
  7. package/dist/{cli-fwpqghgc.js → cli-n311b8g0.js} +112 -2
  8. package/dist/{cli-602yx84w.js → cli-nh23q6ay.js} +5 -5
  9. package/dist/{cli-99p2jh28.js → cli-rcjhfts4.js} +24 -10
  10. package/dist/{cli-9bgnvth2.js → cli-sk1p71wr.js} +1 -1
  11. package/dist/{cli-x9cwat4a.js → cli-skvvwp2q.js} +5 -5
  12. package/dist/{cli-9bgk5jeh.js → cli-tdcx8yz9.js} +3 -3
  13. package/dist/{cli-n2hng3gv.js → cli-xheg54qc.js} +80 -7
  14. package/dist/{cli-yz8xcpyk.js → cli-xk630wjq.js} +1 -1
  15. package/dist/{cli-5fstvkva.js → cli-xtyszvq1.js} +5 -5
  16. package/dist/cli.js +319 -39
  17. package/dist/{doctor-tvre7zvk.js → doctor-xq5bjvpq.js} +7 -7
  18. package/dist/{fix-w5z02wt4.js → fix-kvszavm1.js} +4 -4
  19. package/dist/{harness-github-actions-6gdrpn4m.js → harness-github-actions-drbkcb8d.js} +5 -5
  20. package/dist/{harness-6vwehf47.js → harness-qatnwxrz.js} +5 -5
  21. package/dist/{index-75vcntpe.js → index-y5jnz2t2.js} +11 -11
  22. package/dist/{production-intelligence-7wb1djy2.js → production-intelligence-j55vaw6t.js} +61 -4
  23. package/dist/{profile-commands-h8evz9x0.js → profile-commands-skdxe17v.js} +3 -3
  24. package/dist/{prompt-attribution-t0eq8gn8.js → prompt-attribution-zq38actx.js} +5 -5
  25. package/dist/prompt-source-mcp.js +5 -5
  26. package/dist/{prompts-ab-t7xptf0c.js → prompts-ab-yd2dawe3.js} +7 -7
  27. package/dist/{prompts-b8qx3mrv.js → prompts-cwqn8a57.js} +5 -5
  28. package/dist/{prompts-propose-8feadk2t.js → prompts-propose-11dj9ked.js} +7 -7
  29. package/dist/{provision-y5bdbh4y.js → provision-ghca9d54.js} +5 -5
  30. package/dist/{registry-ctnn8e26.js → registry-76sngjw6.js} +3 -3
  31. package/dist/{skills-96z55tj4.js → skills-btn9r48v.js} +5 -5
  32. package/dist/{sync-drz7req6.js → sync-ye7nxeen.js} +7 -7
  33. package/package.json +1 -1
  34. package/skills/integration/index.json +2 -2
  35. package/skills/moda-cli/SKILL.md +5 -2
  36. package/skills/moda-cli/references/commands.md +3 -0
  37. package/skills/moda-cli/references/dashboard-parity.md +4 -0
  38. package/skills/moda-cli/references/detections.md +93 -0
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isAuthSessionValid,
3
3
  loadAuthSession
4
- } from "./cli-9bgnvth2.js";
4
+ } from "./cli-sk1p71wr.js";
5
5
  import {
6
6
  inspectPromptManifest
7
- } from "./cli-6j8h2ave.js";
7
+ } from "./cli-dmnayt2r.js";
8
8
  import {
9
9
  readHarnessSyncState,
10
10
  renderDoctorHuman,
@@ -12,7 +12,7 @@ import {
12
12
  } from "./cli-xq45etg1.js";
13
13
  import {
14
14
  callDataAPI
15
- } from "./cli-e23g9ywa.js";
15
+ } from "./cli-3n040fp2.js";
16
16
  import {
17
17
  ensureSecretFilePermissions,
18
18
  getActiveProfile,
@@ -26,7 +26,7 @@ import {
26
26
  resolveSecretReference,
27
27
  resolveTenantId,
28
28
  secretFilePathFromRef
29
- } from "./cli-99p2jh28.js";
29
+ } from "./cli-rcjhfts4.js";
30
30
  import {
31
31
  __require
32
32
  } from "./cli-0v6na3yp.js";
@@ -376,7 +376,7 @@ async function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId)
376
376
  };
377
377
  }
378
378
  try {
379
- const { scanHarness } = await import("./harness-6vwehf47.js");
379
+ const { scanHarness } = await import("./harness-qatnwxrz.js");
380
380
  const current = scanHarness({
381
381
  rootDir: cwd,
382
382
  scannerVersion: "doctor",
package/dist/cli.js CHANGED
@@ -13,11 +13,14 @@ import {
13
13
  frustrationsFromEmotions,
14
14
  mapWithConcurrency,
15
15
  parseBatchTarget,
16
+ shapeToolCatalogDetail,
17
+ toolCatalogGetCommand,
18
+ toolFailureExamplesCommand,
16
19
  trimToolFailureConversations,
17
20
  withFrustrationAnchors,
18
21
  withToolFailureAnchors,
19
22
  withoutDetectionWindows
20
- } from "./cli-fwpqghgc.js";
23
+ } from "./cli-n311b8g0.js";
21
24
  import {
22
25
  createCommandContext,
23
26
  envOptOutSet,
@@ -25,7 +28,7 @@ import {
25
28
  optOutFlagSet,
26
29
  parseBooleanFlagValue,
27
30
  withoutFlag
28
- } from "./cli-dr6x0zv7.js";
31
+ } from "./cli-b7nyw498.js";
29
32
  import {
30
33
  AuditSchema,
31
34
  COMMAND_FLAG_SPECS,
@@ -44,6 +47,7 @@ import {
44
47
  SIGNALS_MANAGEMENT_SUBCOMMANDS,
45
48
  SignalLabelSchema,
46
49
  StepScoresSchema,
50
+ TRACE_GRAIN_FLAGS,
47
51
  UUID_RE,
48
52
  assertFlags,
49
53
  assertPositionals,
@@ -67,12 +71,12 @@ import {
67
71
  unknownSignalsSubcommandError,
68
72
  usageLine,
69
73
  writeDryRun
70
- } from "./cli-n2hng3gv.js";
74
+ } from "./cli-xheg54qc.js";
71
75
  import {
72
76
  ApiError,
73
77
  callControlAPI,
74
78
  callDataAPI
75
- } from "./cli-e23g9ywa.js";
79
+ } from "./cli-3n040fp2.js";
76
80
  import {
77
81
  AGENT_ERROR_CODES,
78
82
  EXIT_AUTH_REQUIRED,
@@ -109,7 +113,7 @@ import {
109
113
  shellArg,
110
114
  validateConfig,
111
115
  wasOutputCancelled
112
- } from "./cli-99p2jh28.js";
116
+ } from "./cli-rcjhfts4.js";
113
117
  import {
114
118
  CliAccessError,
115
119
  CliAuthError,
@@ -1242,6 +1246,24 @@ var CANONICAL_LEAVES = [
1242
1246
  summary: "Tool failure leaderboard, or one tool's failure examples",
1243
1247
  examples: ["moda detections tools --days-back=14", "moda detections tools <tool_name> --limit=3"]
1244
1248
  },
1249
+ {
1250
+ noun: "tools",
1251
+ verb: "list",
1252
+ path: "tools list",
1253
+ args: "",
1254
+ handler: "tool-catalog",
1255
+ summary: "Every tool called in the window: calls, failed calls, success rate, effect direction, last seen",
1256
+ examples: ["moda tools list --days-back=7", "moda tools list --sort=failure_rate --limit=10", "moda tools list --search=calendar --direction=write"]
1257
+ },
1258
+ {
1259
+ noun: "tools",
1260
+ verb: "get",
1261
+ path: "tools get",
1262
+ args: "<tool_name>",
1263
+ handler: "tool-catalog-detail",
1264
+ summary: "One tool: calls, recorded schema and payload fields, usage over time, top failure categories",
1265
+ examples: ["moda tools get <tool_name>", "moda tools get <tool_name> --days-back=30 --full"]
1266
+ },
1245
1267
  {
1246
1268
  noun: "review",
1247
1269
  verb: "",
@@ -1275,11 +1297,12 @@ var CANONICAL_LEAVES = [
1275
1297
  examples: ["moda skills push --dry-run", "moda skills push"]
1276
1298
  }
1277
1299
  ];
1278
- var CANONICAL_NOUNS = ["traces", "problems", "detections", "review", "reviews", "skills"];
1300
+ var CANONICAL_NOUNS = ["traces", "problems", "detections", "tools", "review", "reviews", "skills"];
1279
1301
  var NOUN_SUMMARIES = {
1280
1302
  traces: "Traces (agent runs): list, search, read, world state, raw spans",
1281
1303
  problems: "Problems ranked by root cause, their evidence, impact and lifecycle",
1282
1304
  detections: "Detections of every family, and the tool failure leaderboard",
1305
+ tools: "The Tool catalog: every tool with calls and success rate, and one tool's schema, usage and failure categories",
1283
1306
  review: "Mark a detection a false positive, correct, or clear the mark",
1284
1307
  reviews: "List false-positive marks and detection reviews",
1285
1308
  skills: "Generate, pull, push, and install agent skills"
@@ -2959,46 +2982,46 @@ function leafManifestFields(leaf, commands) {
2959
2982
  import { fileURLToPath } from "url";
2960
2983
  import { realpathSync } from "fs";
2961
2984
  async function runPromptsCommand(...args) {
2962
- return (await import("./prompts-b8qx3mrv.js")).runPromptsCommand(...args);
2985
+ return (await import("./prompts-cwqn8a57.js")).runPromptsCommand(...args);
2963
2986
  }
2964
2987
  async function runSkillsCommand(...args) {
2965
- return (await import("./skills-96z55tj4.js")).runSkillsCommand(...args);
2988
+ return (await import("./skills-btn9r48v.js")).runSkillsCommand(...args);
2966
2989
  }
2967
2990
  async function runFixCommand(...args) {
2968
- return (await import("./fix-w5z02wt4.js")).runFixCommand(...args);
2991
+ return (await import("./fix-kvszavm1.js")).runFixCommand(...args);
2969
2992
  }
2970
2993
  async function runFixesCommand(...args) {
2971
- return (await import("./fix-w5z02wt4.js")).runFixesCommand(...args);
2994
+ return (await import("./fix-kvszavm1.js")).runFixesCommand(...args);
2972
2995
  }
2973
2996
  async function runHarnessCommand(...args) {
2974
- return (await import("./harness-6vwehf47.js")).runHarnessCommand(...args);
2997
+ return (await import("./harness-qatnwxrz.js")).runHarnessCommand(...args);
2975
2998
  }
2976
2999
  async function runSyncCommand(...args) {
2977
- return (await import("./sync-drz7req6.js")).runSyncCommand(...args);
3000
+ return (await import("./sync-ye7nxeen.js")).runSyncCommand(...args);
2978
3001
  }
2979
3002
  async function runRegistryCommand(...args) {
2980
- return (await import("./registry-ctnn8e26.js")).runRegistryCommand(...args);
3003
+ return (await import("./registry-76sngjw6.js")).runRegistryCommand(...args);
2981
3004
  }
2982
3005
  async function runDoctorCommand(...args) {
2983
- return (await import("./doctor-tvre7zvk.js")).runDoctorCommand(...args);
3006
+ return (await import("./doctor-xq5bjvpq.js")).runDoctorCommand(...args);
2984
3007
  }
2985
3008
  async function runStatusCommand(...args) {
2986
- return (await import("./doctor-tvre7zvk.js")).runStatusCommand(...args);
3009
+ return (await import("./doctor-xq5bjvpq.js")).runStatusCommand(...args);
2987
3010
  }
2988
3011
  async function runAuthCommand(...args) {
2989
- return (await import("./profile-commands-h8evz9x0.js")).runAuthCommand(...args);
3012
+ return (await import("./profile-commands-skdxe17v.js")).runAuthCommand(...args);
2990
3013
  }
2991
3014
  async function runConfigCommand(...args) {
2992
- return (await import("./profile-commands-h8evz9x0.js")).runConfigCommand(...args);
3015
+ return (await import("./profile-commands-skdxe17v.js")).runConfigCommand(...args);
2993
3016
  }
2994
3017
  async function runProfilesCommand(...args) {
2995
- return (await import("./profile-commands-h8evz9x0.js")).runProfilesCommand(...args);
3018
+ return (await import("./profile-commands-skdxe17v.js")).runProfilesCommand(...args);
2996
3019
  }
2997
3020
  async function runAgentCommand(...args) {
2998
- return (await import("./agent-g07tg64w.js")).runAgentCommand(...args);
3021
+ return (await import("./agent-9r58v0bc.js")).runAgentCommand(...args);
2999
3022
  }
3000
3023
  async function runProductionCommand(...args) {
3001
- return (await import("./production-intelligence-7wb1djy2.js")).runProductionCommand(...args);
3024
+ return (await import("./production-intelligence-j55vaw6t.js")).runProductionCommand(...args);
3002
3025
  }
3003
3026
  function parseArgs(argv) {
3004
3027
  const args = argv.slice(2);
@@ -3285,6 +3308,7 @@ Start here (goal -> command):
3285
3308
  read one trace moda traces get <conversation_id> (whole trace: --all)
3286
3309
  what is broken moda overview, then moda problems list
3287
3310
  tool errors moda detections tools, then moda detections tools <tool_name>
3311
+ tool calls, success rate, schema moda tools list, then moda tools get <tool_name>
3288
3312
  user emotion and frustration moda detections list --family=emotion (or --family=frustration)
3289
3313
  raw spans for one trace moda traces spans <conversation_id|trace_id>
3290
3314
  a detection is wrong moda review <kind> <target> --reason=TEXT
@@ -3300,7 +3324,7 @@ Production data:
3300
3324
  users / user <user_id> End users with health and activity (the dashboard Users page)
3301
3325
  tail Live-tail new traces/detections as NDJSON (one line per item)
3302
3326
 
3303
- Traces, Problems, detections and review (moda <noun> --help lists the verbs):
3327
+ Traces, Problems, detections, tools and review (moda <noun> --help lists the verbs):
3304
3328
  ${canonicalTreeHelpLines().join(`
3305
3329
  `)}
3306
3330
 
@@ -3650,7 +3674,9 @@ async function attachWindows(rows, windowSize, budgetBytes) {
3650
3674
  }
3651
3675
  var TOOL_FAILURE_DETAIL_DEFAULT_LIMIT = 5;
3652
3676
  var TOOL_FAILURE_AGENT_SUBTYPES = 20;
3653
- async function printWithOptionalWindows(enriched, listKey, includeWindow, windowSize, output, warnings, finalize) {
3677
+ var TOOL_FAILURE_CATALOG_LINKS = 3;
3678
+ var TOOL_CATALOG_DEFAULT_LIMIT = 25;
3679
+ async function printWithOptionalWindows(enriched, listKey, includeWindow, windowSize, output, warnings, finalize, nextCommands = [], summary) {
3654
3680
  const allWarnings = [...warnings ?? []];
3655
3681
  let data = enriched;
3656
3682
  if (includeWindow) {
@@ -3660,7 +3686,12 @@ async function printWithOptionalWindows(enriched, listKey, includeWindow, window
3660
3686
  }
3661
3687
  if (finalize)
3662
3688
  data = finalize(data, allWarnings);
3663
- output.writeData(data, allWarnings.length > 0 ? { warnings: allWarnings } : undefined);
3689
+ const options = {
3690
+ ...summary ? { summary } : {},
3691
+ ...allWarnings.length > 0 ? { warnings: allWarnings } : {},
3692
+ ...nextCommands.length > 0 ? { nextCommands } : {}
3693
+ };
3694
+ output.writeData(data, Object.keys(options).length > 0 ? options : undefined);
3664
3695
  }
3665
3696
  function withoutRepeatedFrustrationWindow(data) {
3666
3697
  if (!Array.isArray(data.frustrations))
@@ -4506,6 +4537,91 @@ function processingDisabledWarning(data, family) {
4506
4537
  `${family === "emotion" ? "Emotion" : "Frustration"} analysis is disabled for this tenant (${setting} = false), ` + "so zero results do NOT mean users are not frustrated. Enable it in Settings → Account → Signal processing; " + "only traces ingested after enabling are analyzed."
4507
4538
  ];
4508
4539
  }
4540
+ function readsPerTrace(command, params, perRowScopes) {
4541
+ const filters = TRACE_GRAIN_FLAGS[command].filter((key) => params[key] !== undefined);
4542
+ const grain = params.group_by;
4543
+ if (grain !== undefined && grain !== "trace" && filters.length > 0) {
4544
+ rejectInapplicableFlags(command, params, filters, `with --group-by=${grain}; they filter the per-trace list (--group-by=trace)`);
4545
+ }
4546
+ const perTrace = grain === "trace" || filters.length > 0;
4547
+ if (perTrace) {
4548
+ rejectInapplicableFlags(command, params, perRowScopes, "to the per-trace list (--group-by=trace, or a filter that implies it); drop --group-by and the trace filters to use them");
4549
+ }
4550
+ return perTrace;
4551
+ }
4552
+ function setTraceFilters(query2, params, keys) {
4553
+ query2.set("group_by", "trace");
4554
+ for (const key of keys) {
4555
+ const value = params[key];
4556
+ if (value === undefined)
4557
+ continue;
4558
+ if (key === "signal")
4559
+ query2.set("signals", String(value).split(",").map((part) => part.trim()).join(","));
4560
+ else
4561
+ query2.set(key, String(value));
4562
+ }
4563
+ }
4564
+ function countingSummary(data) {
4565
+ const record = asRecord(data);
4566
+ const counting = asString(record?.counting);
4567
+ const total = asNumber(asRecord(record?.pagination)?.total);
4568
+ if (!counting || total === null)
4569
+ return;
4570
+ switch (counting) {
4571
+ case "per_trace":
4572
+ return `${total} trace(s) match. Counting: per trace, as the dashboard counts (pagination.total = traces).`;
4573
+ case "per_detection":
4574
+ return `${total} detection(s) match. Counting: per detection (one row per trace and family), not per trace; add --group-by=trace for the dashboard's per-trace count.`;
4575
+ case "per_message":
4576
+ return `${total} message detection(s) match. Counting: per scored message, not per trace; add --group-by=trace for the dashboard's per-trace count.`;
4577
+ default:
4578
+ return;
4579
+ }
4580
+ }
4581
+ function traceStateWarnings(data) {
4582
+ const record = asRecord(data);
4583
+ if (asString(record?.trace_state) === "unavailable") {
4584
+ return ["Trace processing state could not be read, so processing_status is null on every row; do not read missing detections as clean."];
4585
+ }
4586
+ const rows = Array.isArray(record?.conversations) ? record.conversations.map(asRecord) : [];
4587
+ const pending = rows.filter((row) => asString(row?.processing_status) === "pending").length;
4588
+ const errored = rows.filter((row) => asString(row?.error_message)).length;
4589
+ const warnings = [];
4590
+ if (pending > 0) {
4591
+ warnings.push(`${pending} of ${rows.length} trace(s) on this page are not fully processed yet (processing_status=pending), so their detections may be incomplete; missing detections do not mean they are clean.`);
4592
+ }
4593
+ if (errored > 0) {
4594
+ warnings.push(`${errored} trace(s) on this page have a processing error (error_message); their detections may be missing.`);
4595
+ }
4596
+ return warnings;
4597
+ }
4598
+ function singleTraceStateWarnings(value) {
4599
+ const traceState = asRecord(value);
4600
+ const warnings = [];
4601
+ if (asString(traceState?.processing_status) === "pending") {
4602
+ warnings.push("This trace is not fully processed yet (trace_state.processing_status=pending), so its detections may be incomplete; missing detections do not mean it is clean.");
4603
+ }
4604
+ if (asString(traceState?.error_message)) {
4605
+ warnings.push("This trace has a processing error (trace_state.error_message); its detections may be missing.");
4606
+ }
4607
+ return warnings;
4608
+ }
4609
+ function customSignalProcessingWarning(data, rows) {
4610
+ const record = asRecord(data);
4611
+ const processing = asRecord(record?.processing);
4612
+ const list = record?.[rows];
4613
+ if (!processing || !Array.isArray(list) || list.length > 0)
4614
+ return [];
4615
+ if (processing.enabled === false) {
4616
+ return [
4617
+ "Custom-signal judging is disabled for this tenant (signals.custom_signals = false), so no hits does NOT mean the traces are clean. " + "Enable it in Settings → Account → Signal processing; only conversations judged after enabling get hits."
4618
+ ];
4619
+ }
4620
+ if (processing.enabled === null) {
4621
+ return ["Could not confirm whether custom-signal judging is enabled for this tenant, so treat no hits with caution."];
4622
+ }
4623
+ return [];
4624
+ }
4509
4625
  var CONTEXT_USAGE = "Usage: moda traces get <conversation_id> [--msg-index=N (alias --message-index)] [--window=0-5 | --metadata-only]";
4510
4626
  var CONTEXT_ALL_USAGE = "Usage: moda traces get <conversation_id> --all [--from=N] [--max-messages=N]";
4511
4627
  var CONTEXT_BATCH_USAGE = `Usage: moda traces get <id>[@msg_index] <id>[@msg_index] ... | --ids-from=-|<file> [--window=0-5 | --metadata-only | --all [--from=N] [--max-messages=N]] (max ${BATCH_MAX_TARGETS} targets)`;
@@ -4611,6 +4727,7 @@ async function readFullTranscript(conversationId, opts = {}) {
4611
4727
  let total = 0;
4612
4728
  let summary = null;
4613
4729
  let ordering;
4730
+ let traceState;
4614
4731
  let nextFrom = null;
4615
4732
  let cursor = start;
4616
4733
  let readBytes = 0;
@@ -4627,6 +4744,7 @@ async function readFullTranscript(conversationId, opts = {}) {
4627
4744
  total = asNumber(page.total_messages) ?? 0;
4628
4745
  summary = stripLoneSurrogates(page.summary ?? null);
4629
4746
  ordering = stripLoneSurrogates(asRecord(page.ordering) ?? undefined);
4747
+ traceState = page.trace_state;
4630
4748
  }
4631
4749
  const batch = stripLoneSurrogates(pageMessages(page));
4632
4750
  messages.push(...batch);
@@ -4678,6 +4796,7 @@ async function readFullTranscript(conversationId, opts = {}) {
4678
4796
  next_from: next,
4679
4797
  summary,
4680
4798
  ...ordering ? { ordering } : {},
4799
+ ...traceState !== undefined ? { trace_state: traceState } : {},
4681
4800
  messages: returned
4682
4801
  },
4683
4802
  warnings: out,
@@ -4699,7 +4818,7 @@ async function readContextItem(params, inputWarnings, budget) {
4699
4818
  fits: fits ? (page) => fits(page.data, { warnings: page.warnings, nextCommands: page.nextCommands }) : undefined,
4700
4819
  maxBytes: budget?.maxBytes
4701
4820
  });
4702
- const fullWarnings = [...inputWarnings, ...full.warnings];
4821
+ const fullWarnings = [...inputWarnings, ...singleTraceStateWarnings(asRecord(full.data)?.trace_state), ...full.warnings];
4703
4822
  return {
4704
4823
  data: full.data,
4705
4824
  options: {
@@ -4721,7 +4840,7 @@ async function readContextItem(params, inputWarnings, budget) {
4721
4840
  const data = params.metadata_only === true ? await readContextMetadataOnly(contextPath, query2) : await callDataAPI(`${contextPath}${queryString}`);
4722
4841
  const ctxRecord = asRecord(data) ?? {};
4723
4842
  throwIfNotFound("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0);
4724
- const warnings = [...inputWarnings];
4843
+ const warnings = [...inputWarnings, ...singleTraceStateWarnings(ctxRecord.trace_state)];
4725
4844
  const nextCommands = [];
4726
4845
  if (params.window !== undefined && params.window > CONTEXT_MAX_WINDOW) {
4727
4846
  const center = asNumber(asRecord(ctxRecord.context)?.center_index) ?? params.msg_index ?? 0;
@@ -5160,6 +5279,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5160
5279
  searchWarnings.push("--sort=slowest: no trace in this page has a known duration (synthetic timestamps), so the order is not by duration. Use --sort=longest (message count) instead.");
5161
5280
  }
5162
5281
  }
5282
+ searchWarnings.push(...traceStateWarnings(data));
5163
5283
  const writeOptions = searchWarnings.length > 0 ? { warnings: searchWarnings } : undefined;
5164
5284
  if (params.include_world_state === true) {
5165
5285
  const enriched = asRecord(data) ?? {};
@@ -5327,6 +5447,15 @@ async function runCommand(command, positional, flags, positionals = positional ?
5327
5447
  query2.set("limit", params.limit.toString());
5328
5448
  if (params.offset !== undefined)
5329
5449
  query2.set("offset", params.offset.toString());
5450
+ if (readsPerTrace("frustrations", params, ["user_id", "conversation_id", "include_window"])) {
5451
+ query2.set("family", "frustration");
5452
+ setTraceFilters(query2, params, TRACE_GRAIN_FLAGS.frustrations);
5453
+ const data2 = await callDataAPI(`/emotions?${query2.toString()}`);
5454
+ const warnings = processingDisabledWarning(data2, "frustration");
5455
+ const summary = countingSummary(data2);
5456
+ context.output.writeData(data2, { ...summary ? { summary } : {}, ...warnings.length > 0 ? { warnings } : {} });
5457
+ break;
5458
+ }
5330
5459
  if (params.user_id)
5331
5460
  query2.set("user_id", params.user_id);
5332
5461
  if (params.conversation_id)
@@ -5338,7 +5467,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5338
5467
  query2.set("include_context", "0");
5339
5468
  const data = frustrationsFromEmotions(await callDataAPI(`/emotions?${query2.toString()}`));
5340
5469
  const anchored = withFrustrationAnchors(data);
5341
- await printWithOptionalWindows(agentMode && !includeWindow ? withoutDetectionWindows(anchored, "frustrations", "conversation") : anchored, "frustrations", includeWindow, params.window ?? 1, context.output, processingDisabledWarning(data, "frustration"), agentMode && includeWindow ? (payload) => withoutRepeatedFrustrationWindow(payload) : undefined);
5470
+ await printWithOptionalWindows(agentMode && !includeWindow ? withoutDetectionWindows(anchored, "frustrations", "conversation") : anchored, "frustrations", includeWindow, params.window ?? 1, context.output, processingDisabledWarning(data, "frustration"), agentMode && includeWindow ? (payload) => withoutRepeatedFrustrationWindow(payload) : undefined, [], countingSummary(data));
5342
5471
  break;
5343
5472
  }
5344
5473
  case "tool-failures": {
@@ -5346,7 +5475,98 @@ async function runCommand(command, positional, flags, positionals = positional ?
5346
5475
  const params = parseSpecFlags("tool-failures", args, command);
5347
5476
  const queryString = params.days_back ? `?days_back=${params.days_back}` : "";
5348
5477
  const data = await callDataAPI(`/tool-failures${queryString}`);
5349
- context.output.writeData(data);
5478
+ const daysBack = params.days_back ?? 7;
5479
+ const failing = (Array.isArray(asRecord(data)?.tools) ? asRecord(data).tools : []).map((row) => asString(asRecord(row)?.tool_name)).filter((name) => Boolean(name)).slice(0, TOOL_FAILURE_CATALOG_LINKS);
5480
+ const nextCommands = failing.flatMap((name, index) => [
5481
+ ...index === 0 ? [{ command: toolFailureExamplesCommand(name, daysBack), purpose: `Read failure examples of ${name}, the tool with the most failures.`, mutability: "read", requires_approval: false }] : [],
5482
+ { command: toolCatalogGetCommand(name, daysBack), purpose: `Calls, recorded schema, usage over time and failure categories of ${name}.`, mutability: "read", requires_approval: false }
5483
+ ]);
5484
+ context.output.writeData(data, nextCommands.length > 0 ? { nextCommands } : undefined);
5485
+ break;
5486
+ }
5487
+ case "tool-catalog": {
5488
+ const params = parseSpecFlags("tool-catalog", flagsToArgs(flags), command);
5489
+ const daysBack = params.days_back ?? 7;
5490
+ const limit = params.limit ?? TOOL_CATALOG_DEFAULT_LIMIT;
5491
+ const offset = params.offset ?? 0;
5492
+ const sort = params.sort ?? "calls";
5493
+ const query2 = new URLSearchParams({ days_back: String(daysBack), sort, limit: String(limit), offset: String(offset) });
5494
+ if (params.search)
5495
+ query2.set("search", params.search);
5496
+ if (params.direction)
5497
+ query2.set("direction", params.direction);
5498
+ const data = asRecord(await callDataAPI(`/tools?${query2.toString()}`)) ?? {};
5499
+ const pagination = asRecord(data.pagination);
5500
+ const tools = Array.isArray(data.tools) ? data.tools.map((row) => asRecord(row)).filter((row) => row !== null) : [];
5501
+ const listFlags = [
5502
+ `--days-back=${daysBack}`,
5503
+ ...sort !== "calls" ? [`--sort=${sort}`] : [],
5504
+ ...params.search ? [`--search=${shellArg(params.search)}`] : [],
5505
+ ...params.direction ? [`--direction=${params.direction}`] : []
5506
+ ];
5507
+ const nextCommands = [];
5508
+ const nextOffset = asNumber(pagination?.next_offset);
5509
+ if (pagination?.has_more === true && nextOffset !== null && nextOffset <= 1e4) {
5510
+ nextCommands.push({
5511
+ command: ["moda tools list", ...listFlags, `--limit=${limit}`, `--offset=${nextOffset}`].join(" "),
5512
+ purpose: `Read the next page: tools ${nextOffset + 1}-${Math.min(nextOffset + limit, asNumber(pagination.total) ?? nextOffset + limit)} of ${asNumber(pagination.total) ?? "more"}.`,
5513
+ mutability: "read",
5514
+ requires_approval: false
5515
+ });
5516
+ }
5517
+ const top = asString(tools[0]?.tool_name);
5518
+ if (top) {
5519
+ nextCommands.push({ command: toolCatalogGetCommand(top, daysBack), purpose: `Recorded schema, usage over time and failure categories of ${top}, the first tool on this page.`, mutability: "read", requires_approval: false });
5520
+ }
5521
+ const warnings = tools.length === 0 ? [`No tool calls recorded in the last ${daysBack} day(s)${params.search || params.direction ? " that match the filters" : ""}. Widen --days-back${params.search || params.direction ? " or drop --search/--direction" : ""}.`] : [];
5522
+ context.output.writeData(data, {
5523
+ ...warnings.length > 0 ? { warnings } : {},
5524
+ ...nextCommands.length > 0 ? { nextCommands } : {}
5525
+ });
5526
+ break;
5527
+ }
5528
+ case "tool-catalog-detail": {
5529
+ if (!positional) {
5530
+ throw new CliInputError("<tool_name> is required", "Usage: moda tools get <tool_name> [--days-back=N] [--full]", "missing_positional", {
5531
+ field: "<tool_name>",
5532
+ suggestedCommands: ["moda tools list"]
5533
+ });
5534
+ }
5535
+ const params = parseSpecFlags("tool-catalog-detail", flagsToArgs(flags, "tool_name", positional), command);
5536
+ const daysBack = params.days_back ?? 7;
5537
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
5538
+ let raw;
5539
+ try {
5540
+ raw = asRecord(await callDataAPI(`/tools/${encodeURIComponent(params.tool_name)}?days_back=${daysBack}`)) ?? {};
5541
+ } catch (error) {
5542
+ if (!(error instanceof ApiError) || error.statusCode !== 404)
5543
+ throw error;
5544
+ throw new CliNotFoundError("tool", params.tool_name, `Tool "${params.tool_name}" has no recorded calls in the last ${daysBack} day(s): the name may be mistyped, or the tool was not called in this window.`, `moda tools list --search=${shellArg(params.tool_name)} --days-back=${daysBack}`);
5545
+ }
5546
+ const { data, shortened } = shapeToolCatalogDetail(raw, { daysBack, shorten: agentMode && params.full !== true });
5547
+ const warnings = [];
5548
+ if (shortened > 0) {
5549
+ warnings.push(`Agent output capped ${shortened} list(s) or value(s): at most 20 observed fields with 3 common values each, 5 recent calls, and 200 characters per input or sample error (the *_total fields give the full counts). Add --full for everything. The registered schema is never cut.`);
5550
+ }
5551
+ const definition = asRecord(data.definition);
5552
+ if (definition && definition.registered === null) {
5553
+ warnings.push(`No registered definition for "${params.tool_name}"; definition.observed_fields is the payload shape seen in recorded calls. Register tools with \`moda registry push\`.`);
5554
+ }
5555
+ const failureBlock = asRecord(data.failure_categories);
5556
+ const totalFailures = asNumber(failureBlock?.total_failures) ?? 0;
5557
+ const nextCommands = [];
5558
+ if (totalFailures > 0) {
5559
+ nextCommands.push({ command: toolFailureExamplesCommand(params.tool_name, daysBack), purpose: `Read the ${totalFailures} failure detection row(s) of ${params.tool_name}, with error text and tool input.`, mutability: "read", requires_approval: false });
5560
+ const first = asRecord(Array.isArray(failureBlock?.categories) ? failureBlock.categories[0] : undefined);
5561
+ const contextCommand = asString(first?.context_command);
5562
+ if (contextCommand) {
5563
+ nextCommands.push({ command: contextCommand, purpose: `Open the newest failure of the top category (${asString(first?.category) ?? "unknown"}) in its trace.`, mutability: "read", requires_approval: false });
5564
+ }
5565
+ }
5566
+ context.output.writeData(data, {
5567
+ ...warnings.length > 0 ? { warnings } : {},
5568
+ ...nextCommands.length > 0 ? { nextCommands } : {}
5569
+ });
5350
5570
  break;
5351
5571
  }
5352
5572
  case "tool-failure-detail": {
@@ -5401,7 +5621,12 @@ async function runCommand(command, positional, flags, positionals = positional ?
5401
5621
  out.push(`Showing the ${TOOL_FAILURE_AGENT_SUBTYPES} most frequent of ${subtypes.length} failure subtypes; --json lists all of them.`);
5402
5622
  }
5403
5623
  return trimmed;
5404
- });
5624
+ }, [{
5625
+ command: toolCatalogGetCommand(params.tool_name, params.days_back ?? 7),
5626
+ purpose: subtypeCount === 0 && exampleCount === 0 ? `Check whether ${params.tool_name} was called at all in this window (it answers not found when it was not).` : `Call count, success rate, recorded schema and usage over time of ${params.tool_name}.`,
5627
+ mutability: "read",
5628
+ requires_approval: false
5629
+ }]);
5405
5630
  break;
5406
5631
  }
5407
5632
  case "problem-impact": {
@@ -5678,7 +5903,8 @@ async function runCommand(command, positional, flags, positionals = positional ?
5678
5903
  query2.set("offset", params.offset.toString());
5679
5904
  const queryString = query2.toString() ? `?${query2.toString()}` : "";
5680
5905
  const data = await callDataAPI(`/custom-signals/${id}/detections${queryString}`);
5681
- context.output.writeData(data);
5906
+ const warnings = customSignalProcessingWarning(data, "detections");
5907
+ context.output.writeData(data, warnings.length > 0 ? { warnings } : undefined);
5682
5908
  break;
5683
5909
  }
5684
5910
  case "trace-signals": {
@@ -5686,7 +5912,8 @@ async function runCommand(command, positional, flags, positionals = positional ?
5686
5912
  throw new CliInputError("<conversation_id> is required", "Usage: moda detections list --family=custom_signal --conversation-id=<conversation_id>");
5687
5913
  }
5688
5914
  const data = await callDataAPI(`/conversations/${encodeURIComponent(positional)}/custom-signals`);
5689
- context.output.writeData(data);
5915
+ const warnings = customSignalProcessingWarning(data, "detections");
5916
+ context.output.writeData(data, warnings.length > 0 ? { warnings } : undefined);
5690
5917
  break;
5691
5918
  }
5692
5919
  case "signal-label": {
@@ -5904,6 +6131,14 @@ async function runCommand(command, positional, flags, positionals = positional ?
5904
6131
  query2.set("offset", params.offset.toString());
5905
6132
  if (params.family)
5906
6133
  query2.set("family", params.family);
6134
+ if (readsPerTrace("emotions", params, ["user_id", "conversation_id", "include_window"])) {
6135
+ setTraceFilters(query2, params, TRACE_GRAIN_FLAGS.emotions);
6136
+ const data2 = await callDataAPI(`/emotions?${query2.toString()}`);
6137
+ const warnings = processingDisabledWarning(data2, "emotion");
6138
+ const summary2 = countingSummary(data2);
6139
+ context.output.writeData(data2, { ...summary2 ? { summary: summary2 } : {}, ...warnings.length > 0 ? { warnings } : {} });
6140
+ break;
6141
+ }
5907
6142
  if (params.user_id)
5908
6143
  query2.set("user_id", params.user_id);
5909
6144
  if (params.conversation_id)
@@ -5916,7 +6151,8 @@ async function runCommand(command, positional, flags, positionals = positional ?
5916
6151
  const processingWarnings = processingDisabledWarning(raw, "emotion");
5917
6152
  const record = asRecord(raw);
5918
6153
  const data = agentMode && params.include_window !== true && record ? withoutDetectionWindows(record, "detections", "conversation_context") : raw;
5919
- context.output.writeData(data, processingWarnings.length > 0 ? { warnings: processingWarnings } : undefined);
6154
+ const summary = countingSummary(data);
6155
+ context.output.writeData(data, summary || processingWarnings.length > 0 ? { ...summary ? { summary } : {}, ...processingWarnings.length > 0 ? { warnings: processingWarnings } : {} } : undefined);
5920
6156
  break;
5921
6157
  }
5922
6158
  case "laziness": {
@@ -5933,9 +6169,21 @@ async function runCommand(command, positional, flags, positionals = positional ?
5933
6169
  query2.set("conversation_id", params.conversation_id);
5934
6170
  if (params.family)
5935
6171
  query2.set("family", params.family);
6172
+ if (params.conversation_id) {
6173
+ rejectInapplicableFlags(command, params, ["search", "status", "sort", "order"], "to one trace's detections (--conversation-id); they filter and order the trace list");
6174
+ }
6175
+ if (params.search)
6176
+ query2.set("search", params.search);
6177
+ if (params.status)
6178
+ query2.set("status", params.status);
6179
+ if (params.sort)
6180
+ query2.set("sort", params.sort);
6181
+ if (params.order)
6182
+ query2.set("order", params.order);
5936
6183
  const queryString = query2.toString() ? `?${query2.toString()}` : "";
5937
6184
  const data = await callDataAPI(`/laziness${queryString}`);
5938
- context.output.writeData(data);
6185
+ const summary = countingSummary(data);
6186
+ context.output.writeData(data, summary ? { summary } : undefined);
5939
6187
  break;
5940
6188
  }
5941
6189
  case "hallucinations": {
@@ -5948,13 +6196,18 @@ async function runCommand(command, positional, flags, positionals = positional ?
5948
6196
  query2.set("limit", params.limit.toString());
5949
6197
  if (params.offset !== undefined)
5950
6198
  query2.set("offset", params.offset.toString());
5951
- if (params.conversation_id)
5952
- query2.set("conversation_id", params.conversation_id);
5953
- if (params.kind)
5954
- query2.set("kind", params.kind);
6199
+ if (readsPerTrace("hallucinations", params, ["conversation_id", "kind"])) {
6200
+ setTraceFilters(query2, params, TRACE_GRAIN_FLAGS.hallucinations);
6201
+ } else {
6202
+ if (params.conversation_id)
6203
+ query2.set("conversation_id", params.conversation_id);
6204
+ if (params.kind)
6205
+ query2.set("kind", params.kind);
6206
+ }
5955
6207
  const queryString = query2.toString() ? `?${query2.toString()}` : "";
5956
6208
  const data = await callDataAPI(`/hallucinations${queryString}`);
5957
- context.output.writeData(data);
6209
+ const summary = countingSummary(data);
6210
+ context.output.writeData(data, summary ? { summary } : undefined);
5958
6211
  break;
5959
6212
  }
5960
6213
  case "step-scores": {
@@ -6143,7 +6396,7 @@ var commandRegistry = createCommandRegistry([
6143
6396
  resetApiRequestCountBeforeRun: true,
6144
6397
  telemetry: "result-and-error",
6145
6398
  handler: async (context) => {
6146
- const { runInit } = await import("./index-75vcntpe.js");
6399
+ const { runInit } = await import("./index-y5jnz2t2.js");
6147
6400
  if (context.outputMode === "agent-stream") {
6148
6401
  context.output.writeEvent({
6149
6402
  event: "started",
@@ -6193,7 +6446,7 @@ var commandRegistry = createCommandRegistry([
6193
6446
  resetApiRequestCountBeforeRun: true,
6194
6447
  telemetry: "result-and-error",
6195
6448
  handler: async (context) => {
6196
- const { runProvision } = await import("./provision-y5bdbh4y.js");
6449
+ const { runProvision } = await import("./provision-ghca9d54.js");
6197
6450
  return runProvision(context, {
6198
6451
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
6199
6452
  });
@@ -6919,6 +7172,33 @@ var commandRegistry = createCommandRegistry([
6919
7172
  telemetry: "result-and-error",
6920
7173
  handler: canonicalNounHandler
6921
7174
  },
7175
+ {
7176
+ name: "tools",
7177
+ description: NOUN_SUMMARIES.tools,
7178
+ examples: [...leavesOf("tools").flatMap((leaf) => leaf.examples.slice(0, 2))],
7179
+ subcommands: treeSubcommandHelp("tools"),
7180
+ auth: "api-key",
7181
+ outputModes: ["human", "json", "agent"],
7182
+ mutability: "read",
7183
+ validateConfigBeforeRun: false,
7184
+ resetApiRequestCountBeforeRun: false,
7185
+ telemetry: "result-and-error",
7186
+ handler: canonicalNounHandler
7187
+ },
7188
+ legacyCommand({
7189
+ name: "tool-catalog",
7190
+ description: "The Tool catalog: every tool called in the window with calls, failed calls, success rate, effect direction and last seen",
7191
+ examples: ["moda tools list --sort=failure_rate --limit=10"],
7192
+ hidden: true,
7193
+ ...dataApiDefaults
7194
+ }),
7195
+ legacyCommand({
7196
+ name: "tool-catalog-detail",
7197
+ description: "One tool's calls, recorded schema and observed payload fields, usage over time and top failure categories",
7198
+ examples: ["moda tools get <tool_name>"],
7199
+ hidden: true,
7200
+ ...dataApiDefaults
7201
+ }),
6922
7202
  {
6923
7203
  name: "review",
6924
7204
  description: NOUN_SUMMARIES.review,