@moda-ai/cli 1.55.41 → 1.55.43

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 (33) hide show
  1. package/dist/{agent-ck6y31n2.js → agent-x1gwrrvd.js} +6 -5
  2. package/dist/{cli-xddtv3yn.js → cli-5fhqfx04.js} +1 -39
  3. package/dist/{cli-gt3yq1y5.js → cli-5y9tj6cb.js} +183 -1
  4. package/dist/{cli-f1jfrqgf.js → cli-9a0a3v13.js} +234 -17
  5. package/dist/cli-e0kbye4s.js +39 -0
  6. package/dist/{cli-ypqwcf9n.js → cli-fpd1pfvt.js} +2 -2
  7. package/dist/{cli-a8nxbtpk.js → cli-h62j4jn7.js} +2 -2
  8. package/dist/{cli-4tg0hkbz.js → cli-k5drmy8r.js} +7 -7
  9. package/dist/{cli-azage7s0.js → cli-s1w5phms.js} +3 -3
  10. package/dist/{cli-7bn406mt.js → cli-stfpr2ct.js} +2 -2
  11. package/dist/cli.js +224 -52
  12. package/dist/{doctor-p8sp6cbk.js → doctor-wrgajgev.js} +5 -4
  13. package/dist/{fix-0r974yge.js → fix-7aajsdbf.js} +1 -1
  14. package/dist/{harness-72ejenza.js → harness-1rn1hqzz.js} +4 -3
  15. package/dist/{harness-github-actions-2qc4gg2w.js → harness-github-actions-m95qvgbs.js} +4 -3
  16. package/dist/{index-w7v472w4.js → index-svfzq5rb.js} +7 -6
  17. package/dist/{production-intelligence-e5vsc6cw.js → production-intelligence-7jvfdz6b.js} +22 -5
  18. package/dist/{prompt-attribution-3987hhqz.js → prompt-attribution-hc6mcvee.js} +4 -3
  19. package/dist/prompt-source-mcp.js +4 -3
  20. package/dist/{prompts-ab-gmd10n5d.js → prompts-ab-ws66335h.js} +5 -4
  21. package/dist/{prompts-propose-q626zmm4.js → prompts-propose-a9m0p9nr.js} +5 -4
  22. package/dist/{prompts-ysm9ra72.js → prompts-xe5bgbx8.js} +4 -3
  23. package/dist/{provision-cya5rpxa.js → provision-a9kkfvp7.js} +2 -1
  24. package/dist/{registry-7xz09ry0.js → registry-j2dsfh6v.js} +1 -1
  25. package/dist/{skills-x6yszxxn.js → skills-vveagdwe.js} +4 -3
  26. package/dist/{sync-trjzvam9.js → sync-yy3fgnxe.js} +6 -5
  27. package/package.json +1 -1
  28. package/skills/integration/index.json +2 -2
  29. package/skills/moda-cli/SKILL.md +4 -1
  30. package/skills/moda-cli/references/commands.md +8 -3
  31. package/skills/moda-cli/references/dashboard-parity.md +7 -2
  32. package/skills/moda-cli/references/detections.md +20 -0
  33. package/skills/moda-cli/references/production-intelligence.md +48 -0
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  buildDoctorReport
3
- } from "./cli-a8nxbtpk.js";
3
+ } from "./cli-h62j4jn7.js";
4
4
  import"./cli-pmzh2qjy.js";
5
- import"./cli-4tg0hkbz.js";
5
+ import"./cli-k5drmy8r.js";
6
6
  import"./cli-mm48br00.js";
7
7
  import {
8
8
  readHarnessSyncState
@@ -15,8 +15,9 @@ import {
15
15
  readHarnessReport,
16
16
  validateHarnessReport
17
17
  } from "./cli-cesds766.js";
18
- import"./cli-xddtv3yn.js";
19
- import"./cli-f1jfrqgf.js";
18
+ import"./cli-5fhqfx04.js";
19
+ import"./cli-e0kbye4s.js";
20
+ import"./cli-9a0a3v13.js";
20
21
  import"./cli-0xc5htv7.js";
21
22
  import {
22
23
  resolveApiKey,
@@ -94,7 +95,7 @@ async function buildAgentContext(context) {
94
95
  const graph = readHarnessGraphIfPresent(context.cwd);
95
96
  const reportState = readHarnessReportState(context.cwd);
96
97
  const syncState = readHarnessSyncState(context.cwd);
97
- const harness = graph ? await import("./harness-72ejenza.js") : undefined;
98
+ const harness = graph ? await import("./harness-1rn1hqzz.js") : undefined;
98
99
  const topFindings = doctor.checks.filter((check) => check.status === "fail" || check.status === "warning").slice(0, 12).map(checkToFinding);
99
100
  const evidenceRefs = [
100
101
  ...doctor.checks.map(checkToEvidenceRef),
@@ -3,44 +3,6 @@ import {
3
3
  outputModeFromFlags
4
4
  } from "./cli-t0pb7qbs.js";
5
5
 
6
- // src/boolean-words.ts
7
- var BOOLEAN_TRUE_WORDS = new Set(["true", "yes", "1", "on"]);
8
- var BOOLEAN_FALSE_WORDS = new Set(["false", "no", "0", "off"]);
9
- function parseBooleanFlagValue(value) {
10
- if (typeof value === "boolean")
11
- return value;
12
- if (typeof value === "number")
13
- return value === 1 ? true : value === 0 ? false : undefined;
14
- if (typeof value !== "string")
15
- return;
16
- const text = value.trim().toLowerCase();
17
- if (BOOLEAN_TRUE_WORDS.has(text))
18
- return true;
19
- if (BOOLEAN_FALSE_WORDS.has(text))
20
- return false;
21
- return;
22
- }
23
- function flagValue(flags, name) {
24
- return flags[name] ?? flags[name.replace(/-/g, "_")];
25
- }
26
- function withoutFlag(flags, name) {
27
- const snake = name.replace(/-/g, "_");
28
- return Object.fromEntries(Object.entries(flags).filter(([key]) => key !== name && key !== snake));
29
- }
30
- function optOutFlagSet(flags, name, strict = true) {
31
- const raw = flagValue(flags, name);
32
- if (raw === undefined)
33
- return false;
34
- const value = parseBooleanFlagValue(raw);
35
- return strict ? value === true : value !== false;
36
- }
37
- function envSwitchedOff(value) {
38
- return parseBooleanFlagValue(value) === false;
39
- }
40
- function envOptOutSet(value) {
41
- return value !== undefined && value.trim() !== "" && parseBooleanFlagValue(value) !== false;
42
- }
43
-
44
6
  // src/command-context.ts
45
7
  function flagEnabled(flags, key) {
46
8
  return flags[key] === "true";
@@ -99,4 +61,4 @@ function createCommandContext(input, options = {}) {
99
61
  };
100
62
  }
101
63
 
102
- export { parseBooleanFlagValue, withoutFlag, optOutFlagSet, envSwitchedOff, envOptOutSet, stringOption, createCommandContext };
64
+ export { stringOption, createCommandContext };
@@ -1,3 +1,9 @@
1
+ import {
2
+ parseBooleanFlagValue
3
+ } from "./cli-e0kbye4s.js";
4
+ import {
5
+ callDataAPI
6
+ } from "./cli-0xc5htv7.js";
1
7
  import {
2
8
  shellArg
3
9
  } from "./cli-t0pb7qbs.js";
@@ -533,6 +539,182 @@ function shapeToolCatalogDetail(response, opts) {
533
539
  };
534
540
  }
535
541
 
542
+ // src/trends.ts
543
+ var OVERVIEW_TREND_FLAGS = ["compare", "series", "since", "until", "agent-name", "unit"];
544
+ function flagOn(value) {
545
+ return value !== undefined && parseBooleanFlagValue(value) !== false;
546
+ }
547
+ function overviewTrendsQuery(flags, daysBack) {
548
+ const wanted = OVERVIEW_TREND_FLAGS.some((name) => name === "compare" || name === "series" ? flagOn(flags[name]) : flags[name] !== undefined);
549
+ if (!wanted)
550
+ return null;
551
+ if (flags.raw !== undefined && flagOn(flags.raw)) {
552
+ throw new CliInputError("--raw prints the /overview payload only; it cannot be combined with --compare, --series, --since, --until, --agent-name or --unit.", "Drop --raw to get the briefing with its trends block. Nothing was sent.", "flag_conflict");
553
+ }
554
+ const query = new URLSearchParams;
555
+ if (flags.since !== undefined) {
556
+ if (flags["days-back"] !== undefined) {
557
+ throw new CliInputError("Pass --days-back or --since/--until, not both: --since sets the trends window and the previous window is the same span before it.", "Example: moda overview --compare --since=2026-10-17T14:00:00Z (after the deploy against the same span before it). Nothing was sent.", "flag_conflict");
558
+ }
559
+ query.set("since", flags.since);
560
+ if (flags.until !== undefined)
561
+ query.set("until", flags.until);
562
+ } else if (flags.until !== undefined) {
563
+ throw new CliInputError("--until needs --since: the trends window runs from --since to --until (default now).", "Example: moda overview --compare --since=2026-10-10 --until=2026-10-12. Nothing was sent.", "missing_value:since");
564
+ } else {
565
+ query.set("days_back", String(daysBack));
566
+ }
567
+ if (flags["agent-name"] !== undefined)
568
+ query.set("agent", flags["agent-name"]);
569
+ if (flags.unit !== undefined)
570
+ query.set("unit", flags.unit);
571
+ if (flagOn(flags.series))
572
+ query.set("series", "1");
573
+ return query;
574
+ }
575
+ var TRENDS_TIMEOUT_MS = 90000;
576
+ async function loadTrends(query) {
577
+ const data = await callDataAPI(`/trends?${query.toString()}`, { method: "GET" }, { timeoutMs: TRENDS_TIMEOUT_MS, retries: 0 });
578
+ return asRecord(data) ?? {};
579
+ }
580
+ var HANDLER_FAMILY = {
581
+ emotions: "emotion",
582
+ frustrations: "frustration",
583
+ laziness: "laziness",
584
+ hallucinations: "hallucination",
585
+ "tool-failures": "tool_failure"
586
+ };
587
+ function assertCompareScope(handler, params) {
588
+ const family = HANDLER_FAMILY[handler];
589
+ if (!family)
590
+ throw new CliInputError(`--compare is not available for '${handler}'.`);
591
+ const scoped = ["user_id", "conversation_id", "conversation_ids", "ids_from", "cohort"].filter((key) => params[key] !== undefined);
592
+ if (scoped.length > 0) {
593
+ const names = scoped.map((key) => `--${key.replace(/_/g, "-")}`).join(", ");
594
+ throw new CliInputError(`--compare covers the whole workspace for this family, so it cannot be combined with ${names}.`, `Drop ${names} to compare the family, or drop --compare to keep the scoped read. Nothing was sent.`, "flag_conflict");
595
+ }
596
+ return family;
597
+ }
598
+ async function loadFamilyCompare(handler, params) {
599
+ const family = assertCompareScope(handler, params);
600
+ const query = new URLSearchParams({
601
+ days_back: String(params.days_back ?? 7),
602
+ include: "detectors,rates",
603
+ family: params.family && (family === "emotion" || family === "laziness") ? `${family}:${params.family}` : family
604
+ });
605
+ const trends = await loadTrends(query);
606
+ const window = asRecord(trends.window) ?? {};
607
+ const detectors = asRecord(trends.detectors) ?? {};
608
+ const rates = asRecord(trends.rates) ?? {};
609
+ const rateKey = Object.keys(rates).find((key) => key.endsWith("_pct"));
610
+ return {
611
+ window: { from: window.from, to: window.to, previous_from: window.previous_from, previous_to: window.previous_to },
612
+ kpis: detectors[family] ?? detectors[Object.keys(detectors)[0] ?? ""] ?? null,
613
+ ...rateKey ? { rate: { unit: rates.unit, ...asRecord(rates[rateKey]) } } : {},
614
+ note: "Dashboard KPI tiles for the family in this window against the previous window of equal length " + "(delta = current - previous; delta_pct = relative change). List filters other than the family do not apply here.",
615
+ ...Array.isArray(trends.notes) && trends.notes.length > 0 ? { notes: trends.notes } : {}
616
+ };
617
+ }
618
+ function withSummaryCompare(data, compare) {
619
+ if (!compare)
620
+ return data;
621
+ const record = asRecord(data);
622
+ if (!record)
623
+ return data;
624
+ return { ...record, summary: { ...asRecord(record.summary) ?? {}, compare } };
625
+ }
626
+ function signed(value, suffix = "") {
627
+ if (value === null)
628
+ return "n/a";
629
+ return `${value > 0 ? "+" : ""}${value}${suffix}`;
630
+ }
631
+ function compareText(value, isRate) {
632
+ const c = asRecord(value);
633
+ if (!c)
634
+ return "n/a";
635
+ const current = asNumber(c.current);
636
+ const previous = asNumber(c.previous);
637
+ const unit = isRate ? "%" : "";
638
+ const delta = signed(asNumber(c.delta), isRate ? " pts" : "");
639
+ const pct = asNumber(c.delta_pct);
640
+ return `${current === null ? "n/a" : `${current}${unit}`} (was ${previous === null ? "n/a" : `${previous}${unit}`}; ${delta}${pct === null ? "" : `, ${signed(pct, "%")}`})${c.spike === true ? " SPIKE" : ""}`;
641
+ }
642
+ function renderTrendsHuman(trends) {
643
+ const lines = [];
644
+ const window = asRecord(trends.window) ?? {};
645
+ lines.push(`Trends ${asString(window.from) ?? "?"} to ${asString(window.to) ?? "?"} against ${asString(window.previous_from) ?? "?"} to ${asString(window.previous_to) ?? "?"}`);
646
+ const agent = asRecord(trends.agent);
647
+ if (agent && agent.selected !== "__all__")
648
+ lines.push(` Agent ${String(agent.label ?? agent.selected)}`);
649
+ const sections = [
650
+ ["Overview", asRecord(trends.overview)],
651
+ ["Problems", asRecord(trends.problems)],
652
+ [`Rates per ${asString(asRecord(trends.rates)?.unit) ?? "unit"}`, asRecord(trends.rates)]
653
+ ];
654
+ for (const [title, section] of sections) {
655
+ if (!section)
656
+ continue;
657
+ lines.push(` ${title}`);
658
+ for (const [key, value] of Object.entries(section)) {
659
+ if (!asRecord(value) || !("current" in value))
660
+ continue;
661
+ lines.push(` ${key.padEnd(26)} ${compareText(value, key.endsWith("_pct"))}`);
662
+ }
663
+ }
664
+ const detectors = asRecord(trends.detectors);
665
+ for (const [family, block] of Object.entries(detectors ?? {})) {
666
+ lines.push(` Detector ${family}`);
667
+ for (const [key, value] of Object.entries(asRecord(block) ?? {})) {
668
+ if (!asRecord(value) || !("current" in value))
669
+ continue;
670
+ lines.push(` ${key.padEnd(26)} ${compareText(value, key.endsWith("_pct"))}`);
671
+ }
672
+ }
673
+ const series = asRecord(trends.series);
674
+ if (series) {
675
+ const names = Object.keys(series).filter((key) => key !== "bucket");
676
+ lines.push(` Series per ${asString(series.bucket) ?? "bucket"}: ${names.join(", ")} (use --json for the points)`);
677
+ }
678
+ for (const note of Array.isArray(trends.notes) ? trends.notes : [])
679
+ lines.push(` Note: ${String(note)}`);
680
+ return lines;
681
+ }
682
+ function trendsSummaryText(trends) {
683
+ const overview = asRecord(trends.overview);
684
+ if (!overview)
685
+ return null;
686
+ const parts = [];
687
+ const label = {
688
+ conversations: "traces",
689
+ negative_emotion_rate_pct: "negative emotion",
690
+ tool_failure_rate_pct: "failed tool calls",
691
+ ungrounded_rate_pct: "ungrounded claims"
692
+ };
693
+ for (const [key, name] of Object.entries(label)) {
694
+ const c = asRecord(overview[key]);
695
+ if (!c)
696
+ continue;
697
+ const isRate = key.endsWith("_pct");
698
+ const current = asNumber(c.current);
699
+ if (current === null)
700
+ continue;
701
+ const pct = asNumber(c.delta_pct);
702
+ parts.push(`${name} ${current}${isRate ? "%" : ""} (${isRate ? signed(asNumber(c.delta), " pts") : signed(pct, "%")})`);
703
+ }
704
+ return parts.length > 0 ? `Against the previous window of equal length: ${parts.join(", ")}.` : null;
705
+ }
706
+ function problemTrendSummary(data) {
707
+ const record = asRecord(data) ?? {};
708
+ const days = asNumber(record.days_back) ?? 30;
709
+ const incidents = asRecord(asRecord(record.compare)?.incidents);
710
+ const lastSeen = asString(record.last_seen);
711
+ const seen = lastSeen ? ` Last incident on ${lastSeen}.` : " No incident on record.";
712
+ if (!incidents) {
713
+ return `Incidents per day for the last ${days} day(s); no previous window to compare (the history keeps 90 days).${seen}`;
714
+ }
715
+ return `Incidents in the last ${days} day(s): ${compareText(incidents, false)} against the ${days} day(s) before.${seen}`;
716
+ }
717
+
536
718
  // src/intelligence-schema.ts
537
719
  var INTELLIGENCE_SCHEMA_VERSION = "moda.intelligence.v1";
538
720
  var provenanceSchema = { type: "string", enum: ["measured", "inferred"] };
@@ -676,4 +858,4 @@ var MODA_INTELLIGENCE_V1_JSON_SCHEMA = {
676
858
  }
677
859
  };
678
860
 
679
- export { BATCH_MAX_TARGETS, BATCH_CONCURRENCY, parseBatchTarget, parseTargetLines, readIdsFrom, collectBatchTargets, mapWithConcurrency, contextTarget, asRecord, asString, asNumber, frustrationAnchorIndex, frustrationsFromEmotions, withFrustrationAnchors, trimToolFailureConversations, withToolFailureAnchors, embeddedWindowSize, withoutDetectionWindows, compactProblemDossier, toolFailureExamplesCommand, toolCatalogGetCommand, shapeToolCatalogDetail, INTELLIGENCE_SCHEMA_VERSION, MODA_INTELLIGENCE_V1_JSON_SCHEMA };
861
+ export { BATCH_MAX_TARGETS, BATCH_CONCURRENCY, parseBatchTarget, parseTargetLines, readIdsFrom, collectBatchTargets, mapWithConcurrency, contextTarget, asRecord, asString, asNumber, frustrationAnchorIndex, frustrationsFromEmotions, withFrustrationAnchors, trimToolFailureConversations, withToolFailureAnchors, embeddedWindowSize, withoutDetectionWindows, compactProblemDossier, toolFailureExamplesCommand, toolCatalogGetCommand, shapeToolCatalogDetail, overviewTrendsQuery, loadTrends, assertCompareScope, loadFamilyCompare, withSummaryCompare, renderTrendsHuman, trendsSummaryText, problemTrendSummary, INTELLIGENCE_SCHEMA_VERSION, MODA_INTELLIGENCE_V1_JSON_SCHEMA };