@moda-ai/cli 1.55.25 → 1.55.27

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 (34) hide show
  1. package/dist/{agent-t7dxmpdq.js → agent-vp9prdma.js} +8 -8
  2. package/dist/{cli-qycsmxev.js → cli-0pkc8jhg.js} +3 -3
  3. package/dist/{cli-mebf5vtr.js → cli-4h0ave0f.js} +5 -5
  4. package/dist/{cli-m0045npe.js → cli-6et4z504.js} +10 -8
  5. package/dist/{cli-9hc5bg2r.js → cli-ccjfwzqx.js} +1 -1
  6. package/dist/{cli-0wr3483h.js → cli-hmjdgxrn.js} +1 -1
  7. package/dist/{cli-9btx12wp.js → cli-pg5qfmqc.js} +1 -1
  8. package/dist/{cli-m805msp6.js → cli-q9nsvqqg.js} +14 -14
  9. package/dist/{cli-7xc585hc.js → cli-qwgct6x7.js} +7 -6
  10. package/dist/{cli-dve50x7p.js → cli-r5pp7qny.js} +140 -455
  11. package/dist/{cli-qvg26twp.js → cli-v8q7sd7g.js} +38 -13
  12. package/dist/cli-vdkwkkp5.js +567 -0
  13. package/dist/{cli-dn91fb56.js → cli-wzds257x.js} +92 -49
  14. package/dist/cli.js +986 -362
  15. package/dist/{doctor-q21mr5ya.js → doctor-wmre3mr7.js} +8 -8
  16. package/dist/{fix-0qdtdz5h.js → fix-75s9s0d6.js} +45 -47
  17. package/dist/{harness-vzy7n7ea.js → harness-a7tb9a23.js} +5 -5
  18. package/dist/{harness-github-actions-atc5bbkj.js → harness-github-actions-6v4wydb8.js} +5 -5
  19. package/dist/{index-4b1ybz51.js → index-91bpc8g8.js} +15 -14
  20. package/dist/{production-intelligence-c8e0xw3n.js → production-intelligence-7nqddd4f.js} +88 -28
  21. package/dist/{profile-commands-6e2dgv72.js → profile-commands-49yn02yg.js} +5 -4
  22. package/dist/prompt-source-mcp.js +5 -5
  23. package/dist/{prompts-3h5jcjrw.js → prompts-17wyrst6.js} +6 -6
  24. package/dist/{provision-q86phh4a.js → provision-bc3h68e1.js} +5 -5
  25. package/dist/{registry-s2vdsfw8.js → registry-fpzhjznj.js} +3 -3
  26. package/dist/{skills-vq3njc8a.js → skills-ccdbqghj.js} +5 -5
  27. package/dist/{sync-hq9dpqpr.js → sync-hkxce5zh.js} +7 -7
  28. package/package.json +1 -1
  29. package/skills/integration/index.json +2 -2
  30. package/skills/moda-cli/SKILL.md +4 -1
  31. package/skills/moda-cli/references/dashboard-parity.md +1 -1
  32. package/skills/moda-cli/references/output-protocol.md +35 -10
  33. package/skills/moda-cli/references/search-and-traces.md +20 -2
  34. package/dist/cli-bb7133m7.js +0 -144
@@ -1,6 +1,12 @@
1
1
  import {
2
- INTELLIGENCE_SCHEMA_VERSION
3
- } from "./cli-bb7133m7.js";
2
+ INTELLIGENCE_SCHEMA_VERSION,
3
+ asNumber,
4
+ asRecord,
5
+ asString,
6
+ contextTarget,
7
+ frustrationAnchorIndex,
8
+ frustrationsFromEmotions
9
+ } from "./cli-vdkwkkp5.js";
4
10
  import {
5
11
  renderMarkdownForTerminal,
6
12
  shouldColorTerminalOutput,
@@ -10,25 +16,20 @@ import {
10
16
  import {
11
17
  callControlAPI,
12
18
  callDataAPI
13
- } from "./cli-9btx12wp.js";
19
+ } from "./cli-pg5qfmqc.js";
14
20
  import {
15
21
  CliAuthError,
16
22
  CliInputError,
17
23
  EXIT_DEGRADED,
18
24
  EXIT_OK,
25
+ apiErrorStatus,
19
26
  apiKeyHeaders,
20
- asNumber,
21
- asRecord,
22
- asString,
23
- contextTarget,
24
- frustrationAnchorIndex,
25
- frustrationsFromEmotions,
26
27
  recordApiRequest,
27
28
  resolveApiKey,
28
29
  resolveModaBaseUrl,
29
30
  safeWriteStderr,
30
- shellWord
31
- } from "./cli-dve50x7p.js";
31
+ shellArg
32
+ } from "./cli-r5pp7qny.js";
32
33
  import"./cli-0v6na3yp.js";
33
34
 
34
35
  // src/production-intelligence.ts
@@ -406,6 +407,9 @@ var OVERVIEW_SCHEMA_VERSION = "production_overview.v0.1";
406
407
  var ASK_SCHEMA_VERSION = "production_ask.v0.1";
407
408
  var INVESTIGATION_PROBLEM_LIMIT = 3;
408
409
  var INVESTIGATION_PROBLEM_SLOTS = INVESTIGATION_PROBLEM_LIMIT;
410
+ function isAuthFailure(error) {
411
+ return error instanceof CliAuthError || apiErrorStatus(error) === 401;
412
+ }
409
413
  async function runProductionCommand(context) {
410
414
  const daysBack = daysBackFlag(context.flags);
411
415
  if (context.command === "overview") {
@@ -419,7 +423,8 @@ async function runProductionCommand(context) {
419
423
  if (!context.quiet)
420
424
  console.log(renderOverviewBriefingHuman(briefing));
421
425
  } else {
422
- context.output.writeData(briefing, overviewAgentOptions(briefing));
426
+ const { rawOverview: _rawOverview, ...withoutRaw } = briefing;
427
+ context.output.writeData(withoutRaw, overviewAgentOptions(briefing));
423
428
  }
424
429
  return { exitCode: 0 };
425
430
  }
@@ -448,7 +453,7 @@ async function runProductionCommand(context) {
448
453
  toolName: context.flags.tool
449
454
  });
450
455
  writeInvestigation(context, investigation);
451
- return { exitCode: 0 };
456
+ return { exitCode: investigation.degraded ? EXIT_DEGRADED : EXIT_OK };
452
457
  }
453
458
  if (context.command === "investigate") {
454
459
  const investigation = await investigateProduction({
@@ -458,7 +463,7 @@ async function runProductionCommand(context) {
458
463
  toolName: context.flags.tool
459
464
  });
460
465
  writeInvestigation(context, investigation);
461
- return { exitCode: 0 };
466
+ return { exitCode: investigation.degraded ? EXIT_DEGRADED : EXIT_OK };
462
467
  }
463
468
  throw new CliInputError(`Unknown production command '${context.command}'`);
464
469
  }
@@ -522,11 +527,18 @@ async function investigateProduction(options) {
522
527
  if (result.warning)
523
528
  warnings.push(result.warning);
524
529
  }
530
+ const failed = Object.entries(sources).filter(([, result]) => result.status === "unavailable");
531
+ const authFailure = failed.find(([, result]) => isAuthFailure(result.error));
532
+ if (authFailure)
533
+ throw authFailure[1].error;
534
+ if (failed.length > 0 && failed.length === Object.keys(sources).length)
535
+ throw failed[0][1].error;
536
+ const failedSources = failed.map(([key]) => key);
525
537
  if (options.toolName && tools.status === "ok" && toolRows(tools.data, options.toolName).every((row) => row.count <= 0)) {
526
538
  warnings.push(`No failures found for tool "${options.toolName}" in the last ${options.daysBack} day(s) — the tool may have no failures in this window, or the name may not exist in this tenant. ` + "Run `moda detections tools` to list tools with recorded failures, or widen --days-back.");
527
539
  }
528
540
  if (options.conversationId) {
529
- warnings.push(`Scoped to trace ${options.conversationId} for frustration evidence only; overview and tool failures are tenant-wide. ` + `Open the trace itself with \`moda traces spans ${options.conversationId}\`.`);
541
+ warnings.push(`Scoped to trace ${options.conversationId} for frustration evidence only; overview and tool failures are tenant-wide. ` + `Open the trace itself with \`moda traces spans ${shellArg(options.conversationId)}\`.`);
530
542
  }
531
543
  const evidenceRefs = [];
532
544
  const findings = [];
@@ -537,12 +549,17 @@ async function investigateProduction(options) {
537
549
  findings.push(...problemFindings(problems.data, options.daysBack, evidenceRefs));
538
550
  }
539
551
  if (findings.length === 0) {
540
- findings.push(insufficientDataFinding(overview.data, evidenceRefs));
552
+ findings.push(failedSources.length > 0 ? incompleteDataFinding(failedSources, Object.keys(sources).length) : insufficientDataFinding(overview.data, evidenceRefs));
541
553
  }
542
554
  findings.sort(compareFindings);
543
555
  const boundedFindings = capFindings(findings, 8, INVESTIGATION_PROBLEM_SLOTS);
544
556
  const nextCommands = nextCommandsForFindings(boundedFindings, options.daysBack, !options.failureOnly);
545
557
  const summary = summarizeInvestigation(boundedFindings);
558
+ if (failedSources.length > 0) {
559
+ summary.text = `Incomplete: could not load ${failedSources.join(", ")}, so findings cover only ${Object.keys(sources).filter((key) => !failedSources.includes(key)).join(", ")}. ${summary.text}`;
560
+ if (summary.confidence === "high" || summary.confidence === "medium")
561
+ summary.confidence = "low";
562
+ }
546
563
  if (options.conversationId) {
547
564
  summary.text = `${summary.text} (Only frustration evidence is scoped to trace ${options.conversationId}.)`;
548
565
  }
@@ -560,7 +577,9 @@ async function investigateProduction(options) {
560
577
  evidenceRefs: uniqueEvidenceRefs(evidenceRefs),
561
578
  nextCommands,
562
579
  warnings,
563
- sourceStatus
580
+ sourceStatus,
581
+ degraded: failedSources.length > 0,
582
+ failedSources
564
583
  };
565
584
  }
566
585
  async function askModa(options) {
@@ -592,8 +611,8 @@ async function askModa(options) {
592
611
  cwd: options.cwd,
593
612
  question: options.question
594
613
  });
595
- const top = investigation.findings[0];
596
- const answer = top ? `Moda Cloud intelligence is not available, so I synthesized this from production evidence. The strongest signal is: ${top.title}. ${top.summary}` : "Moda Cloud intelligence is not available, and the local Data API evidence did not contain a strong production signal.";
614
+ const top = investigation.findings.find((finding) => finding.kind !== "insufficient_data");
615
+ const answer = top ? `Moda Cloud intelligence is not available, so I synthesized this from production evidence${investigation.degraded ? ` (${investigation.failedSources.join(", ")} could not be loaded)` : ""}. The strongest signal is: ${top.title}. ${top.summary}` : investigation.degraded ? `Moda Cloud intelligence is not available, and ${investigation.failedSources.join(", ")} could not be loaded, so no answer could be synthesized and no issue is ruled out.` : "Moda Cloud intelligence is not available, and the local Data API evidence did not contain a strong production signal.";
597
616
  const confidence = capFallbackConfidence(investigation.summary.confidence);
598
617
  const evidenceRefs = investigation.evidenceRefs.slice(0, 12);
599
618
  const findings = investigation.findings.slice(0, 5);
@@ -717,9 +736,16 @@ function writeInvestigation(context, investigation) {
717
736
  if (context.outputMode === "human") {
718
737
  if (!context.quiet)
719
738
  console.log(renderInvestigationHuman(investigation));
739
+ if (investigation.degraded) {
740
+ safeWriteStderr(`Warning: incomplete result, could not load ${investigation.failedSources.join(", ")}.
741
+ `);
742
+ }
720
743
  return;
721
744
  }
722
- context.output.writeData(investigation, investigationAgentOptions(investigation));
745
+ context.output.writeData(investigation, {
746
+ ...investigationAgentOptions(investigation),
747
+ ...investigation.degraded ? { status: "degraded" } : {}
748
+ });
723
749
  }
724
750
  async function safeData(endpoint) {
725
751
  try {
@@ -728,7 +754,8 @@ async function safeData(endpoint) {
728
754
  return {
729
755
  data: null,
730
756
  status: "unavailable",
731
- warning: `Could not load ${endpoint}: ${error instanceof Error ? error.message : String(error)}`
757
+ warning: `Could not load ${endpoint}: ${error instanceof Error ? error.message : String(error)}`,
758
+ error
732
759
  };
733
760
  }
734
761
  }
@@ -817,7 +844,7 @@ function toolFailureFindings(data, daysBack, hints, evidenceRefs, scopedTool) {
817
844
  label: `${name}: ${count} failure(s)${subtype}`,
818
845
  endpoint: scopedTool ? `/tool-failures/${encodeURIComponent(name)}?days_back=${daysBack}` : `/tool-failures?days_back=${daysBack}`,
819
846
  toolName: name,
820
- value: tool.raw
847
+ value: { tool_name: name, failure_count: count, conversation_count: tool.conversations, ...tool.subtype ? { subtype: tool.subtype } : {} }
821
848
  });
822
849
  const location = likelyToolLocation(name, hints);
823
850
  if (location?.path) {
@@ -845,7 +872,7 @@ function toolFailureFindings(data, daysBack, hints, evidenceRefs, scopedTool) {
845
872
  id: `action_tool_detail_${slug(name)}`,
846
873
  title: `Inspect ${name} failure examples.`,
847
874
  rationale: "Examples include trace anchors and error subtypes.",
848
- command: `moda detections tools ${name} --days-back=${daysBack} --include-window`,
875
+ command: `moda detections tools ${shellArg(name)} --days-back=${daysBack} --include-window`,
849
876
  mutability: "read",
850
877
  requiresApproval: false
851
878
  }]
@@ -874,7 +901,7 @@ function frustrationFindings(data, daysBack, evidenceRefs) {
874
901
  label: quote ? `Frustration anchor: "${quote}"` : `${count} frustrated trace(s)`,
875
902
  endpoint: investigateFrustrationsEndpoint(daysBack),
876
903
  ...conversationId ? { conversationId } : {},
877
- value: first ?? summary ?? data
904
+ value: first ? frustrationEvidenceIds(first, anchorIndex) : { frustrated_count: count, at_risk_count: atRisk }
878
905
  });
879
906
  return [{
880
907
  id: "finding_frustration_rate",
@@ -891,12 +918,23 @@ function frustrationFindings(data, daysBack, evidenceRefs) {
891
918
  id: "action_frustration_window",
892
919
  title: "Read the frustration window.",
893
920
  rationale: "The user quote and nearby turns reveal what confused or blocked the user.",
894
- command: conversationId ? `moda traces get ${shellWord(contextTarget(conversationId))}${anchorIndex !== null ? ` --msg-index=${anchorIndex}` : ""} --window=3` : `moda detections list --family=frustration --days-back=${daysBack} --include-window`,
921
+ command: conversationId ? `moda traces get ${shellArg(contextTarget(conversationId))}${anchorIndex !== null ? ` --msg-index=${anchorIndex}` : ""} --window=3` : `moda detections list --family=frustration --days-back=${daysBack} --include-window`,
895
922
  mutability: "read",
896
923
  requiresApproval: false
897
924
  }]
898
925
  }];
899
926
  }
927
+ function frustrationEvidenceIds(row, anchorIndex) {
928
+ const ids = {};
929
+ for (const key of ["detection_id", "conversation_id", "trace_id", "user_id"]) {
930
+ const value = asString(row[key]);
931
+ if (value)
932
+ ids[key] = value;
933
+ }
934
+ if (anchorIndex !== null)
935
+ ids.msg_index = anchorIndex;
936
+ return ids;
937
+ }
900
938
  function problemRows(data) {
901
939
  const record = asRecord(data);
902
940
  const rows = [];
@@ -938,7 +976,7 @@ function problemFindings(data, daysBack, evidenceRefs) {
938
976
  kind: "problem",
939
977
  label: `Problem "${problem.name}" (${trustNote})`,
940
978
  endpoint: `/problems?days_back=${daysBack}&limit=${INVESTIGATION_PROBLEM_LIMIT}`,
941
- value: problem.raw
979
+ value: { problem_id: problem.id, lifecycle: problem.lifecycle, trust: problem.trust, affected_conversations: problem.affectedConversations }
942
980
  });
943
981
  const affected = problem.affectedConversations;
944
982
  return {
@@ -956,7 +994,7 @@ function problemFindings(data, daysBack, evidenceRefs) {
956
994
  id: `action_problem_${slug(problem.id)}`,
957
995
  title: `Open the Problem dossier for ${problem.name}.`,
958
996
  rationale: "The dossier has the cause, evidence, affected traces and verification state.",
959
- command: `moda problems get ${problem.id}`,
997
+ command: `moda problems get ${shellArg(problem.id)}`,
960
998
  mutability: "read",
961
999
  requiresApproval: false
962
1000
  }]
@@ -971,7 +1009,7 @@ function insufficientDataFinding(overview, evidenceRefs) {
971
1009
  kind: "data_api",
972
1010
  label: "Overview did not contain actionable production signals",
973
1011
  endpoint: "/overview",
974
- value: overview
1012
+ value: overviewMetrics(overview)
975
1013
  });
976
1014
  }
977
1015
  return {
@@ -995,6 +1033,28 @@ function insufficientDataFinding(overview, evidenceRefs) {
995
1033
  }]
996
1034
  };
997
1035
  }
1036
+ function incompleteDataFinding(failedSources, total) {
1037
+ return {
1038
+ id: "finding_incomplete_data",
1039
+ kind: "insufficient_data",
1040
+ title: `Could not check ${failedSources.join(", ")} (${failedSources.length} of ${total} sources failed)`,
1041
+ severity: "info",
1042
+ confidence: "low",
1043
+ impactScore: 10,
1044
+ rankReason: "The sources that loaded show no ranked issue, but the failed ones were not checked.",
1045
+ summary: "This is not evidence that production is healthy; re-run once the failed sources load (see warnings).",
1046
+ evidenceRefIds: [],
1047
+ likelyLocations: [],
1048
+ recommendedActions: [{
1049
+ id: "action_doctor_online",
1050
+ title: "Check connectivity and the API key.",
1051
+ rationale: "Failed reads usually mean a network, server, or credential problem.",
1052
+ command: "moda doctor --online",
1053
+ mutability: "read",
1054
+ requiresApproval: false
1055
+ }]
1056
+ };
1057
+ }
998
1058
  function normalizeCloudAsk(response, question) {
999
1059
  const record = asRecord(response);
1000
1060
  const answer = asString(record?.answer);
@@ -2,7 +2,7 @@ import {
2
2
  probeApiKey,
3
3
  redactApiKey,
4
4
  resolveApiKeyCredential
5
- } from "./cli-9hc5bg2r.js";
5
+ } from "./cli-ccjfwzqx.js";
6
6
  import {
7
7
  authFetch,
8
8
  clearAuthSession,
@@ -10,7 +10,7 @@ import {
10
10
  loadAuthSession,
11
11
  login,
12
12
  revokeCliSessionToken
13
- } from "./cli-0wr3483h.js";
13
+ } from "./cli-hmjdgxrn.js";
14
14
  import {
15
15
  CliInputError,
16
16
  DEFAULT_INGEST_URL,
@@ -34,8 +34,9 @@ import {
34
34
  saveCliConfig,
35
35
  secretFilePathFromRef,
36
36
  setActiveProfile,
37
+ shellArg,
37
38
  upsertProfile
38
- } from "./cli-dve50x7p.js";
39
+ } from "./cli-r5pp7qny.js";
39
40
  import"./cli-0v6na3yp.js";
40
41
 
41
42
  // src/profile-commands.ts
@@ -326,7 +327,7 @@ async function runProfilesCommand(context) {
326
327
  default_profile: config.active_profile,
327
328
  profiles: Object.values(config.profiles).map((profile) => serializeProfile(profile, effective)),
328
329
  migrations: config.migrations
329
- }, missing ? { warnings: [`The active profile '${effective}' (from ${source}) does not exist. Create it with \`moda profiles create ${effective}\` or select an existing profile.`] } : undefined);
330
+ }, missing ? { warnings: [`The active profile '${effective}' (from ${source}) does not exist. Create it with \`moda profiles create ${shellArg(effective)}\` or select an existing profile.`] } : undefined);
330
331
  return { exitCode: 0 };
331
332
  }
332
333
  case "use": {
@@ -5,12 +5,12 @@ import {
5
5
  inspectCodeSelectors,
6
6
  inspectPythonSelectors,
7
7
  safePromptEvidencePath
8
- } from "./cli-7xc585hc.js";
8
+ } from "./cli-qwgct6x7.js";
9
9
  import"./cli-97fnztpy.js";
10
- import"./cli-qvg26twp.js";
11
- import"./cli-dn91fb56.js";
12
- import"./cli-9btx12wp.js";
13
- import"./cli-dve50x7p.js";
10
+ import"./cli-v8q7sd7g.js";
11
+ import"./cli-wzds257x.js";
12
+ import"./cli-pg5qfmqc.js";
13
+ import"./cli-r5pp7qny.js";
14
14
  import {
15
15
  __commonJS,
16
16
  __toESM
@@ -11,16 +11,16 @@ import {
11
11
  runPromptSync,
12
12
  runPromptsCommand,
13
13
  writePromptSyncProgress
14
- } from "./cli-m805msp6.js";
14
+ } from "./cli-q9nsvqqg.js";
15
15
  import {
16
16
  promptSourceHashPayload
17
17
  } from "./cli-mm48br00.js";
18
- import"./cli-7xc585hc.js";
18
+ import"./cli-qwgct6x7.js";
19
19
  import"./cli-97fnztpy.js";
20
- import"./cli-qvg26twp.js";
21
- import"./cli-dn91fb56.js";
22
- import"./cli-9btx12wp.js";
23
- import"./cli-dve50x7p.js";
20
+ import"./cli-v8q7sd7g.js";
21
+ import"./cli-wzds257x.js";
22
+ import"./cli-pg5qfmqc.js";
23
+ import"./cli-r5pp7qny.js";
24
24
  import"./cli-0v6na3yp.js";
25
25
  export {
26
26
  writePromptSyncProgress,
@@ -1,18 +1,18 @@
1
1
  import {
2
2
  selectTenantAndCreateKey
3
- } from "./cli-qycsmxev.js";
4
- import"./cli-9hc5bg2r.js";
3
+ } from "./cli-0pkc8jhg.js";
4
+ import"./cli-ccjfwzqx.js";
5
5
  import {
6
6
  loadAuthSession
7
- } from "./cli-0wr3483h.js";
7
+ } from "./cli-hmjdgxrn.js";
8
8
  import {
9
9
  stringOption
10
- } from "./cli-qvg26twp.js";
10
+ } from "./cli-v8q7sd7g.js";
11
11
  import {
12
12
  CliAuthError,
13
13
  resolveIngestUrl,
14
14
  resolveModaBaseUrl
15
- } from "./cli-dve50x7p.js";
15
+ } from "./cli-r5pp7qny.js";
16
16
  import"./cli-0v6na3yp.js";
17
17
 
18
18
  // src/provision.ts
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  assertFlags
3
- } from "./cli-dn91fb56.js";
3
+ } from "./cli-wzds257x.js";
4
4
  import {
5
5
  callControlAPI
6
- } from "./cli-9btx12wp.js";
6
+ } from "./cli-pg5qfmqc.js";
7
7
  import {
8
8
  CliInputError,
9
9
  explicitOutputMode,
10
10
  resolveApiKey
11
- } from "./cli-dve50x7p.js";
11
+ } from "./cli-r5pp7qny.js";
12
12
  import"./cli-0v6na3yp.js";
13
13
 
14
14
  // src/registry.ts
@@ -3,11 +3,11 @@ import {
3
3
  pullSkills,
4
4
  runSkillSync,
5
5
  runSkillsCommand
6
- } from "./cli-m0045npe.js";
7
- import"./cli-qvg26twp.js";
8
- import"./cli-dn91fb56.js";
9
- import"./cli-9btx12wp.js";
10
- import"./cli-dve50x7p.js";
6
+ } from "./cli-6et4z504.js";
7
+ import"./cli-v8q7sd7g.js";
8
+ import"./cli-wzds257x.js";
9
+ import"./cli-pg5qfmqc.js";
10
+ import"./cli-r5pp7qny.js";
11
11
  import"./cli-8dtnwp9r.js";
12
12
  import"./cli-0v6na3yp.js";
13
13
  export {
@@ -1,20 +1,20 @@
1
1
  import {
2
2
  runPromptsCommand
3
- } from "./cli-m805msp6.js";
3
+ } from "./cli-q9nsvqqg.js";
4
4
  import"./cli-mm48br00.js";
5
5
  import {
6
6
  runHarnessCommand
7
- } from "./cli-7xc585hc.js";
7
+ } from "./cli-qwgct6x7.js";
8
8
  import"./cli-97fnztpy.js";
9
9
  import {
10
10
  runSkillsCommand
11
- } from "./cli-m0045npe.js";
12
- import"./cli-qvg26twp.js";
13
- import"./cli-dn91fb56.js";
14
- import"./cli-9btx12wp.js";
11
+ } from "./cli-6et4z504.js";
12
+ import"./cli-v8q7sd7g.js";
13
+ import"./cli-wzds257x.js";
14
+ import"./cli-pg5qfmqc.js";
15
15
  import {
16
16
  CliInputError
17
- } from "./cli-dve50x7p.js";
17
+ } from "./cli-r5pp7qny.js";
18
18
  import"./cli-8dtnwp9r.js";
19
19
  import"./cli-0v6na3yp.js";
20
20
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moda-ai/cli",
3
- "version": "1.55.25",
3
+ "version": "1.55.27",
4
4
  "description": "CLI for Moda: production monitoring and evals for AI agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schema_version": "moda.skill_index.v1",
3
- "bundled_at": "2026-10-15T20:30:38.730Z",
4
- "cli_version": "1.55.25",
3
+ "bundled_at": "2026-10-15T21:22:44.784Z",
4
+ "cli_version": "1.55.27",
5
5
  "skills": [
6
6
  {
7
7
  "id": "integration-cloudflare-think",
@@ -95,7 +95,10 @@ More: `references/production-intelligence.md`.
95
95
  indexes when you report.
96
96
  - Never run writes (`problems feedback`, `review`,
97
97
  `signals create|update|...`, `prompts sync|promote|ab`, `registry push`)
98
- unless the user asked. Use `--dry-run` where a command offers it.
98
+ unless the user asked. Preview with `--dry-run` (every write except
99
+ `prompts promote|ab|propose` takes it): it validates and applies nothing.
100
+ Most writes print the exact request and a `next_commands` entry that runs
101
+ it for real (see `references/output-protocol.md`).
99
102
  - An empty result in a window means "nothing in that window". Widen the window
100
103
  once before saying something never happened.
101
104
  - Batch reads instead of looping one id per call: `moda traces get` and
@@ -5,7 +5,7 @@ Loaded on demand from the moda-cli skill.
5
5
  ### 10. Everything the dashboard does, from the CLI
6
6
 
7
7
  Every command below needs only an API key, and the tenant comes from the key.
8
- Writes listed here accept `--dry-run` (prints the exact request, sends nothing) except `problems feedback`, `review`, `problems link`, and `prompts promote|ab|propose`. Those refuse `--dry-run` before sending anything, so run them only when you mean it.
8
+ Writes listed here accept `--dry-run`: it validates the call, prints the exact request (method, endpoint, body) and sends nothing, and its `next_commands` entry is the command that sends it for real (`mutability: write`, `requires_approval: true`). That covers `problems feedback|reopen|link`, `review`, `feedback` and the `signals` writes. `prompts promote|ab|propose` refuse `--dry-run` before sending anything, so run them only when you mean it.
9
9
 
10
10
  | Dashboard | CLI |
11
11
  |---|---|
@@ -40,7 +40,7 @@ Branch on the exit code; it is stable and cheaper than parsing the payload:
40
40
  |---|---|---|
41
41
  | `0` | ok — answer is grounded in Moda Cloud intelligence | Trust it. |
42
42
  | `1` | error — bad input, unknown id (`not_found`), access denied, API/network failure | Read `errors[0].code`; retry only `network_error` / 5xx `api_error`. For `not_found`, find a valid id first (the `cause` names the command). |
43
- | `3` | degraded — Moda Cloud was unavailable; answer synthesized from local Data API evidence | Answer is present but lower-trust; verify before acting. |
43
+ | `3` | degraded — Moda Cloud was unavailable and the answer was synthesized from local Data API evidence (`ask`), or some sources failed to load (`investigate`/`failures`, named in `data.failedSources`) | Answer is present but lower-trust or partial; verify before acting, and never read a partial result as "no issues". |
44
44
  | `4` | auth required — no API key, or the API rejected it (HTTP 401) | Set `MODA_API_KEY` or run the `login_command` from the `auth` payload (`moda auth login --api-key`), then re-run. |
45
45
  | `5` | input required — a choice is needed that the non-interactive run could not answer | Pick a choice from the `input_request` payload and re-invoke the same command with that choice's `resume_flags` appended. |
46
46
  | `130` | cancelled | Treat as interrupted or closed pipe; do not retry blindly. |
@@ -195,17 +195,42 @@ Treat an answer as degraded if **any** of these hold:
195
195
  that text stays whole, and the error message says whether `data` is whole
196
196
  or bounded with its complete copy at `truncation.data.full_output_path`.
197
197
  You can also page with a smaller `--limit` and
198
- `--offset`, or rerun with `--json` (no byte limit).
198
+ `--offset`, or rerun with `--json` (no byte limit). Commands that read
199
+ per-row extras (`--include-window`, `--include-world-state`, batch reads)
200
+ stop reading once the budget is spent; rows they did not enrich carry
201
+ `window_skipped` / `world_state_skipped: "agent_output_budget"`.
202
+ - **`--json` is compact when piped.** `--json` prints one line of JSON when
203
+ stdout is not a terminal (indented on a terminal); `--pretty` indents it
204
+ anyway. `--json` prints the payload as read: `--profile` is stamped only on
205
+ the agent envelope's generated commands (`next_commands`, `*_command`
206
+ fields), never on trace content.
199
207
  - **Unknown flags fail.** A flag the command doesn't take (a typo, or a
200
208
  filter it lacks) exits `1` with the valid flag list and a "did you mean",
201
- instead of being silently ignored. Stray arguments on commands that take
202
- none fail the same way.
203
- - **`--dry-run` is only accepted where it's implemented** (for example
204
- `registry push`, `harness sync|delete|register`, `prompts sync|decide`,
205
- `skills sync|policy`, `signals` write subcommands, `problem-reopen`;
206
- `moda <command> --help` says whether a command takes it). Anywhere else it fails **before
207
- anything is sent**. It is never silently ignored, so a "preview" can't
208
- perform a real write.
209
+ instead of being silently ignored. So does a flag the chosen mode would
210
+ not send (`moda signal <id> --limit=3` without `--detections`).
211
+ - **`--days-back` and `--days_back` are the same flag.** Every flag is read
212
+ under its kebab-case name whichever spelling you type.
213
+ - **A value flag needs a value.** `--user-id` with nothing after it (often an
214
+ empty shell variable) exits `1` naming the flag instead of sending the
215
+ string "true". Switches such as `--include-tool-io` stay bare.
216
+ - **Numbers are plain decimal integers.** `--limit=0x10`, `--limit=1e1` and
217
+ `--limit=2.5` fail; text flags keep their text (`--search=404` searches
218
+ for "404").
219
+ - **Extra words fail.** A command that takes one id rejects a second word
220
+ instead of ignoring it. Free text joins every word: `moda traces search
221
+ refund not processed` searches "refund not processed" (same for `ask` and
222
+ `feedback`).
223
+ - **Writes take `--dry-run`** (`prompts promote|ab|propose` excepted).
224
+ - `problems feedback|reopen|link`, `review`, `feedback`, `signals` writes
225
+ and `skills policy` validate fully, send nothing, and return
226
+ `data.planned` (method, endpoint, body) plus a `next_commands` entry
227
+ that runs the write for real (`requires_approval: true`).
228
+ - `registry push`, `harness sync|delete|register`, `prompts sync|decide`
229
+ and `skills sync` return their own preview. Some ask the server to
230
+ compute it (`skills sync --dry-run` sends the local skills marked
231
+ `dryRun: true`), but none of them applies a change.
232
+ - A read refuses `--dry-run` **before anything is sent**, so a "preview"
233
+ can't perform a real write.
209
234
  - **Unknown profiles fail.** `--profile=<name>` or `MODA_PROFILE` naming a
210
235
  profile that doesn't exist exits `1` instead of falling back to another
211
236
  profile's key and tenant. Time windows differ by command (below).
@@ -110,7 +110,16 @@ moda traces get <conversation_id> --all --from=500 --max-messages=500 # continu
110
110
  ```
111
111
 
112
112
  `--all` returns `has_more`/`next_from`; when it stops at the cap, the warning
113
- prints the exact `--from` command to continue.
113
+ prints the exact `--from` command to continue. In agent output `--all` reads
114
+ only about what fits the byte budget (a ~50-message first page), so
115
+ `returned` can be well under `--max-messages`; follow `next_from`.
116
+
117
+ A window over the agent byte budget is cut around its anchor, never past it:
118
+ the requested message is always returned, the rest are kept nearest-first on
119
+ both sides, `context.from_index`/`to_index` describe what was returned
120
+ (`requested_from_index`/`requested_to_index` and `omitted_for_byte_limit`
121
+ what was asked for), and `next_commands` has an `--all --from` command for
122
+ each side that lost messages.
114
123
 
115
124
  **Several traces? Batch them in one call instead of looping `moda traces get`
116
125
  per id.** Pass up to 25 targets as positionals or one per line with
@@ -130,7 +139,9 @@ plus `succeeded`/`failed` counts. A missing trace is a per-item
130
139
  `error.code: "not_found"`, not a failed call; the exit code is 1 only when
131
140
  every target failed. When the agent byte budget would overflow, the items that
132
141
  fit are returned and `remaining_targets` plus a `next_commands` entry read the
133
- rest. One positional id keeps the single-trace output above.
142
+ rest. Agent output stops reading targets once the budget is spent, so the
143
+ targets it names were not read yet (nothing is read and then dropped). One
144
+ positional id keeps the single-trace output above.
134
145
 
135
146
  `moda traces get` returns messages whole, with their tool calls and results. An
136
147
  older Moda server cuts message text, tool inputs, and tool results at 500
@@ -148,6 +159,7 @@ moda traces spans <conversation_id> --include-raw # attach verbatim raw_event
148
159
  moda traces spans <conversation_id> --include-bodies # keep prompt/response/attribute bodies
149
160
  moda traces spans <conversation_id> --limit=1000 # ingest rows to read (default 200, max 1000)
150
161
  moda traces spans <conversation_id> --cursor=<next_cursor> # next page of a capped audit
162
+ moda traces spans <conversation_id> --cursor=<c> --span-offset=N # rest of a page cut for the agent budget
151
163
  moda traces spans <id1> <id2> <id3> # batch: up to 25 ids, one envelope
152
164
  ```
153
165
 
@@ -162,6 +174,12 @@ A full `--limit` page of ingest rows, the server's ~3 MB response budget
162
174
  (`summary.truncated_reason: "byte_limit"`) or a span cap sets both, and a
163
175
  warning plus `next_commands` give the follow-up — usually the `--cursor=` page
164
176
  from `next_cursor`; for very large traces audit one OTLP trace at a time
177
+ (see below). In agent output a page over the byte budget (the server's
178
+ smallest page, 32 KiB, is over the 24,000-byte default) keeps the most spans
179
+ that fit: `span_offset`/`next_span_offset`/`page_spans` say which,
180
+ `next_cursor` is `null` until the last spans of the page are read, and
181
+ `next_commands` has the `--span-offset=N` command that reads the rest of the
182
+ same page. Following `next_commands` never skips a span;
165
183
  (`summary.trace_ids`, `--kind=trace`). Prompt/response bodies are omitted by
166
184
  default (`{"omitted": true, "original_bytes": N}`); `--include-bodies` keeps
167
185
  them, cutting strings over 8 KB to `{"truncated": true, "original_bytes": N,