@moda-ai/cli 1.55.13 → 1.55.15

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 (31) hide show
  1. package/README.md +12 -0
  2. package/dist/{agent-rd9deae9.js → agent-a2xwfeeh.js} +9 -9
  3. package/dist/{cli-ryd7nzke.js → cli-2ars875d.js} +2 -2
  4. package/dist/{cli-bfmn3bsk.js → cli-3gwbg0xp.js} +2 -2
  5. package/dist/{cli-4qe6n8am.js → cli-438g4nwh.js} +122 -2
  6. package/dist/{cli-k7vwt56h.js → cli-53mvsfgn.js} +3 -3
  7. package/dist/{cli-ssqb8bfw.js → cli-6ca1sz0a.js} +1 -1
  8. package/dist/{cli-m0fa54ny.js → cli-7fc44hhq.js} +2258 -383
  9. package/dist/{cli-90hb4ng0.js → cli-86q35fpq.js} +8 -8
  10. package/dist/{cli-09rr5smg.js → cli-atx672xv.js} +1 -1
  11. package/dist/{cli-kwz900s4.js → cli-b3cxcxgn.js} +5 -4
  12. package/dist/{cli-4x9w6ey7.js → cli-kf3d6y8c.js} +1 -1
  13. package/dist/{cli-34zdvcpg.js → cli-xy6zn80e.js} +5 -5
  14. package/dist/{cli-y8gbbe9k.js → cli-zdeywyn9.js} +4 -4
  15. package/dist/cli.js +299 -94
  16. package/dist/{doctor-8yb6r66e.js → doctor-e2xrbpmp.js} +9 -9
  17. package/dist/{fix-bt5zn07e.js → fix-v8xka487.js} +7 -7
  18. package/dist/{harness-9psndqtm.js → harness-28wbzncq.js} +6 -6
  19. package/dist/{harness-github-actions-nph5t2s7.js → harness-github-actions-301nak95.js} +6 -6
  20. package/dist/{index-qjaprhrv.js → index-ccdpy9ma.js} +11 -11
  21. package/dist/{production-intelligence-mg3qp2dg.js → production-intelligence-0wqcvvxk.js} +6 -5
  22. package/dist/{profile-commands-2g5bjzj2.js → profile-commands-f5kysjrv.js} +3 -3
  23. package/dist/prompt-source-mcp.js +6 -6
  24. package/dist/{prompts-mzazn8ce.js → prompts-jg0stjfb.js} +7 -7
  25. package/dist/{provision-rm0yc08f.js → provision-25bw5rd7.js} +4 -4
  26. package/dist/{registry-mbz65bjy.js → registry-39xzetsc.js} +4 -4
  27. package/dist/{skills-sagxq9sc.js → skills-gjesa81c.js} +6 -6
  28. package/dist/{sync-gkwexz68.js → sync-7ts9psky.js} +8 -8
  29. package/package.json +1 -1
  30. package/skills/integration/index.json +2 -2
  31. package/skills/moda-cli/SKILL.md +31 -4
package/dist/cli.js CHANGED
@@ -1,19 +1,25 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ BATCH_CONCURRENCY,
4
+ BATCH_MAX_TARGETS,
3
5
  MODA_INTELLIGENCE_V1_JSON_SCHEMA,
4
6
  asNumber,
5
7
  asRecord,
6
8
  asString,
9
+ collectBatchTargets,
10
+ contextTarget,
7
11
  embeddedWindowSize,
8
12
  frustrationsFromEmotions,
13
+ mapWithConcurrency,
14
+ parseBatchTarget,
9
15
  trimToolFailureConversations,
10
16
  withFrustrationAnchors,
11
17
  withToolFailureAnchors
12
- } from "./cli-4qe6n8am.js";
18
+ } from "./cli-438g4nwh.js";
13
19
  import {
14
20
  createCommandContext,
15
21
  parseBooleanFlagValue
16
- } from "./cli-4x9w6ey7.js";
22
+ } from "./cli-kf3d6y8c.js";
17
23
  import {
18
24
  SIGNALS_MANAGEMENT_SUBCOMMANDS,
19
25
  assertFlags,
@@ -23,17 +29,17 @@ import {
23
29
  runUserCommand,
24
30
  runUsersCommand,
25
31
  unknownSignalsSubcommandError
26
- } from "./cli-k7vwt56h.js";
32
+ } from "./cli-53mvsfgn.js";
27
33
  import {
28
34
  ApiError,
29
35
  callControlAPI,
30
36
  callDataAPI
31
- } from "./cli-ryd7nzke.js";
37
+ } from "./cli-2ars875d.js";
32
38
  import {
33
39
  apiKeyHeaders,
34
40
  isPlatformApiKey,
35
41
  setPlatformTenantOverride
36
- } from "./cli-09rr5smg.js";
42
+ } from "./cli-atx672xv.js";
37
43
  import {
38
44
  AGENT_ERROR_CODES,
39
45
  CliAccessError,
@@ -55,6 +61,7 @@ import {
55
61
  apiErrorStatus,
56
62
  createCliOutput,
57
63
  embeddedTenantIdFromApiKey,
64
+ errorToAgentError,
58
65
  getApiRequestCount,
59
66
  getModaDir,
60
67
  isApiLikeError,
@@ -70,7 +77,7 @@ import {
70
77
  setAgentUpdateNotice,
71
78
  validateConfig,
72
79
  wasOutputCancelled
73
- } from "./cli-kwz900s4.js";
80
+ } from "./cli-b3cxcxgn.js";
74
81
  import {
75
82
  __require
76
83
  } from "./cli-0v6na3yp.js";
@@ -142,7 +149,8 @@ var ContextSchema = z.object({
142
149
  metadata_only: boolFlag(),
143
150
  all: boolFlag(),
144
151
  from: z.number().int().min(0).optional(),
145
- max_messages: z.number().int().min(1).max(5000).optional()
152
+ max_messages: z.number().int().min(1).max(5000).optional(),
153
+ ids_from: z.string().min(1).optional()
146
154
  });
147
155
  var FrustrationsSchema = z.object({
148
156
  days_back: daysBackFlag(7),
@@ -378,7 +386,8 @@ var AuditSchema = z.object({
378
386
  include_raw: boolFlag(),
379
387
  include_bodies: boolFlag(),
380
388
  limit: z.number().min(1).max(1000).default(200).optional(),
381
- cursor: z.string().min(1).max(512).optional()
389
+ cursor: z.string().min(1).max(512).optional(),
390
+ ids_from: z.string().min(1).optional()
382
391
  });
383
392
  var TIME_RANGES = ["all", "1h", "3d", "7d", "24h", "30d", "90d"];
384
393
  var SEARCH_MODES = ["keyword", "semantic", "hybrid"];
@@ -2081,46 +2090,46 @@ function exitCodesForCommand(command) {
2081
2090
  import { fileURLToPath } from "url";
2082
2091
  import { realpathSync } from "fs";
2083
2092
  async function runPromptsCommand(...args) {
2084
- return (await import("./prompts-mzazn8ce.js")).runPromptsCommand(...args);
2093
+ return (await import("./prompts-jg0stjfb.js")).runPromptsCommand(...args);
2085
2094
  }
2086
2095
  async function runSkillsCommand(...args) {
2087
- return (await import("./skills-sagxq9sc.js")).runSkillsCommand(...args);
2096
+ return (await import("./skills-gjesa81c.js")).runSkillsCommand(...args);
2088
2097
  }
2089
2098
  async function runFixCommand(...args) {
2090
- return (await import("./fix-bt5zn07e.js")).runFixCommand(...args);
2099
+ return (await import("./fix-v8xka487.js")).runFixCommand(...args);
2091
2100
  }
2092
2101
  async function runFixesCommand(...args) {
2093
- return (await import("./fix-bt5zn07e.js")).runFixesCommand(...args);
2102
+ return (await import("./fix-v8xka487.js")).runFixesCommand(...args);
2094
2103
  }
2095
2104
  async function runHarnessCommand(...args) {
2096
- return (await import("./harness-9psndqtm.js")).runHarnessCommand(...args);
2105
+ return (await import("./harness-28wbzncq.js")).runHarnessCommand(...args);
2097
2106
  }
2098
2107
  async function runSyncCommand(...args) {
2099
- return (await import("./sync-gkwexz68.js")).runSyncCommand(...args);
2108
+ return (await import("./sync-7ts9psky.js")).runSyncCommand(...args);
2100
2109
  }
2101
2110
  async function runRegistryCommand(...args) {
2102
- return (await import("./registry-mbz65bjy.js")).runRegistryCommand(...args);
2111
+ return (await import("./registry-39xzetsc.js")).runRegistryCommand(...args);
2103
2112
  }
2104
2113
  async function runDoctorCommand(...args) {
2105
- return (await import("./doctor-8yb6r66e.js")).runDoctorCommand(...args);
2114
+ return (await import("./doctor-e2xrbpmp.js")).runDoctorCommand(...args);
2106
2115
  }
2107
2116
  async function runStatusCommand(...args) {
2108
- return (await import("./doctor-8yb6r66e.js")).runStatusCommand(...args);
2117
+ return (await import("./doctor-e2xrbpmp.js")).runStatusCommand(...args);
2109
2118
  }
2110
2119
  async function runAuthCommand(...args) {
2111
- return (await import("./profile-commands-2g5bjzj2.js")).runAuthCommand(...args);
2120
+ return (await import("./profile-commands-f5kysjrv.js")).runAuthCommand(...args);
2112
2121
  }
2113
2122
  async function runConfigCommand(...args) {
2114
- return (await import("./profile-commands-2g5bjzj2.js")).runConfigCommand(...args);
2123
+ return (await import("./profile-commands-f5kysjrv.js")).runConfigCommand(...args);
2115
2124
  }
2116
2125
  async function runProfilesCommand(...args) {
2117
- return (await import("./profile-commands-2g5bjzj2.js")).runProfilesCommand(...args);
2126
+ return (await import("./profile-commands-f5kysjrv.js")).runProfilesCommand(...args);
2118
2127
  }
2119
2128
  async function runAgentCommand(...args) {
2120
- return (await import("./agent-rd9deae9.js")).runAgentCommand(...args);
2129
+ return (await import("./agent-a2xwfeeh.js")).runAgentCommand(...args);
2121
2130
  }
2122
2131
  async function runProductionCommand(...args) {
2123
- return (await import("./production-intelligence-mg3qp2dg.js")).runProductionCommand(...args);
2132
+ return (await import("./production-intelligence-0wqcvvxk.js")).runProductionCommand(...args);
2124
2133
  }
2125
2134
  function parseArgs(argv) {
2126
2135
  const args = argv.slice(2);
@@ -2376,7 +2385,9 @@ Commands:
2376
2385
  world-state <conversation_id> Get a trace's world state (slots/threads/events)
2377
2386
  context <conversation_id> Get windowed trace context (--metadata-only: summary + counts only)
2378
2387
  context <conversation_id> --all Whole transcript in order (first 500; --from=N --max-messages=N to continue)
2388
+ context <id>[@N] <id>[@N] ... Batch: up to 25 traces in one call (or --ids-from=-|<file>)
2379
2389
  audit <conversation_id|trace_id> Raw span audit (spans, hierarchy, orphans, duplicates)
2390
+ audit <id> <id> ... Batch audit: up to 25 ids in one call (or --ids-from=-|<file>)
2380
2391
  frustrations Frustration detections (same data as emotions --family=frustration)
2381
2392
  emotions Multi-family emotion detections (frustration, disapproval, sadness, confusion, anxiety, trust, positive)
2382
2393
  hallucinations Grounding detections: contradicted/verified outputs with rule breakdown
@@ -2825,7 +2836,7 @@ function noWorldStateWarnings(conversationId, isMissing) {
2825
2836
  return;
2826
2837
  return {
2827
2838
  warnings: [
2828
- `No world state for trace "${conversationId}": the trace may not exist in this tenant, or its world state has not been generated yet. Check the trace exists with: moda context ${conversationId} --metadata-only`
2839
+ `No world state for trace "${conversationId}": the trace may not exist in this tenant, or its world state has not been generated yet. Check the trace exists with: moda context ${shellArg(contextTarget(conversationId))} --metadata-only`
2829
2840
  ]
2830
2841
  };
2831
2842
  }
@@ -3550,6 +3561,7 @@ function processingDisabledWarning(data, family) {
3550
3561
  }
3551
3562
  var CONTEXT_USAGE = "Usage: moda context <conversation_id> [--msg-index=N (alias --message-index)] [--window=0-5 | --metadata-only]";
3552
3563
  var CONTEXT_ALL_USAGE = "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]";
3564
+ var CONTEXT_BATCH_USAGE = `Usage: moda context <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)`;
3553
3565
  var CONTEXT_FLAG_ALIASES = { "message-index": "msg-index" };
3554
3566
  var CONTEXT_MAX_WINDOW = 5;
3555
3567
  var EMPTY_ANCHOR_VALUES = new Set(["", "null", "undefined", "none"]);
@@ -3723,7 +3735,7 @@ async function readFullTranscript(conversationId, opts = {}) {
3723
3735
  if (next !== null) {
3724
3736
  const last = asNumber(returned[returned.length - 1]?.index) ?? next - 1;
3725
3737
  const nextMax = firstMissing !== null ? Math.min(pageSize, Math.max(kept * 2, 50)) : pageSize;
3726
- const continueWith = `moda context ${shellArg(conversationId)} --all --from=${next} --max-messages=${nextMax}`;
3738
+ const continueWith = `moda context ${shellArg(contextTarget(conversationId))} --all --from=${next} --max-messages=${nextMax}`;
3727
3739
  out.push(`Trace has ${total} messages; returned messages ${start}-${last}. ` + (firstMissing !== null ? `Stopped at ${kept} of the ${messages.length} messages read to stay under the agent output byte limit (--json has no limit). ` : "") + `Continue with: ${continueWith}`);
3728
3740
  nextCommands.push({
3729
3741
  command: continueWith,
@@ -3768,6 +3780,249 @@ async function readFullTranscript(conversationId, opts = {}) {
3768
3780
  }
3769
3781
  return build(low);
3770
3782
  }
3783
+ async function readContextItem(command, params, inputWarnings, fits) {
3784
+ if (params.all === true) {
3785
+ const full = await readFullTranscript(params.conversation_id, {
3786
+ from: params.from,
3787
+ maxMessages: params.max_messages,
3788
+ fits: fits ? (page) => fits(page.data, { warnings: page.warnings, nextCommands: page.nextCommands }) : undefined
3789
+ });
3790
+ const fullWarnings = [...inputWarnings, ...full.warnings];
3791
+ return {
3792
+ data: full.data,
3793
+ options: {
3794
+ ...fullWarnings.length > 0 ? { warnings: fullWarnings } : {},
3795
+ ...full.nextCommands.length > 0 ? { nextCommands: full.nextCommands } : {}
3796
+ }
3797
+ };
3798
+ }
3799
+ const query2 = new URLSearchParams;
3800
+ if (params.msg_index !== undefined)
3801
+ query2.set("msg_index", params.msg_index.toString());
3802
+ if (params.metadata_only === true)
3803
+ query2.set("metadata_only", "1");
3804
+ const window = params.window === undefined ? undefined : Math.min(params.window, CONTEXT_MAX_WINDOW);
3805
+ if (window !== undefined)
3806
+ query2.set("window", window.toString());
3807
+ const queryString = query2.toString() ? `?${query2.toString()}` : "";
3808
+ const contextPath = `/conversations/${encodeURIComponent(params.conversation_id)}/context`;
3809
+ const data = params.metadata_only === true ? await readContextMetadataOnly(contextPath, query2) : await callDataAPI(`${contextPath}${queryString}`);
3810
+ const ctxRecord = asRecord(data) ?? {};
3811
+ throwIfNotFound("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0);
3812
+ const warnings = [...inputWarnings];
3813
+ const nextCommands = [];
3814
+ if (params.window !== undefined && params.window > CONTEXT_MAX_WINDOW) {
3815
+ const center = asNumber(asRecord(ctxRecord.context)?.center_index) ?? params.msg_index ?? 0;
3816
+ const span = Math.min(params.window * 2 + 1, CONTEXT_ALL_MAX_MESSAGES);
3817
+ const from = Math.max(0, center - Math.floor((span - 1) / 2));
3818
+ const wide = `moda context ${shellArg(contextTarget(params.conversation_id))} --all --from=${from} --max-messages=${span}`;
3819
+ warnings.push(`--window=${params.window} is above the maximum of ${CONTEXT_MAX_WINDOW}, so this shows ±${CONTEXT_MAX_WINDOW} messages. For a wider slice run: ${wide}`);
3820
+ nextCommands.push({ command: wide, purpose: `Read ±${params.window} messages around the anchor.`, mutability: "read", requires_approval: false });
3821
+ }
3822
+ return {
3823
+ data,
3824
+ options: {
3825
+ ...warnings.length > 0 ? { warnings } : {},
3826
+ ...nextCommands.length > 0 ? { nextCommands } : {}
3827
+ }
3828
+ };
3829
+ }
3830
+ var AUDIT_USAGE = "Usage: moda audit <conversation_id|trace_id> [--kind=auto|trace|conversation] [--include-raw] [--include-bodies] [--limit=N] [--cursor=<next_cursor>]";
3831
+ var AUDIT_BATCH_USAGE = `Usage: moda audit <id> <id> ... | --ids-from=-|<file> [--kind=auto|trace|conversation] [--include-raw] [--include-bodies] [--limit=N] (max ${BATCH_MAX_TARGETS} targets)`;
3832
+ async function readAuditItem(command, params, budget) {
3833
+ const query2 = new URLSearchParams;
3834
+ if (params.kind && params.kind !== "auto")
3835
+ query2.set("kind", params.kind);
3836
+ if (params.include_raw === true)
3837
+ query2.set("include_raw", "1");
3838
+ if (params.include_bodies === true)
3839
+ query2.set("include_bodies", "1");
3840
+ if (params.limit)
3841
+ query2.set("limit", params.limit.toString());
3842
+ if (params.cursor)
3843
+ query2.set("cursor", params.cursor);
3844
+ let maxBytes = budget?.maxBytes;
3845
+ let page = auditOutput(command, params, await fetchAudit(params.id, query2, maxBytes));
3846
+ while (budget && maxBytes !== undefined && maxBytes > AUDIT_MIN_PAGE_BYTES && !budget.fits(page.data, page.options)) {
3847
+ maxBytes = Math.max(AUDIT_MIN_PAGE_BYTES, Math.floor(maxBytes / 2));
3848
+ page = auditOutput(command, params, await fetchAudit(params.id, query2, maxBytes));
3849
+ }
3850
+ if (budget && !budget.fits(page.data, page.options)) {
3851
+ page.options.warnings = [
3852
+ ...page.options.warnings ?? [],
3853
+ "This page is a single ingest row larger than the agent output budget, so some of its spans are cut from this output. Rerun this command with --json (no byte limit) or a higher MODA_AGENT_MAX_OUTPUT_BYTES to see the whole row before following next_cursor."
3854
+ ];
3855
+ }
3856
+ return page;
3857
+ }
3858
+ var IDS_FROM_KEYS = ["ids-from", "ids_from"];
3859
+ function singleContextTarget(positional, flags) {
3860
+ if (positional === undefined)
3861
+ return [positional, flags];
3862
+ const target = parseBatchTarget(positional, true, CONTEXT_USAGE);
3863
+ if (target.msgIndex === undefined)
3864
+ return [target.id, flags];
3865
+ if (Object.keys(flags).some((key) => ["msg-index", "message-index"].includes(key.replace(/_/g, "-")))) {
3866
+ throw new CliInputError(`${JSON.stringify(positional)} already anchors at message ${target.msgIndex}; drop --msg-index, or pass {"id": "..."} if the id itself ends in @<digits>.`, CONTEXT_USAGE, "flag_conflict");
3867
+ }
3868
+ return [target.id, { ...flags, "msg-index": String(target.msgIndex) }];
3869
+ }
3870
+ function isBatchRead(positionals, flags) {
3871
+ return positionals.length > 1 || IDS_FROM_KEYS.some((key) => flags[key] !== undefined);
3872
+ }
3873
+ function splitIdsFrom(flags) {
3874
+ let idsFrom;
3875
+ const rest = {};
3876
+ for (const [key, value] of Object.entries(flags)) {
3877
+ if (IDS_FROM_KEYS.includes(key))
3878
+ idsFrom = value;
3879
+ else
3880
+ rest[key] = value;
3881
+ }
3882
+ return { idsFrom, rest };
3883
+ }
3884
+ function auditItemByteShare(count) {
3885
+ return Math.max(AUDIT_MIN_PAGE_BYTES, Math.floor((agentMaxOutputBytes() - AUDIT_AGENT_RESERVE_BYTES) / count));
3886
+ }
3887
+ var BATCH_ENVELOPE_RESERVE_BYTES = 4096;
3888
+ var BATCH_ENVELOPE_RESERVE_PER_TARGET_BYTES = 256;
3889
+ function contextItemByteShare(count) {
3890
+ const reserve = BATCH_ENVELOPE_RESERVE_BYTES + BATCH_ENVELOPE_RESERVE_PER_TARGET_BYTES * count;
3891
+ return Math.max(1, Math.floor((agentMaxOutputBytes() - reserve) / count));
3892
+ }
3893
+ function fitsShare(share) {
3894
+ return (data, options) => Buffer.byteLength(JSON.stringify({ data, ...options }) ?? "", "utf8") <= share;
3895
+ }
3896
+ function isBatchFatal(error) {
3897
+ const type = classifyCliError(error);
3898
+ return type === "auth_error" || type === "access_error" || error instanceof CliInputError;
3899
+ }
3900
+ async function readBatchItem(target, read) {
3901
+ try {
3902
+ const item = await read();
3903
+ return {
3904
+ target: target.raw,
3905
+ ok: true,
3906
+ data: item.data,
3907
+ ...item.options.warnings?.length ? { warnings: item.options.warnings } : {},
3908
+ ...item.options.nextCommands?.length ? { next_commands: item.options.nextCommands } : {}
3909
+ };
3910
+ } catch (error) {
3911
+ if (isBatchFatal(error))
3912
+ throw error;
3913
+ const agentError = errorToAgentError(error);
3914
+ const code = classifyCliError(error) === "api_not_found" ? "not_found" : agentError.code;
3915
+ return {
3916
+ target: target.raw,
3917
+ ok: false,
3918
+ error: {
3919
+ code,
3920
+ message: agentError.message,
3921
+ ...agentError.cause ? { cause: agentError.cause } : {},
3922
+ ...agentError.suggested_commands?.length ? { suggested_commands: agentError.suggested_commands } : {}
3923
+ }
3924
+ };
3925
+ }
3926
+ }
3927
+ function renderBatchFlags(flags) {
3928
+ return Object.entries(flags).map(([key, value]) => value === "true" ? `--${key}` : `--${key}=${shellArg(value)}`);
3929
+ }
3930
+ function writeBatchResult(command, context, targets, results, batchWarnings, flags) {
3931
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
3932
+ const build = (kept2) => {
3933
+ const returned = results.slice(0, kept2);
3934
+ const remaining = targets.slice(kept2);
3935
+ const failed = returned.filter((result) => !result.ok);
3936
+ const allFailed = failed.length === returned.length;
3937
+ const warnings = [...batchWarnings];
3938
+ if (failed.length > 0 && failed.length < returned.length) {
3939
+ warnings.push(`${failed.length} of ${returned.length} targets failed: ` + failed.map((result) => `${result.target} (${result.error?.code ?? "error"})`).join(", ") + ".");
3940
+ }
3941
+ const nextCommands = [];
3942
+ if (remaining.length > 0) {
3943
+ const lines = remaining.map((target) => shellArg(target.raw)).join(" ");
3944
+ const continueWith = [`printf '%s\\n' ${lines} |`, `moda ${command}`, "--ids-from=-", ...renderBatchFlags(flags)].join(" ");
3945
+ warnings.push(`Returned ${kept2} of ${targets.length} targets to stay under the agent output byte limit (--json has no limit). Read the other ${remaining.length} with: ${continueWith}`);
3946
+ nextCommands.push({
3947
+ command: continueWith,
3948
+ purpose: `Read the remaining ${remaining.length} target(s) of this batch.`,
3949
+ mutability: "read",
3950
+ requires_approval: false
3951
+ });
3952
+ }
3953
+ return {
3954
+ data: {
3955
+ results: returned,
3956
+ requested: targets.length,
3957
+ returned: returned.length,
3958
+ succeeded: returned.length - failed.length,
3959
+ failed: failed.length,
3960
+ has_more: remaining.length > 0,
3961
+ remaining_targets: remaining.map((target) => target.raw)
3962
+ },
3963
+ options: {
3964
+ summary: `Read ${returned.length - failed.length} of ${targets.length} targets` + (failed.length > 0 ? ` (${failed.length} failed)` : "") + (remaining.length > 0 ? `; ${remaining.length} left for a follow-up call` : "") + ".",
3965
+ ...warnings.length > 0 ? { warnings } : {},
3966
+ ...nextCommands.length > 0 ? { nextCommands } : {},
3967
+ ...allFailed ? {
3968
+ status: "error",
3969
+ errors: returned.map((result) => ({
3970
+ code: result.error?.code ?? "unknown_error",
3971
+ message: clipText(`${result.target}: ${result.error?.message ?? "failed"}`, BATCH_ERROR_MESSAGE_CHARS),
3972
+ blocking: false
3973
+ }))
3974
+ } : failed.length > 0 ? { status: "degraded" } : {}
3975
+ }
3976
+ };
3977
+ };
3978
+ let kept = results.length;
3979
+ let page = build(kept);
3980
+ while (agentMode && kept > 1 && !agentEnvelopeFits(command, page.data, page.options)) {
3981
+ kept -= 1;
3982
+ page = build(kept);
3983
+ }
3984
+ const failedPage = page.options.status === "error";
3985
+ context.output.writeData(page.data, { ...page.options, ...failedPage ? { bypassQuiet: true } : {} });
3986
+ return failedPage ? 1 : 0;
3987
+ }
3988
+ var BATCH_ERROR_MESSAGE_CHARS = 300;
3989
+ function clipText(text, max) {
3990
+ return text.length <= max ? text : `${text.slice(0, max - 3)}...`;
3991
+ }
3992
+ async function runContextBatch(command, positionals, flags, context) {
3993
+ const { idsFrom, rest } = splitIdsFrom(flags);
3994
+ if (Object.keys(rest).some((key) => key.replace(/_/g, "-") === "conversation-id")) {
3995
+ throw new CliInputError("Batch reads take ids as positionals or --ids-from, not --conversation-id; drop --conversation-id.", CONTEXT_BATCH_USAGE, "flag_conflict");
3996
+ }
3997
+ const targets = await collectBatchTargets(positionals, idsFrom, { anchors: true, usage: CONTEXT_BATCH_USAGE, command });
3998
+ const { params: base, warnings: inputWarnings } = parseContextRequest(targets[0].id, rest);
3999
+ if ((base.all === true || base.metadata_only === true) && targets.some((target) => target.msgIndex !== undefined)) {
4000
+ throw new CliInputError(`${base.all === true ? "--all reads whole traces" : "--metadata-only reads no messages"}, so targets cannot carry an @msg_index anchor; drop the flag or the anchors.`, CONTEXT_BATCH_USAGE, "flag_conflict");
4001
+ }
4002
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
4003
+ const share = agentMode ? contextItemByteShare(targets.length) : undefined;
4004
+ const results = await mapWithConcurrency(targets, BATCH_CONCURRENCY, (target) => readBatchItem(target, () => {
4005
+ const params = {
4006
+ ...base,
4007
+ conversation_id: target.id,
4008
+ ...target.msgIndex !== undefined ? { msg_index: target.msgIndex } : {}
4009
+ };
4010
+ return readContextItem(command, params, [], share !== undefined ? fitsShare(share) : undefined);
4011
+ }));
4012
+ return writeBatchResult(command, context, targets, results, inputWarnings, rest);
4013
+ }
4014
+ async function runAuditBatch(command, positionals, flags, context) {
4015
+ const { idsFrom, rest } = splitIdsFrom(flags);
4016
+ if (rest.cursor !== undefined) {
4017
+ throw new CliInputError("--cursor continues one trace, so it cannot be used with several ids; follow each item's next_commands instead.", AUDIT_BATCH_USAGE, "flag_conflict");
4018
+ }
4019
+ const targets = await collectBatchTargets(positionals, idsFrom, { anchors: false, usage: AUDIT_BATCH_USAGE, command });
4020
+ const base = parseCommandFlags(AuditSchema, flagsToArgs(rest, "id", targets[0].id), command, { positionalKey: "id" });
4021
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
4022
+ const share = agentMode ? auditItemByteShare(targets.length) : undefined;
4023
+ const results = await mapWithConcurrency(targets, BATCH_CONCURRENCY, (target) => readBatchItem(target, () => readAuditItem(command, { ...base, id: target.id }, share !== undefined ? { maxBytes: share, fits: fitsShare(share) } : undefined)));
4024
+ return writeBatchResult(command, context, targets, results, [], rest);
4025
+ }
3771
4026
  async function runCommand(command, positional, flags, positionals = positional ? [positional] : [], context = createCommandContext({ command, positional, positionals, flags })) {
3772
4027
  assertHandParsedFlags(command, flags, positionals);
3773
4028
  switch (command) {
@@ -3988,81 +4243,28 @@ async function runCommand(command, positional, flags, positionals = positional ?
3988
4243
  break;
3989
4244
  }
3990
4245
  case "context": {
3991
- const { params, warnings: inputWarnings } = parseContextRequest(positional, flags);
3992
- if (params.all === true) {
3993
- const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
3994
- const full = await readFullTranscript(params.conversation_id, {
3995
- from: params.from,
3996
- maxMessages: params.max_messages,
3997
- fits: agentMode ? (page) => agentEnvelopeFits(command, page.data, { warnings: page.warnings, nextCommands: page.nextCommands }) : undefined
3998
- });
3999
- const fullWarnings = [...inputWarnings, ...full.warnings];
4000
- context.output.writeData(full.data, {
4001
- ...fullWarnings.length > 0 ? { warnings: fullWarnings } : {},
4002
- ...full.nextCommands.length > 0 ? { nextCommands: full.nextCommands } : {}
4003
- });
4004
- break;
4005
- }
4006
- const query2 = new URLSearchParams;
4007
- if (params.msg_index !== undefined)
4008
- query2.set("msg_index", params.msg_index.toString());
4009
- if (params.metadata_only === true)
4010
- query2.set("metadata_only", "1");
4011
- const window = params.window === undefined ? undefined : Math.min(params.window, CONTEXT_MAX_WINDOW);
4012
- if (window !== undefined)
4013
- query2.set("window", window.toString());
4014
- const queryString = query2.toString() ? `?${query2.toString()}` : "";
4015
- const contextPath = `/conversations/${encodeURIComponent(params.conversation_id)}/context`;
4016
- const data = params.metadata_only === true ? await readContextMetadataOnly(contextPath, query2) : await callDataAPI(`${contextPath}${queryString}`);
4017
- const ctxRecord = asRecord(data) ?? {};
4018
- throwIfNotFound("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0);
4019
- const warnings = [...inputWarnings];
4020
- const nextCommands = [];
4021
- if (params.window !== undefined && params.window > CONTEXT_MAX_WINDOW) {
4022
- const center = asNumber(asRecord(ctxRecord.context)?.center_index) ?? params.msg_index ?? 0;
4023
- const span = Math.min(params.window * 2 + 1, CONTEXT_ALL_MAX_MESSAGES);
4024
- const from = Math.max(0, center - Math.floor((span - 1) / 2));
4025
- const wide = `moda context ${shellArg(params.conversation_id)} --all --from=${from} --max-messages=${span}`;
4026
- warnings.push(`--window=${params.window} is above the maximum of ${CONTEXT_MAX_WINDOW}, so this shows ±${CONTEXT_MAX_WINDOW} messages. For a wider slice run: ${wide}`);
4027
- nextCommands.push({ command: wide, purpose: `Read ±${params.window} messages around the anchor.`, mutability: "read", requires_approval: false });
4028
- }
4029
- context.output.writeData(data, {
4030
- ...warnings.length > 0 ? { warnings } : {},
4031
- ...nextCommands.length > 0 ? { nextCommands } : {}
4032
- });
4246
+ if (isBatchRead(positionals, flags))
4247
+ return runContextBatch(command, positionals, flags, context);
4248
+ const { params, warnings: inputWarnings } = parseContextRequest(...singleContextTarget(positional, flags));
4249
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
4250
+ const item = await readContextItem(command, params, inputWarnings, agentMode ? (data, options) => agentEnvelopeFits(command, data, options) : undefined);
4251
+ context.output.writeData(item.data, item.options);
4033
4252
  break;
4034
4253
  }
4035
4254
  case "audit":
4036
4255
  case "trace": {
4256
+ if (isBatchRead(positionals, flags))
4257
+ return runAuditBatch(command, positionals, flags, context);
4037
4258
  if (!positional) {
4038
- throw new CliInputError("<conversation_id|trace_id> is required", "Usage: moda audit <conversation_id|trace_id> [--kind=auto|trace|conversation] [--include-raw] [--include-bodies] [--limit=N] [--cursor=<next_cursor>]");
4259
+ throw new CliInputError("<conversation_id|trace_id> is required", AUDIT_USAGE);
4039
4260
  }
4040
4261
  const args = flagsToArgs(flags, "id", positional);
4041
4262
  const params = parseCommandFlags(AuditSchema, args, command, { positionalKey: "id" });
4042
- const query2 = new URLSearchParams;
4043
- if (params.kind && params.kind !== "auto")
4044
- query2.set("kind", params.kind);
4045
- if (params.include_raw === true)
4046
- query2.set("include_raw", "1");
4047
- if (params.include_bodies === true)
4048
- query2.set("include_bodies", "1");
4049
- if (params.limit)
4050
- query2.set("limit", params.limit.toString());
4051
- if (params.cursor)
4052
- query2.set("cursor", params.cursor);
4053
4263
  const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
4054
- let maxBytes = agentMode ? Math.max(AUDIT_MIN_PAGE_BYTES, agentMaxOutputBytes() - AUDIT_AGENT_RESERVE_BYTES) : undefined;
4055
- let page = auditOutput(command, params, await fetchAudit(params.id, query2, maxBytes));
4056
- while (maxBytes !== undefined && maxBytes > AUDIT_MIN_PAGE_BYTES && !agentEnvelopeFits(command, page.data, page.options)) {
4057
- maxBytes = Math.max(AUDIT_MIN_PAGE_BYTES, Math.floor(maxBytes / 2));
4058
- page = auditOutput(command, params, await fetchAudit(params.id, query2, maxBytes));
4059
- }
4060
- if (maxBytes !== undefined && !agentEnvelopeFits(command, page.data, page.options)) {
4061
- page.options.warnings = [
4062
- ...page.options.warnings ?? [],
4063
- "This page is a single ingest row larger than the agent output budget, so some of its spans are cut from this output. Rerun this command with --json (no byte limit) or a higher MODA_AGENT_MAX_OUTPUT_BYTES to see the whole row before following next_cursor."
4064
- ];
4065
- }
4264
+ const page = await readAuditItem(command, params, agentMode ? {
4265
+ maxBytes: Math.max(AUDIT_MIN_PAGE_BYTES, agentMaxOutputBytes() - AUDIT_AGENT_RESERVE_BYTES),
4266
+ fits: (data, options) => agentEnvelopeFits(command, data, options)
4267
+ } : undefined);
4066
4268
  context.output.writeData(page.data, page.options);
4067
4269
  break;
4068
4270
  }
@@ -4773,7 +4975,7 @@ var commandRegistry = createCommandRegistry([
4773
4975
  resetApiRequestCountBeforeRun: true,
4774
4976
  telemetry: "result",
4775
4977
  handler: async (context) => {
4776
- const { runInit } = await import("./index-qjaprhrv.js");
4978
+ const { runInit } = await import("./index-ccdpy9ma.js");
4777
4979
  if (context.outputMode === "agent-stream") {
4778
4980
  context.output.writeEvent({
4779
4981
  event: "started",
@@ -4814,7 +5016,7 @@ var commandRegistry = createCommandRegistry([
4814
5016
  resetApiRequestCountBeforeRun: true,
4815
5017
  telemetry: "result-and-error",
4816
5018
  handler: async (context) => {
4817
- const { runProvision } = await import("./provision-rm0yc08f.js");
5019
+ const { runProvision } = await import("./provision-25bw5rd7.js");
4818
5020
  return runProvision(context, {
4819
5021
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
4820
5022
  });
@@ -5270,7 +5472,9 @@ var commandRegistry = createCommandRegistry([
5270
5472
  "moda context <conversation_id> --msg-index=40 --window=0 # --message-index is an alias",
5271
5473
  "moda context <conversation_id> --metadata-only # summary + total_messages, no messages",
5272
5474
  "moda context <conversation_id> --all",
5273
- "moda context <conversation_id> --all --from=500 --max-messages=500"
5475
+ "moda context <conversation_id> --all --from=500 --max-messages=500",
5476
+ "moda context <id>@12 <id2>@3 <id3> --window=2 # batch: up to 25 targets, one envelope; id@N anchors at message N",
5477
+ "moda context --ids-from=ids.txt --window=1 # one target per line (id or id@N); --ids-from=- reads stdin"
5274
5478
  ],
5275
5479
  ...dataApiDefaults
5276
5480
  }),
@@ -5284,7 +5488,8 @@ var commandRegistry = createCommandRegistry([
5284
5488
  "moda audit <conversation_id> --include-raw",
5285
5489
  "moda audit <conversation_id> --include-bodies # keep prompt/response bodies (omitted by default; long strings truncated)",
5286
5490
  "moda audit <conversation_id> --limit=1000 # ingest rows to read (default 200, max 1000); warns when capped",
5287
- "moda audit <conversation_id> --cursor=<next_cursor> # next page of a capped audit"
5491
+ "moda audit <conversation_id> --cursor=<next_cursor> # next page of a capped audit",
5492
+ "moda audit <id1> <id2> <id3> # batch: up to 25 ids, one envelope (or --ids-from=-|<file>)"
5288
5493
  ],
5289
5494
  ...dataApiDefaults
5290
5495
  }),
@@ -3,17 +3,17 @@ import {
3
3
  promptsDiscoveredCheck,
4
4
  runDoctorCommand,
5
5
  runStatusCommand
6
- } from "./cli-34zdvcpg.js";
7
- import"./cli-ssqb8bfw.js";
8
- import"./cli-90hb4ng0.js";
6
+ } from "./cli-xy6zn80e.js";
7
+ import"./cli-6ca1sz0a.js";
8
+ import"./cli-86q35fpq.js";
9
9
  import"./cli-mm48br00.js";
10
- import"./cli-m0fa54ny.js";
10
+ import"./cli-7fc44hhq.js";
11
11
  import"./cli-97fnztpy.js";
12
- import"./cli-4x9w6ey7.js";
13
- import"./cli-k7vwt56h.js";
14
- import"./cli-ryd7nzke.js";
15
- import"./cli-09rr5smg.js";
16
- import"./cli-kwz900s4.js";
12
+ import"./cli-kf3d6y8c.js";
13
+ import"./cli-53mvsfgn.js";
14
+ import"./cli-2ars875d.js";
15
+ import"./cli-atx672xv.js";
16
+ import"./cli-b3cxcxgn.js";
17
17
  import"./cli-0v6na3yp.js";
18
18
  export {
19
19
  runStatusCommand,
@@ -2,18 +2,18 @@ import {
2
2
  DEFAULT_POLL_INTERVAL_MS,
3
3
  DEFAULT_WAIT_TIMEOUT_MS,
4
4
  fetchLatestRun
5
- } from "./cli-90hb4ng0.js";
5
+ } from "./cli-86q35fpq.js";
6
6
  import"./cli-mm48br00.js";
7
- import"./cli-m0fa54ny.js";
7
+ import"./cli-7fc44hhq.js";
8
8
  import"./cli-97fnztpy.js";
9
- import"./cli-4x9w6ey7.js";
9
+ import"./cli-kf3d6y8c.js";
10
10
  import {
11
11
  assertFlags
12
- } from "./cli-k7vwt56h.js";
12
+ } from "./cli-53mvsfgn.js";
13
13
  import {
14
14
  callControlAPI
15
- } from "./cli-ryd7nzke.js";
16
- import"./cli-09rr5smg.js";
15
+ } from "./cli-2ars875d.js";
16
+ import"./cli-atx672xv.js";
17
17
  import {
18
18
  CliInputError,
19
19
  EXIT_DEGRADED,
@@ -22,7 +22,7 @@ import {
22
22
  getModaPaths,
23
23
  resolveApiTenantId,
24
24
  validateConfig
25
- } from "./cli-kwz900s4.js";
25
+ } from "./cli-b3cxcxgn.js";
26
26
  import"./cli-0v6na3yp.js";
27
27
 
28
28
  // src/fix.ts
@@ -42,13 +42,13 @@ import {
42
42
  writeHarnessAnalyzeResult,
43
43
  writeHarnessArtifacts,
44
44
  writeHumanProgress
45
- } from "./cli-m0fa54ny.js";
45
+ } from "./cli-7fc44hhq.js";
46
46
  import"./cli-97fnztpy.js";
47
- import"./cli-4x9w6ey7.js";
48
- import"./cli-k7vwt56h.js";
49
- import"./cli-ryd7nzke.js";
50
- import"./cli-09rr5smg.js";
51
- import"./cli-kwz900s4.js";
47
+ import"./cli-kf3d6y8c.js";
48
+ import"./cli-53mvsfgn.js";
49
+ import"./cli-2ars875d.js";
50
+ import"./cli-atx672xv.js";
51
+ import"./cli-b3cxcxgn.js";
52
52
  import"./cli-0v6na3yp.js";
53
53
  export {
54
54
  writeHumanProgress,