@moda-ai/cli 1.48.0 → 1.49.0

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.
@@ -13,7 +13,7 @@ import {
13
13
  resolvePromptSource,
14
14
  safePromptEvidencePath,
15
15
  scanHarness
16
- } from "./cli-tznhpmf2.js";
16
+ } from "./cli-m3bg9yyh.js";
17
17
  import {
18
18
  SKILL_SOURCE_HARNESS,
19
19
  SKILL_SOURCE_INTEGRATION_BUNDLED,
@@ -26,7 +26,7 @@ import {
26
26
  import {
27
27
  isAuthSessionValid,
28
28
  loadAuthSession
29
- } from "./cli-fpt3jkyh.js";
29
+ } from "./cli-c64d2jrw.js";
30
30
  import {
31
31
  CliInputError,
32
32
  EXIT_ERROR,
@@ -45,7 +45,7 @@ import {
45
45
  resolveTenantId,
46
46
  secretFilePathFromRef,
47
47
  validateConfig
48
- } from "./cli-233xm35b.js";
48
+ } from "./cli-bqhs6sk7.js";
49
49
  import {
50
50
  __commonJS,
51
51
  __require,
@@ -6711,7 +6711,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
6711
6711
  const analyzedDefinitions = new Map;
6712
6712
  if (flags["no-analyze"] !== "true") {
6713
6713
  options.onProgress?.("Analyzing prompt sources before sync.");
6714
- const { analyzeHarnessPrompts } = await import("./harness-vf1e1t2h.js");
6714
+ const { analyzeHarnessPrompts } = await import("./harness-4ypeg9dh.js");
6715
6715
  const result = await analyzeHarnessPrompts({
6716
6716
  rootDir: process.cwd(),
6717
6717
  existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
@@ -1418,10 +1418,14 @@ function errorToAgentError(error) {
1418
1418
  }
1419
1419
  if (isApiLikeError(error)) {
1420
1420
  const statusCode = "statusCode" in error ? error.statusCode : undefined;
1421
+ const typedCode = "code" in error && typeof error.code === "string" ? error.code : undefined;
1422
+ const suggestions = "suggestions" in error && Array.isArray(error.suggestions) ? error.suggestions.filter((s) => typeof s === "string") : [];
1423
+ const http = typeof statusCode === "number" ? `HTTP ${statusCode}` : undefined;
1421
1424
  return {
1422
1425
  code: "api_error",
1423
1426
  message: error.message,
1424
- cause: typeof statusCode === "number" ? `HTTP ${statusCode}` : undefined,
1427
+ cause: typedCode ? http ? `${typedCode} (${http})` : typedCode : http,
1428
+ ...suggestions.length > 0 ? { suggested_commands: suggestions } : {},
1425
1429
  blocking: true
1426
1430
  };
1427
1431
  }
@@ -1717,4 +1721,4 @@ function createCommandContext(input, options = {}) {
1717
1721
  };
1718
1722
  }
1719
1723
 
1720
- export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, assertValidProfileName, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, CliAccessError, CliInputRequiredError, CliAuthError, CliCancellationError, isNetworkLikeError, isApiLikeError, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, resolveOutputMode, createCliOutput, agentEnvelopeFits, stringOption, createCommandContext };
1724
+ export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, assertValidProfileName, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, CliInputError, CliAccessError, CliInputRequiredError, CliAuthError, CliCancellationError, isNetworkLikeError, isApiLikeError, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, validateConfig, MAX_SCANNED_FILE_BYTES, DEFAULT_MAX_INVENTORY_FILES, DEFAULT_MAX_INVENTORY_TEXT_BYTES, MAX_RECORDED_SKIPS, SKIPPED_DIRS, isSkippedDir, isSkippedPathPrefix, isEvalLikePath, shouldInventoryFile, isTextFile, isSecretishPath, SECRET_KEYS, redactDeep, redactString, packSnapshot, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, resolveOutputMode, createCliOutput, agentEnvelopeFits, agentMaxOutputBytes, stringOption, createCommandContext };
@@ -7,7 +7,7 @@ import {
7
7
  saveProfileConfig,
8
8
  secretFilePathFromRef,
9
9
  writeSecretJsonFile
10
- } from "./cli-233xm35b.js";
10
+ } from "./cli-bqhs6sk7.js";
11
11
  import {
12
12
  __require
13
13
  } from "./cli-0v6na3yp.js";
@@ -25,7 +25,7 @@ import {
25
25
  resolveTenantId,
26
26
  shouldInventoryFile,
27
27
  stringOption
28
- } from "./cli-233xm35b.js";
28
+ } from "./cli-bqhs6sk7.js";
29
29
  import {
30
30
  __commonJS,
31
31
  __require,
@@ -177909,13 +177909,59 @@ var apiRequestCount = 0;
177909
177909
  class ApiError extends Error {
177910
177910
  statusCode;
177911
177911
  responseBody;
177912
+ code;
177913
+ suggestions;
177914
+ readable;
177912
177915
  constructor(message, statusCode, responseBody) {
177913
- super(message);
177916
+ const typed = parseTypedErrorBody(responseBody);
177917
+ const platform = platformFailure(responseBody);
177918
+ const readable = typed?.code === "audit_too_large" || platform !== null;
177919
+ super(readable ? `API error (${statusCode}): ${typed?.message ?? platform?.message}` : message);
177914
177920
  this.statusCode = statusCode;
177915
177921
  this.responseBody = responseBody;
177916
177922
  this.name = "ApiError";
177923
+ this.code = typed?.code ?? platform?.code;
177924
+ this.suggestions = typed?.suggestions;
177925
+ this.readable = readable;
177917
177926
  }
177918
177927
  }
177928
+ function parseTypedErrorBody(body) {
177929
+ if (!body.trimStart().startsWith("{"))
177930
+ return null;
177931
+ try {
177932
+ const parsed = JSON.parse(body);
177933
+ if (typeof parsed.code !== "string")
177934
+ return null;
177935
+ const suggestions = Array.isArray(parsed.suggestions) ? parsed.suggestions.filter((s) => typeof s === "string") : undefined;
177936
+ return {
177937
+ code: parsed.code,
177938
+ message: typeof parsed.message === "string" ? parsed.message : undefined,
177939
+ suggestions
177940
+ };
177941
+ } catch {
177942
+ return null;
177943
+ }
177944
+ }
177945
+ var DETERMINISTIC_PLATFORM_FAILURES = [
177946
+ "FUNCTION_INVOCATION_FAILED",
177947
+ "FUNCTION_RESPONSE_PAYLOAD_TOO_LARGE"
177948
+ ];
177949
+ function platformFailure(body) {
177950
+ const code = DETERMINISTIC_PLATFORM_FAILURES.find((c) => body.includes(c));
177951
+ if (!code)
177952
+ return null;
177953
+ const requestId = /\b([a-z]{3}\d::[A-Za-z0-9:-]+)/.exec(body)?.[1];
177954
+ const cause = code === "FUNCTION_RESPONSE_PAYLOAD_TOO_LARGE" ? "the response was larger than the hosting platform allows" : "the server function crashed (typically out of memory or an oversized response)";
177955
+ return {
177956
+ code,
177957
+ message: `The Moda API could not complete this request: ${cause} [${code}` + `${requestId ? `, request ${requestId}` : ""}]. Retrying the same request will fail the same way; ` + "narrow it (a smaller --limit, a single trace, or fewer results) and report it with `moda feedback` if it persists."
177958
+ };
177959
+ }
177960
+ function isRetryableResponse(status, body) {
177961
+ if (!isRetryable(status))
177962
+ return false;
177963
+ return platformFailure(body) === null;
177964
+ }
177919
177965
 
177920
177966
  class NetworkError extends Error {
177921
177967
  constructor(message) {
@@ -177970,7 +178016,7 @@ async function callModaAPI(url, options, profileOptions = {}, requestOptions = {
177970
178016
  if (!response.ok) {
177971
178017
  const errorText = await response.text();
177972
178018
  const error = new ApiError(`API error (${response.status}): ${errorText}`, response.status, errorText);
177973
- if (isRetryable(response.status) && attempt < maxRetries) {
178019
+ if (isRetryableResponse(response.status, errorText) && attempt < maxRetries) {
177974
178020
  continue;
177975
178021
  }
177976
178022
  throw error;
@@ -184813,7 +184859,7 @@ async function runHarnessCommand(context) {
184813
184859
  throw new CliInputError("Focused remote prompt analysis is not supported yet.", "Use local --analyst=claude|codex|cursor|local-scan, or drop --concern for a full remote report.");
184814
184860
  }
184815
184861
  if (context.flags["github-actions"] === "true") {
184816
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-379faaqe.js");
184862
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-dvq7spqh.js");
184817
184863
  const result = await runGithubActionsAnalyze(rootDir, {
184818
184864
  writeReport: (report2) => {
184819
184865
  const normalized = normalizeHarnessReport(report2);
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  authFetch,
3
3
  getCachedLoginContext
4
- } from "./cli-fpt3jkyh.js";
4
+ } from "./cli-c64d2jrw.js";
5
5
  import {
6
6
  CliAccessError,
7
7
  CliInputError,
@@ -15,7 +15,7 @@ import {
15
15
  resolveTenantIdFromActiveProfile,
16
16
  saveCliConfig,
17
17
  writeSecretJsonFile
18
- } from "./cli-233xm35b.js";
18
+ } from "./cli-bqhs6sk7.js";
19
19
 
20
20
  // src/init/tenant.ts
21
21
  import { randomUUID } from "node:crypto";
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  runPromptsCommand,
9
9
  runSkillsCommand,
10
10
  runStatusCommand
11
- } from "./cli-eaaegm7a.js";
11
+ } from "./cli-6xndg2h4.js";
12
12
  import {
13
13
  ApiError,
14
14
  HARNESS_REPORT_APPROVAL_PATH,
@@ -37,7 +37,7 @@ import {
37
37
  terminalStyles,
38
38
  unknownSignalsSubcommandError,
39
39
  validateHarnessReport
40
- } from "./cli-tznhpmf2.js";
40
+ } from "./cli-m3bg9yyh.js";
41
41
  import"./cli-ssfq84k5.js";
42
42
  import {
43
43
  authFetch,
@@ -46,7 +46,7 @@ import {
46
46
  loadAuthSession,
47
47
  login,
48
48
  revokeCliSessionToken
49
- } from "./cli-fpt3jkyh.js";
49
+ } from "./cli-c64d2jrw.js";
50
50
  import {
51
51
  AGENT_ERROR_CODES,
52
52
  CliAccessError,
@@ -65,6 +65,7 @@ import {
65
65
  PROD_BASE_URL,
66
66
  VERSION,
67
67
  agentEnvelopeFits,
68
+ agentMaxOutputBytes,
68
69
  assertValidProfileName,
69
70
  clearStoredApiKeyCredentials,
70
71
  createCliOutput,
@@ -96,7 +97,7 @@ import {
96
97
  validateConfig,
97
98
  wasOutputCancelled,
98
99
  writeSecretJsonFile
99
- } from "./cli-233xm35b.js";
100
+ } from "./cli-bqhs6sk7.js";
100
101
  import {
101
102
  __require
102
103
  } from "./cli-0v6na3yp.js";
@@ -389,7 +390,9 @@ var AuditSchema = z.object({
389
390
  id: z.string().min(1),
390
391
  kind: z.enum(["auto", "trace", "conversation"]).default("auto").optional(),
391
392
  include_raw: boolFlag(),
392
- limit: z.number().min(1).max(1000).default(200).optional()
393
+ include_bodies: boolFlag(),
394
+ limit: z.number().min(1).max(1000).default(200).optional(),
395
+ cursor: z.string().min(1).max(512).optional()
393
396
  });
394
397
  var TIME_RANGES = ["all", "1h", "3d", "7d", "24h", "30d", "90d"];
395
398
  var SEARCH_MODES = ["keyword", "semantic", "hybrid"];
@@ -8367,7 +8370,62 @@ function auditCapStatus(data, limit) {
8367
8370
  const rowsCapped = hasMore || !serverSaid && rows >= limit;
8368
8371
  if (!rowsCapped && !spansCapped)
8369
8372
  return null;
8370
- return { rowsCapped, spansCapped, hasMoreKnown: hasMore, rows, spans };
8373
+ const reason = typeof summary.truncated_reason === "string" ? summary.truncated_reason : null;
8374
+ const cursorValue = summary.next_cursor ?? record.next_cursor;
8375
+ const nextCursor = typeof cursorValue === "string" && cursorValue ? cursorValue : null;
8376
+ return { rowsCapped, spansCapped, hasMoreKnown: hasMore, rows, spans, reason, nextCursor };
8377
+ }
8378
+ var AUDIT_MIN_PAGE_BYTES = 32 * 1024;
8379
+ var AUDIT_AGENT_RESERVE_BYTES = 16 * 1024;
8380
+ async function fetchAudit(id, query2, maxBytes) {
8381
+ const pageQuery = new URLSearchParams(query2);
8382
+ if (maxBytes !== undefined)
8383
+ pageQuery.set("max_bytes", maxBytes.toString());
8384
+ const queryString = pageQuery.toString() ? `?${pageQuery.toString()}` : "";
8385
+ return callDataAPI(`/audit/${encodeURIComponent(id)}${queryString}`);
8386
+ }
8387
+ function auditOutput(command, params, data) {
8388
+ const capped = auditCapStatus(data, params.limit ?? AUDIT_DEFAULT_LIMIT);
8389
+ const auditRecord = asRecord(data);
8390
+ if (!capped || !auditRecord) {
8391
+ return { data: auditRecord ? { ...auditRecord, truncated: false, has_more: false, next_cursor: null } : data, options: {} };
8392
+ }
8393
+ const limit = params.limit ?? AUDIT_DEFAULT_LIMIT;
8394
+ const perTrace = "audit one OTLP trace at a time with `moda audit <trace_id> --kind=trace` (ids in summary.trace_ids)";
8395
+ const warnings = [];
8396
+ const nextCommands = [];
8397
+ const auditFlags = (extra) => [
8398
+ `moda ${command} ${shellArg(params.id)}`,
8399
+ params.kind && params.kind !== "auto" ? `--kind=${params.kind}` : "",
8400
+ params.include_raw === true ? "--include-raw" : "",
8401
+ params.include_bodies === true ? "--include-bodies" : "",
8402
+ ...extra
8403
+ ].filter(Boolean).join(" ");
8404
+ if (capped.nextCursor) {
8405
+ nextCommands.push({
8406
+ command: auditFlags([params.limit ? `--limit=${params.limit}` : "", `--cursor=${capped.nextCursor}`]),
8407
+ purpose: "Read the next page of ingest rows of this trace.",
8408
+ mutability: "read",
8409
+ requires_approval: false
8410
+ });
8411
+ }
8412
+ if (capped.reason === "byte_limit") {
8413
+ warnings.push(`Spans were capped: the response reached the server's size budget after ${capped.rows} ingest row(s), so this trace has more spans than the ${capped.spans} shown. ` + `Continue with the next_cursor page${params.include_bodies === true ? ", or drop --include-bodies to fit more rows per page" : ""}. Orphan/duplicate analysis covers this page only.`);
8414
+ } else if (capped.reason === "span_limit" && capped.nextCursor) {
8415
+ warnings.push(`Spans were capped: the page reached the server's per-page span cap after ${capped.rows} ingest row(s), so this trace has more spans than the ${capped.spans} shown. ` + "Continue with the next_cursor page. Orphan/duplicate analysis covers this page only.");
8416
+ } else if (capped.rowsCapped) {
8417
+ const bigger = Math.min(AUDIT_MAX_LIMIT, limit * 5);
8418
+ warnings.push(`Spans were capped: read ${capped.rows} ingest row(s), the --limit=${limit} maximum, so this trace ${capped.hasMoreKnown ? "has" : "may have"} more spans than the ${capped.spans} shown. ` + (capped.nextCursor ? "Page on with the next_cursor command, or " : "") + (limit < AUDIT_MAX_LIMIT ? `${capped.nextCursor ? "rerun" : "Rerun"} with --limit=${bigger} (max ${AUDIT_MAX_LIMIT}), or ${perTrace}.` : capped.nextCursor ? `${perTrace}.` : `${perTrace[0].toUpperCase()}${perTrace.slice(1)}.`));
8419
+ if (limit < AUDIT_MAX_LIMIT && !params.cursor) {
8420
+ nextCommands.push({ command: auditFlags([`--limit=${bigger}`]), purpose: "Read more ingest rows of this trace.", mutability: "read", requires_approval: false });
8421
+ }
8422
+ } else {
8423
+ warnings.push(`Spans were capped: the server returned ${capped.spans} span(s) and marked the response truncated. ${perTrace[0].toUpperCase()}${perTrace.slice(1)}.`);
8424
+ }
8425
+ return {
8426
+ data: { ...auditRecord, truncated: true, has_more: capped.rowsCapped, next_cursor: capped.nextCursor },
8427
+ options: { warnings, ...nextCommands.length > 0 ? { nextCommands } : {} }
8428
+ };
8371
8429
  }
8372
8430
  var TAIL_SEEN_MAX = 5000;
8373
8431
  var EMOTIONS_TAIL_PAGE_SIZE = 20;
@@ -9055,7 +9113,7 @@ async function readFullTranscript(conversationId, opts = {}) {
9055
9113
  out.push(`Message order may not be chronological: ${tied} of ${total} messages share a timestamp with another message ` + `(ordered by id, not time)${synthetic > 0 ? ` and ${synthetic} carry a synthetic pre-2022 timestamp` : ""}.`);
9056
9114
  }
9057
9115
  if (returned.some(isTruncated)) {
9058
- out.push(`Message text, tool-call inputs and tool results longer than ${CONTEXT_MESSAGE_TRUNCATE_CHARS} characters are truncated by the context endpoint. ` + "For full raw content (prompts, tool arguments/results) use `moda audit <conversation_id> --include-raw`.");
9116
+ out.push(`Message text, tool-call inputs and tool results longer than ${CONTEXT_MESSAGE_TRUNCATE_CHARS} characters are truncated by the context endpoint. ` + "For full content (prompts, tool arguments/results) use `moda audit <conversation_id> --include-bodies` (or `--include-raw` for the verbatim events).");
9059
9117
  }
9060
9118
  return {
9061
9119
  data: stripLoneSurrogates({
@@ -9366,7 +9424,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
9366
9424
  case "audit":
9367
9425
  case "trace": {
9368
9426
  if (!positional) {
9369
- throw new CliInputError("<conversation_id|trace_id> is required", "Usage: moda audit <conversation_id|trace_id> [--kind=auto|trace|conversation] [--include-raw] [--limit=N]");
9427
+ 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>]");
9370
9428
  }
9371
9429
  const args = flagsToArgs(flags, "id", positional);
9372
9430
  const params = parseCommandFlags(AuditSchema, args, command, { positionalKey: "id" });
@@ -9375,36 +9433,26 @@ async function runCommand(command, positional, flags, positionals = positional ?
9375
9433
  query2.set("kind", params.kind);
9376
9434
  if (params.include_raw === true)
9377
9435
  query2.set("include_raw", "1");
9436
+ if (params.include_bodies === true)
9437
+ query2.set("include_bodies", "1");
9378
9438
  if (params.limit)
9379
9439
  query2.set("limit", params.limit.toString());
9380
- const queryString = query2.toString() ? `?${query2.toString()}` : "";
9381
- const data = await callDataAPI(`/audit/${encodeURIComponent(params.id)}${queryString}`);
9382
- const capped = auditCapStatus(data, params.limit ?? AUDIT_DEFAULT_LIMIT);
9383
- const auditRecord = asRecord(data);
9384
- if (!capped || !auditRecord) {
9385
- context.output.writeData(auditRecord ? { ...auditRecord, truncated: false, has_more: false } : data);
9386
- break;
9387
- }
9388
- const limit = params.limit ?? AUDIT_DEFAULT_LIMIT;
9389
- const perTrace = "audit one OTLP trace at a time with `moda audit <trace_id> --kind=trace` (ids in summary.trace_ids)";
9390
- const warnings = [];
9391
- const nextCommands = [];
9392
- if (capped.rowsCapped) {
9393
- const bigger = Math.min(AUDIT_MAX_LIMIT, limit * 5);
9394
- warnings.push(`Spans were capped: read ${capped.rows} ingest row(s), the --limit=${limit} maximum, so this trace ${capped.hasMoreKnown ? "has" : "may have"} more spans than the ${capped.spans} shown. ` + (limit < AUDIT_MAX_LIMIT ? `Rerun with --limit=${bigger} (max ${AUDIT_MAX_LIMIT}), or ${perTrace}.` : `${perTrace[0].toUpperCase()}${perTrace.slice(1)}.`));
9395
- if (limit < AUDIT_MAX_LIMIT) {
9396
- const rerun = [
9397
- `moda ${command} ${shellArg(params.id)}`,
9398
- params.kind && params.kind !== "auto" ? `--kind=${params.kind}` : "",
9399
- params.include_raw === true ? "--include-raw" : "",
9400
- `--limit=${bigger}`
9401
- ].filter(Boolean).join(" ");
9402
- nextCommands.push({ command: rerun, purpose: "Read more ingest rows of this trace.", mutability: "read", requires_approval: false });
9403
- }
9404
- } else {
9405
- warnings.push(`Spans were capped: the server returned ${capped.spans} span(s) and marked the response truncated. ${perTrace[0].toUpperCase()}${perTrace.slice(1)}.`);
9440
+ if (params.cursor)
9441
+ query2.set("cursor", params.cursor);
9442
+ const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
9443
+ let maxBytes = agentMode ? Math.max(AUDIT_MIN_PAGE_BYTES, agentMaxOutputBytes() - AUDIT_AGENT_RESERVE_BYTES) : undefined;
9444
+ let page = auditOutput(command, params, await fetchAudit(params.id, query2, maxBytes));
9445
+ while (maxBytes !== undefined && maxBytes > AUDIT_MIN_PAGE_BYTES && !agentEnvelopeFits(command, page.data, page.options)) {
9446
+ maxBytes = Math.max(AUDIT_MIN_PAGE_BYTES, Math.floor(maxBytes / 2));
9447
+ page = auditOutput(command, params, await fetchAudit(params.id, query2, maxBytes));
9448
+ }
9449
+ if (maxBytes !== undefined && !agentEnvelopeFits(command, page.data, page.options)) {
9450
+ page.options.warnings = [
9451
+ ...page.options.warnings ?? [],
9452
+ "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."
9453
+ ];
9406
9454
  }
9407
- context.output.writeData({ ...auditRecord, truncated: true, has_more: capped.rowsCapped }, { warnings, ...nextCommands.length > 0 ? { nextCommands } : {} });
9455
+ context.output.writeData(page.data, page.options);
9408
9456
  break;
9409
9457
  }
9410
9458
  case "frustrations": {
@@ -10115,7 +10163,7 @@ var commandRegistry = createCommandRegistry([
10115
10163
  resetApiRequestCountBeforeRun: true,
10116
10164
  telemetry: "result",
10117
10165
  handler: async (context) => {
10118
- const { runInit } = await import("./index-p8vab4p4.js");
10166
+ const { runInit } = await import("./index-pdg9t77n.js");
10119
10167
  if (context.outputMode === "agent-stream") {
10120
10168
  context.output.writeEvent({
10121
10169
  event: "started",
@@ -10156,7 +10204,7 @@ var commandRegistry = createCommandRegistry([
10156
10204
  resetApiRequestCountBeforeRun: true,
10157
10205
  telemetry: "result-and-error",
10158
10206
  handler: async (context) => {
10159
- const { runProvision } = await import("./provision-e4cnxpdh.js");
10207
+ const { runProvision } = await import("./provision-7fhbgk2d.js");
10160
10208
  return runProvision(context, {
10161
10209
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
10162
10210
  });
@@ -10633,7 +10681,9 @@ var commandRegistry = createCommandRegistry([
10633
10681
  "moda audit <conversation_id|trace_id>",
10634
10682
  "moda audit <trace_id> --kind=trace --json",
10635
10683
  "moda audit <conversation_id> --include-raw",
10636
- "moda audit <conversation_id> --limit=1000 # ingest rows to read (default 200, max 1000); warns when capped"
10684
+ "moda audit <conversation_id> --include-bodies # keep prompt/response bodies (omitted by default; long strings truncated)",
10685
+ "moda audit <conversation_id> --limit=1000 # ingest rows to read (default 200, max 1000); warns when capped",
10686
+ "moda audit <conversation_id> --cursor=<next_cursor> # next page of a capped audit"
10637
10687
  ],
10638
10688
  ...dataApiDefaults
10639
10689
  }),
@@ -11061,6 +11111,15 @@ function printCliError(error) {
11061
11111
  ${issues.join(`
11062
11112
  `)}
11063
11113
  `);
11114
+ } else if (error instanceof ApiError && error.readable) {
11115
+ safeWriteStderr(`${error.message}
11116
+ `);
11117
+ if (error.suggestions?.length) {
11118
+ safeWriteStderr(`Try:
11119
+ ${error.suggestions.map((s) => ` ${s}`).join(`
11120
+ `)}
11121
+ `);
11122
+ }
11064
11123
  } else if (error instanceof ApiError) {
11065
11124
  safeWriteStderr(`API error (HTTP ${error.statusCode}): ${error.responseBody || error.message}
11066
11125
  `);
@@ -42,8 +42,8 @@ import {
42
42
  writeHarnessAnalyzeResult,
43
43
  writeHarnessArtifacts,
44
44
  writeHumanProgress
45
- } from "./cli-tznhpmf2.js";
46
- import"./cli-233xm35b.js";
45
+ } from "./cli-m3bg9yyh.js";
46
+ import"./cli-bqhs6sk7.js";
47
47
  import"./cli-0v6na3yp.js";
48
48
  export {
49
49
  writeHumanProgress,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-tznhpmf2.js";
4
- import"./cli-233xm35b.js";
3
+ } from "./cli-m3bg9yyh.js";
4
+ import"./cli-bqhs6sk7.js";
5
5
  import"./cli-0v6na3yp.js";
6
6
 
7
7
  // src/harness-github-actions.ts
@@ -3,7 +3,7 @@ import {
3
3
  initPrompts,
4
4
  runPromptSync,
5
5
  runSkillSync
6
- } from "./cli-eaaegm7a.js";
6
+ } from "./cli-6xndg2h4.js";
7
7
  import {
8
8
  codingAgentDisplayName,
9
9
  describeCodingAgentEvent,
@@ -22,7 +22,7 @@ import {
22
22
  runHarnessCommand,
23
23
  startRemoteAnalyze,
24
24
  stripAnsi
25
- } from "./cli-tznhpmf2.js";
25
+ } from "./cli-m3bg9yyh.js";
26
26
  import {
27
27
  bundledSkillsDir,
28
28
  installIntegrationSkill,
@@ -34,14 +34,14 @@ import {
34
34
  } from "./cli-ssfq84k5.js";
35
35
  import {
36
36
  selectTenantAndCreateKey
37
- } from "./cli-ss2nere4.js";
37
+ } from "./cli-taf854xx.js";
38
38
  import {
39
39
  ConnectCodeError,
40
40
  connectWithCode,
41
41
  loadAuthSession,
42
42
  loadToken,
43
43
  login
44
- } from "./cli-fpt3jkyh.js";
44
+ } from "./cli-c64d2jrw.js";
45
45
  import {
46
46
  CliAuthError,
47
47
  CliInputError,
@@ -49,7 +49,7 @@ import {
49
49
  createCommandContext,
50
50
  resolveIngestUrl,
51
51
  resolveModaBaseUrl
52
- } from "./cli-233xm35b.js";
52
+ } from "./cli-bqhs6sk7.js";
53
53
  import"./cli-0v6na3yp.js";
54
54
 
55
55
  // src/init/index.ts
@@ -604,6 +604,11 @@ function hasUnexpectedAuditDuplicates(value) {
604
604
  return new Set(calls).size !== calls.length;
605
605
  });
606
606
  }
607
+ function promptHasSystemMessage(prompt) {
608
+ if (Array.isArray(prompt))
609
+ return prompt.some((message) => isRecord2(message) && message.role === "system");
610
+ return isRecord2(prompt) && prompt.reason === "row_payload_cap" && Array.isArray(prompt.roles) && prompt.roles.includes("system");
611
+ }
607
612
  function completeAI7Projection(value) {
608
613
  if (!isAI7Audit(value))
609
614
  return true;
@@ -612,7 +617,7 @@ function completeAI7Projection(value) {
612
617
  const spans = value.spans.filter(isRecord2);
613
618
  for (const span of spans.filter((span2) => span2.type === "llm")) {
614
619
  if (isRecord2(span.attributes) && span.attributes["gen_ai.system_instructions"]) {
615
- if (!Array.isArray(span.prompt) || !span.prompt.some((message) => isRecord2(message) && message.role === "system"))
620
+ if (!promptHasSystemMessage(span.prompt))
616
621
  return false;
617
622
  }
618
623
  }
@@ -632,7 +637,7 @@ function completeAI7Projection(value) {
632
637
  return expected.every((id) => typeof id === "string") && actual.every((id) => typeof id === "string") && new Set(actual).size === actual.length && expected.length === actual.length && expected.every((id) => actual.includes(id));
633
638
  }
634
639
  async function fetchAuditWithApiKey(id, apiKey, baseUrl) {
635
- const url = `${baseUrl}/api/v1/data/audit/${encodeURIComponent(id)}?kind=conversation`;
640
+ const url = `${baseUrl}/api/v1/data/audit/${encodeURIComponent(id)}?kind=conversation&include_bodies=1`;
636
641
  const response = await fetch(url, {
637
642
  method: "GET",
638
643
  headers: { "x-api-key": apiKey },
@@ -5,8 +5,8 @@ import {
5
5
  inspectCodeSelectors,
6
6
  inspectPythonSelectors,
7
7
  safePromptEvidencePath
8
- } from "./cli-tznhpmf2.js";
9
- import"./cli-233xm35b.js";
8
+ } from "./cli-m3bg9yyh.js";
9
+ import"./cli-bqhs6sk7.js";
10
10
  import {
11
11
  __commonJS,
12
12
  __toESM
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  selectTenantAndCreateKey
3
- } from "./cli-ss2nere4.js";
3
+ } from "./cli-taf854xx.js";
4
4
  import {
5
5
  loadAuthSession
6
- } from "./cli-fpt3jkyh.js";
6
+ } from "./cli-c64d2jrw.js";
7
7
  import {
8
8
  CliAuthError,
9
9
  resolveIngestUrl,
10
10
  resolveModaBaseUrl,
11
11
  stringOption
12
- } from "./cli-233xm35b.js";
12
+ } from "./cli-bqhs6sk7.js";
13
13
  import"./cli-0v6na3yp.js";
14
14
 
15
15
  // src/provision.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moda-ai/cli",
3
- "version": "1.48.0",
3
+ "version": "1.49.0",
4
4
  "description": "CLI for Moda - AI agent analytics and observability",
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-10T06:36:17.459Z",
4
- "cli_version": "1.48.0",
3
+ "bundled_at": "2026-10-10T08:40:09.772Z",
4
+ "cli_version": "1.49.0",
5
5
  "skills": [
6
6
  {
7
7
  "id": "integration-cloudflare-think",
@@ -652,13 +652,23 @@ tool calls, prompt/response bodies, and `gen_ai.*` attributes — use `moda audi
652
652
  moda audit <conversation_id|trace_id> # auto-detects OTLP trace_id vs trace ID (conversation_id)
653
653
  moda audit <trace_id> --kind=trace # force OTLP trace_id lookup
654
654
  moda audit <conversation_id> --include-raw # attach verbatim raw_event bodies
655
+ moda audit <conversation_id> --include-bodies # keep prompt/response/attribute bodies
655
656
  moda audit <conversation_id> --limit=1000 # ingest rows to read (default 200, max 1000)
657
+ moda audit <conversation_id> --cursor=<next_cursor> # next page of a capped audit
656
658
  ```
657
659
 
658
660
  `truncated` / `has_more` at the top level say whether the audit is complete.
659
- A full `--limit` page of ingest rows (or a server span cap) sets both, and a
660
- warning plus `next_commands` give the rerun; for very large traces audit one
661
- OTLP trace at a time (`summary.trace_ids`, `--kind=trace`).
661
+ A full `--limit` page of ingest rows, the server's ~3 MB response budget
662
+ (`summary.truncated_reason: "byte_limit"`) or a span cap sets both, and a
663
+ warning plus `next_commands` give the follow-up — usually the `--cursor=` page
664
+ from `next_cursor`; for very large traces audit one OTLP trace at a time
665
+ (`summary.trace_ids`, `--kind=trace`). Prompt/response bodies are omitted by
666
+ default (`{"omitted": true, "original_bytes": N}`); `--include-bodies` keeps
667
+ them, cutting strings over 8 KB to `{"truncated": true, "original_bytes": N,
668
+ "preview": …}`. Ingest rows whose stored payload is too large carry
669
+ `payload_capped: true`: their spans keep ids, hierarchy, timing and types but
670
+ no bodies. A trace too large to audit at all fails fast with an
671
+ `audit_too_large` error whose `suggested_commands` list per-trace audits.
662
672
 
663
673
  Returns the raw, NON-deduped span set from the Layer-0 store (`events_raw`), so
664
674
  nothing is collapsed. Use it to verify capture completeness: the `summary` gives