@moda-ai/cli 1.50.0 → 1.54.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.
@@ -534,9 +534,11 @@ function writeSecretJsonFile(path, value) {
534
534
  // src/errors.ts
535
535
  class CliInputError extends Error {
536
536
  usage;
537
- constructor(message, usage) {
537
+ reason;
538
+ constructor(message, usage, reason) {
538
539
  super(message);
539
540
  this.usage = usage;
541
+ this.reason = reason;
540
542
  this.name = "CliInputError";
541
543
  }
542
544
  }
@@ -7,7 +7,7 @@ import {
7
7
  saveProfileConfig,
8
8
  secretFilePathFromRef,
9
9
  writeSecretJsonFile
10
- } from "./cli-xrs02c0t.js";
10
+ } from "./cli-ac3p2byq.js";
11
11
  import {
12
12
  __require
13
13
  } from "./cli-0v6na3yp.js";
@@ -0,0 +1,47 @@
1
+ // src/prompt-hash.ts
2
+ import { createHash } from "node:crypto";
3
+ var PROMPT_HASH_VERSION = 1;
4
+ function promptSourceHashPayload(definition) {
5
+ return {
6
+ kind: definition.kind,
7
+ source: definition.source,
8
+ ...["text", "messages"].includes(definition.kind) ? {
9
+ sourceHash: definition.sourceHash
10
+ } : ["builder", "template"].includes(definition.kind) ? {
11
+ sourceHash: definition.sourceHash,
12
+ dependencies: definition.dependencies,
13
+ coverage: definition.coverage,
14
+ unresolved: definition.unresolved
15
+ } : {}
16
+ };
17
+ }
18
+ function stableJson(value) {
19
+ return JSON.stringify(sortJson(value));
20
+ }
21
+ function sortJson(value) {
22
+ if (Array.isArray(value))
23
+ return value.map(sortJson);
24
+ if (value && typeof value === "object") {
25
+ return Object.fromEntries(Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, item]) => [key, sortJson(item)]));
26
+ }
27
+ return value;
28
+ }
29
+ function promptContentHashPayload(prompt) {
30
+ return stableJson({
31
+ key: prompt.key,
32
+ content: prompt.content,
33
+ systemPrompt: prompt.systemPrompt ?? null,
34
+ messages: prompt.messages ?? [],
35
+ variables: prompt.variables ?? [],
36
+ variablesSchema: prompt.variablesSchema ?? {},
37
+ modelConfig: prompt.modelConfig ?? {},
38
+ toolRefs: prompt.toolRefs ?? [],
39
+ responseSchema: prompt.responseSchema ?? null,
40
+ ...prompt.sourceDefinition ? { sourceDefinition: promptSourceHashPayload(prompt.sourceDefinition) } : {}
41
+ });
42
+ }
43
+ function computePromptContentHash(prompt) {
44
+ return createHash("sha256").update(promptContentHashPayload(prompt)).digest("hex");
45
+ }
46
+
47
+ export { PROMPT_HASH_VERSION, promptSourceHashPayload, stableJson, promptContentHashPayload, computePromptContentHash };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  authFetch,
3
3
  getCachedLoginContext
4
- } from "./cli-7kbzqact.js";
4
+ } from "./cli-kxwm7y62.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-xrs02c0t.js";
18
+ } from "./cli-ac3p2byq.js";
19
19
 
20
20
  // src/init/tenant.ts
21
21
  import { randomUUID } from "node:crypto";
package/dist/cli.js CHANGED
@@ -8,7 +8,8 @@ import {
8
8
  runPromptsCommand,
9
9
  runSkillsCommand,
10
10
  runStatusCommand
11
- } from "./cli-jqfm8dp4.js";
11
+ } from "./cli-a2jq9yd5.js";
12
+ import"./cli-mm48br00.js";
12
13
  import {
13
14
  ApiError,
14
15
  HARNESS_REPORT_APPROVAL_PATH,
@@ -37,7 +38,7 @@ import {
37
38
  terminalStyles,
38
39
  unknownSignalsSubcommandError,
39
40
  validateHarnessReport
40
- } from "./cli-x0x0n35w.js";
41
+ } from "./cli-9250ckvg.js";
41
42
  import"./cli-ssfq84k5.js";
42
43
  import {
43
44
  authFetch,
@@ -46,7 +47,7 @@ import {
46
47
  loadAuthSession,
47
48
  login,
48
49
  revokeCliSessionToken
49
- } from "./cli-7kbzqact.js";
50
+ } from "./cli-kxwm7y62.js";
50
51
  import {
51
52
  AGENT_ERROR_CODES,
52
53
  CliAccessError,
@@ -97,7 +98,7 @@ import {
97
98
  validateConfig,
98
99
  wasOutputCancelled,
99
100
  writeSecretJsonFile
100
- } from "./cli-xrs02c0t.js";
101
+ } from "./cli-ac3p2byq.js";
101
102
  import {
102
103
  __require
103
104
  } from "./cli-0v6na3yp.js";
@@ -150,11 +151,20 @@ var WorldStateSchema = z.object({
150
151
  format: z.enum(["frames", "fold-inputs"]).optional(),
151
152
  message_count: z.number().min(1).max(1e6).optional()
152
153
  });
154
+ var lenientBoolFlag = () => z.preprocess((val) => {
155
+ const text = String(val).toLowerCase();
156
+ if (["true", "1", "yes", "on"].includes(text))
157
+ return true;
158
+ if (["false", "0", "no", "off"].includes(text))
159
+ return false;
160
+ return val;
161
+ }, z.boolean()).optional();
153
162
  var ContextSchema = z.object({
154
- conversation_id: z.string(),
155
- msg_index: z.number().min(0).optional(),
163
+ conversation_id: z.string().min(1),
164
+ msg_index: z.number().int().min(0).optional(),
156
165
  window: z.number().int().min(0).optional(),
157
- all: boolFlag(),
166
+ metadata_only: lenientBoolFlag(),
167
+ all: lenientBoolFlag(),
158
168
  from: z.number().int().min(0).optional(),
159
169
  max_messages: z.number().int().min(1).max(5000).optional()
160
170
  });
@@ -1991,6 +2001,20 @@ function nextCommandsFor(fix) {
1991
2001
  }
1992
2002
  ];
1993
2003
  case "UNROUTED":
2004
+ return [
2005
+ {
2006
+ command: `moda fix ${fix.id} --packet`,
2007
+ purpose: "Read the investigation packet — this fix is deliverable as diagnosis.",
2008
+ mutability: "read",
2009
+ requires_approval: false
2010
+ },
2011
+ {
2012
+ command: "moda prompts status",
2013
+ purpose: "If the reason says evidence carries no prompt version: check the prompt lockfile, then pass prompt: lock.prompts['<key>'] to createThinkTelemetry / createAI7Telemetry (docs.moda.dev/prompt-management/attribution).",
2014
+ mutability: "read",
2015
+ requires_approval: false
2016
+ }
2017
+ ];
1994
2018
  case "NO_EVIDENCE":
1995
2019
  case "BLOCKED_COVERAGE":
1996
2020
  case "NO_HEADROOM":
@@ -3534,6 +3558,11 @@ function stripTelemetryFlag(flags) {
3534
3558
  function isTelemetryDisabled(flags) {
3535
3559
  return flags[TELEMETRY_FLAG] === "true" || process.env.MODA_CLI_TELEMETRY === "0" || process.env.DO_NOT_TRACK === "1";
3536
3560
  }
3561
+ var VALIDATION_REASON_MAX = 128;
3562
+ function sanitizeValidationReason(reason) {
3563
+ const cleaned = reason?.replace(/[^A-Za-z0-9_.:-]/g, "_").slice(0, VALIDATION_REASON_MAX);
3564
+ return cleaned ? cleaned : undefined;
3565
+ }
3537
3566
  function sanitizedFlagNames(flags) {
3538
3567
  return Object.keys(stripTelemetryFlag(flags)).sort();
3539
3568
  }
@@ -3541,6 +3570,7 @@ async function sendCliUsageTelemetry(input) {
3541
3570
  if (!input.apiKey || isTelemetryDisabled(input.flags)) {
3542
3571
  return;
3543
3572
  }
3573
+ const validationReason = sanitizeValidationReason(input.validationReason);
3544
3574
  const controller = new AbortController;
3545
3575
  const timeout = setTimeout(() => controller.abort(), TELEMETRY_TIMEOUT_MS);
3546
3576
  if (typeof timeout.unref === "function") {
@@ -3558,6 +3588,7 @@ async function sendCliUsageTelemetry(input) {
3558
3588
  command: input.command.slice(0, 64),
3559
3589
  status: input.status,
3560
3590
  error_type: input.errorType,
3591
+ ...validationReason ? { validation_reason: validationReason } : {},
3561
3592
  exit_code: input.exitCode,
3562
3593
  duration_ms: Math.max(0, Math.round(input.durationMs)),
3563
3594
  api_request_count: Math.max(0, Math.round(input.apiRequestCount)),
@@ -6663,7 +6694,7 @@ function frustrationFindings(data, daysBack, evidenceRefs) {
6663
6694
  id: "action_frustration_window",
6664
6695
  title: "Read the frustration window.",
6665
6696
  rationale: "The user quote and nearby turns reveal what confused or blocked the user.",
6666
- command: conversationId ? `moda context ${conversationId}${anchorIndex !== null ? ` --msg-index=${anchorIndex}` : ""} --window=3` : `moda frustrations --days-back=${daysBack} --include-window`,
6697
+ command: conversationId ? `moda context ${shellWord(conversationId)}${anchorIndex !== null ? ` --msg-index=${anchorIndex}` : ""} --window=3` : `moda frustrations --days-back=${daysBack} --include-window`,
6667
6698
  mutability: "read",
6668
6699
  requiresApproval: false
6669
6700
  }]
@@ -7750,7 +7781,7 @@ function parseArgs(argv) {
7750
7781
  if (!endOfOptions && arg === "--" && command !== "") {
7751
7782
  endOfOptions = true;
7752
7783
  } else if (!endOfOptions && arg.startsWith("--")) {
7753
- i = parseFlag(args, i, flags, command === "", bareFlags);
7784
+ i = parseFlag(args, i, flags, command === "", bareFlags, command);
7754
7785
  } else if (!endOfOptions && command !== "" && /^-[A-Za-z]/.test(arg)) {
7755
7786
  shortFlags.push(arg);
7756
7787
  } else if (command === "") {
@@ -7790,7 +7821,10 @@ var GLOBAL_BOOLEAN_FLAGS = new Set([
7790
7821
  "tui",
7791
7822
  "no-tui"
7792
7823
  ]);
7793
- function parseFlag(args, index, flags, beforeCommand, bareFlags) {
7824
+ var COMMAND_BOOLEAN_FLAGS = {
7825
+ context: new Set(["all", "metadata-only"])
7826
+ };
7827
+ function parseFlag(args, index, flags, beforeCommand, bareFlags, command = "") {
7794
7828
  const set = (key2, value, bare) => {
7795
7829
  flags[key2] = value;
7796
7830
  const at = bareFlags.indexOf(key2);
@@ -7811,6 +7845,10 @@ function parseFlag(args, index, flags, beforeCommand, bareFlags) {
7811
7845
  set(key, "true", true);
7812
7846
  return index;
7813
7847
  }
7848
+ if (!beforeCommand && COMMAND_BOOLEAN_FLAGS[command]?.has(key.replace(/_/g, "-")) && next !== "true" && next !== "false") {
7849
+ set(key, "true", true);
7850
+ return index;
7851
+ }
7814
7852
  if (next !== undefined && !next.startsWith("--")) {
7815
7853
  set(key, next, false);
7816
7854
  return index + 1;
@@ -7903,7 +7941,7 @@ Commands:
7903
7941
  traces --sort=longest Sort traces: recent (default), longest, slowest
7904
7942
  search "<query>" Search trace messages (keyword/semantic/hybrid)
7905
7943
  world-state <conversation_id> Get a trace's world state (slots/threads/events)
7906
- context <conversation_id> Get windowed trace context
7944
+ context <conversation_id> Get windowed trace context (--metadata-only: summary + counts only)
7907
7945
  context <conversation_id> --all Whole transcript in order (first 500; --from=N --max-messages=N to continue)
7908
7946
  audit <conversation_id|trace_id> Raw span audit (spans, hierarchy, orphans, duplicates)
7909
7947
  frustrations Frustration detections (same data as emotions --family=frustration)
@@ -7940,9 +7978,10 @@ Commands:
7940
7978
  --signal=conversations = --signal=traces. <conversation_id> is the trace ID.
7941
7979
 
7942
7980
  Prompt management:
7943
- prompts init Create .moda/prompts.yml
7944
- prompts status Show local prompt changes
7981
+ prompts init Create .moda/prompts.yml (version 2: prompt_paths + sources)
7982
+ prompts status Show local prompt changes; warns on globs that match nothing
7945
7983
  prompts diff Only changed/new/deleted prompts since last sync
7984
+ prompts migrate [--dry-run] Rewrite a version 1 .moda/prompts.yml to version 2
7946
7985
  prompts sync Analyze prompt sources and upload versions
7947
7986
  prompts sync --watch Upload again when prompt files change
7948
7987
  prompts list|show|proposals|usage|replay-runs|decide
@@ -8736,7 +8775,7 @@ function parseCommandFlags(schema, args, command, options = {}) {
8736
8775
  ]);
8737
8776
  const unknown = Object.keys(args).filter((key) => !known.has(key));
8738
8777
  if (unknown.includes("dry_run")) {
8739
- throw new CliInputError(`'moda ${command}' has no dry-run mode, so nothing was sent.`, `Remove --dry-run to run it for real. Commands with a real dry-run: sync, registry push, harness sync/delete, prompts sync/decide, skills sync/policy, signals <write subcommands>, problem-reopen.`);
8778
+ throw new CliInputError(`'moda ${command}' has no dry-run mode, so nothing was sent.`, `Remove --dry-run to run it for real. Commands with a real dry-run: sync, registry push, harness sync/delete, prompts sync/decide, skills sync/policy, signals <write subcommands>, problem-reopen.`, "unsupported_dry_run");
8740
8779
  }
8741
8780
  if (unknown.length > 0) {
8742
8781
  const flagKeys = schemaKeys.filter((key) => key !== options.positionalKey);
@@ -8751,7 +8790,7 @@ function parseCommandFlags(schema, args, command, options = {}) {
8751
8790
  return close ? `Did you mean --${close.candidate.replace(/_/g, "-")}?` : "";
8752
8791
  }).filter(Boolean);
8753
8792
  const names = unknown.map((key) => `--${key.replace(/_/g, "-")}`).join(", ");
8754
- throw new CliInputError(`Unknown flag${unknown.length > 1 ? "s" : ""} ${names} for 'moda ${command}'.`, [...hints, `Valid flags: ${valid.join(", ") || "(none)"}. Run 'moda ${command} --help'.`].join(" "));
8793
+ throw new CliInputError(`Unknown flag${unknown.length > 1 ? "s" : ""} ${names} for 'moda ${command}'.`, [...hints, `Valid flags: ${valid.join(", ") || "(none)"}. Run 'moda ${command} --help'.`].join(" "), `unknown_flag:${unknown[0].replace(/_/g, "-")}`);
8755
8794
  }
8756
8795
  return schema.parse(args);
8757
8796
  }
@@ -8941,7 +8980,7 @@ function assertHandParsedFlags(command, flags, positionals) {
8941
8980
  } catch (error) {
8942
8981
  if (command !== "feedback" || !(error instanceof CliInputError))
8943
8982
  throw error;
8944
- throw new CliInputError(/nothing was sent/i.test(error.message) ? error.message : `${error.message} Nothing was sent.`, `${error.usage ?? ""} Id flags (--<name>-id=ID) are attached as refs; put other detail in the note. ${FEEDBACK_USAGE}`.trim());
8983
+ throw new CliInputError(/nothing was sent/i.test(error.message) ? error.message : `${error.message} Nothing was sent.`, `${error.usage ?? ""} Id flags (--<name>-id=ID) are attached as refs; put other detail in the note. ${FEEDBACK_USAGE}`.trim(), error.reason);
8945
8984
  }
8946
8985
  }
8947
8986
  var PROFILE_MANAGING_COMMANDS = new Set(["profiles", "auth", "init", "provision", "status", "config", "keys", "manifest", "agent", "doctor"]);
@@ -8975,6 +9014,66 @@ function processingDisabledWarning(data, family) {
8975
9014
  `${family === "emotion" ? "Emotion" : "Frustration"} analysis is disabled for this tenant (${setting} = false), ` + "so zero results do NOT mean users are not frustrated. Enable it in Settings → Account → Signal processing; " + "only traces ingested after enabling are analyzed."
8976
9015
  ];
8977
9016
  }
9017
+ var CONTEXT_USAGE = "Usage: moda context <conversation_id> [--msg-index=N] [--window=0-5 | --metadata-only]";
9018
+ var CONTEXT_ALL_USAGE = "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]";
9019
+ var CONTEXT_MAX_WINDOW = 5;
9020
+ var EMPTY_ANCHOR_VALUES = new Set(["", "null", "undefined", "none"]);
9021
+ function parseContextRequest(positional, rawFlags) {
9022
+ const flags = {};
9023
+ const flagIds = [];
9024
+ for (const [rawKey, value] of Object.entries(rawFlags)) {
9025
+ const key = rawKey.replace(/_/g, "-");
9026
+ if (key === "conversation-id") {
9027
+ if (value !== "true")
9028
+ flagIds.push(value);
9029
+ } else if (flags[key] !== undefined && flags[key] !== value) {
9030
+ throw new CliInputError(`Got two different values for --${key} (both spellings were passed), so nothing was read.`, CONTEXT_USAGE, "flag_conflict");
9031
+ } else {
9032
+ flags[key] = value;
9033
+ }
9034
+ }
9035
+ const flagId = flagIds[0];
9036
+ const warnings = [];
9037
+ if (new Set([...positional !== undefined ? [positional] : [], ...flagIds]).size > 1) {
9038
+ throw new CliInputError("Got two different trace ids (from the positional and --conversation-id), so nothing was read.", CONTEXT_USAGE, "flag_conflict");
9039
+ }
9040
+ const conversationId = positional ?? flagId;
9041
+ if (!conversationId) {
9042
+ throw new CliInputError("<conversation_id> is required", CONTEXT_USAGE, "missing_positional");
9043
+ }
9044
+ const msgIndex = flags["msg-index"];
9045
+ if (msgIndex !== undefined && EMPTY_ANCHOR_VALUES.has(msgIndex.trim().toLowerCase())) {
9046
+ delete flags["msg-index"];
9047
+ warnings.push(`--msg-index had no value (${JSON.stringify(msgIndex)}), so the window is centered on the middle of the trace. ` + "Trace-level search hits have no message_index; pass one only when the hit has it.");
9048
+ }
9049
+ const args = { ...flagsToArgs(flags), conversation_id: conversationId };
9050
+ const params = parseCommandFlags(ContextSchema, args, "context", { positionalKey: "conversation_id" });
9051
+ if (params.metadata_only === true && params.window !== undefined) {
9052
+ throw new CliInputError("--metadata-only reads no messages, so it cannot be combined with --window; drop --window.", CONTEXT_USAGE, "flag_conflict");
9053
+ }
9054
+ if (params.all === true) {
9055
+ if (params.msg_index !== undefined || flags.window !== undefined || params.metadata_only === true) {
9056
+ throw new CliInputError("--all reads the whole trace; drop --msg-index/--window/--metadata-only.", CONTEXT_ALL_USAGE, "flag_conflict");
9057
+ }
9058
+ } else if (params.from !== undefined || params.max_messages !== undefined) {
9059
+ throw new CliInputError("--from and --max-messages page the whole trace and need --all.", CONTEXT_ALL_USAGE, "flag_conflict");
9060
+ }
9061
+ return { params, warnings };
9062
+ }
9063
+ async function readContextMetadataOnly(contextPath, query2) {
9064
+ try {
9065
+ return await callDataAPI(`${contextPath}?${query2.toString()}`);
9066
+ } catch (error) {
9067
+ if (!(error instanceof ApiError) || error.statusCode !== 400 || !/metadata_only/.test(error.message))
9068
+ throw error;
9069
+ const legacy = new URLSearchParams(query2);
9070
+ legacy.delete("metadata_only");
9071
+ legacy.set("window", "0");
9072
+ const data = asRecord(await callDataAPI(`${contextPath}?${legacy.toString()}`)) ?? {};
9073
+ const ctx = asRecord(data.context) ?? {};
9074
+ return { ...data, metadata_only: true, context: { ...ctx, messages: [] } };
9075
+ }
9076
+ }
8978
9077
  var FULL_TRANSCRIPT_DEFAULT_MAX_MESSAGES = 500;
8979
9078
  var CONTEXT_RANGE_PAGE_SIZE = 200;
8980
9079
  var LEGACY_WINDOW_MAX_MESSAGES = 100;
@@ -9001,7 +9100,6 @@ function pageMessages(page) {
9001
9100
  const messages = asRecord(page.context)?.messages ?? page.messages;
9002
9101
  return (Array.isArray(messages) ? messages : []).map((m) => asRecord(m) ?? {});
9003
9102
  }
9004
- var CONTEXT_MAX_WINDOW = 5;
9005
9103
  var CONTEXT_ALL_MAX_MESSAGES = 5000;
9006
9104
  async function readFullTranscript(conversationId, opts = {}) {
9007
9105
  const start = opts.from ?? 0;
@@ -9360,40 +9458,37 @@ async function runCommand(command, positional, flags, positionals = positional ?
9360
9458
  break;
9361
9459
  }
9362
9460
  case "context": {
9363
- if (!positional) {
9364
- throw new CliInputError("<conversation_id> is required", "Usage: moda context <conversation_id> [--msg-index=N] [--window=N]");
9365
- }
9366
- const args = flagsToArgs(flags, "conversation_id", positional);
9367
- const params = parseCommandFlags(ContextSchema, args, command, { positionalKey: "conversation_id" });
9461
+ const { params, warnings: inputWarnings } = parseContextRequest(positional, flags);
9368
9462
  if (params.all === true) {
9369
- if (params.msg_index !== undefined || flags.window !== undefined) {
9370
- throw new CliInputError("--all reads the whole trace; drop --msg-index/--window.", "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]");
9371
- }
9372
9463
  const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
9373
9464
  const full = await readFullTranscript(params.conversation_id, {
9374
9465
  from: params.from,
9375
9466
  maxMessages: params.max_messages,
9376
9467
  fits: agentMode ? (page) => agentEnvelopeFits(command, page.data, { warnings: page.warnings, nextCommands: page.nextCommands }) : undefined
9377
9468
  });
9469
+ const fullWarnings = [...inputWarnings, ...full.warnings];
9378
9470
  context.output.writeData(full.data, {
9379
- ...full.warnings.length > 0 ? { warnings: full.warnings } : {},
9471
+ ...fullWarnings.length > 0 ? { warnings: fullWarnings } : {},
9380
9472
  ...full.nextCommands.length > 0 ? { nextCommands: full.nextCommands } : {}
9381
9473
  });
9382
9474
  break;
9383
9475
  }
9384
- if (params.from !== undefined || params.max_messages !== undefined) {
9385
- throw new CliInputError("--from and --max-messages page the whole trace and need --all.", "Usage: moda context <conversation_id> --all [--from=N] [--max-messages=N]");
9386
- }
9387
9476
  const query2 = new URLSearchParams;
9388
9477
  if (params.msg_index !== undefined)
9389
9478
  query2.set("msg_index", params.msg_index.toString());
9479
+ if (params.metadata_only === true)
9480
+ query2.set("metadata_only", "1");
9390
9481
  const window = params.window === undefined ? undefined : Math.min(params.window, CONTEXT_MAX_WINDOW);
9391
9482
  if (window !== undefined)
9392
9483
  query2.set("window", window.toString());
9393
9484
  const queryString = query2.toString() ? `?${query2.toString()}` : "";
9394
- const data = await callDataAPI(`/conversations/${params.conversation_id}/context${queryString}`);
9485
+ const contextPath = `/conversations/${encodeURIComponent(params.conversation_id)}/context`;
9486
+ const data = params.metadata_only === true ? await readContextMetadataOnly(contextPath, query2) : await callDataAPI(`${contextPath}${queryString}`);
9395
9487
  const ctxRecord = asRecord(data) ?? {};
9396
- const warnings = notFoundWarning("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0);
9488
+ const warnings = [
9489
+ ...inputWarnings,
9490
+ ...notFoundWarning("trace", params.conversation_id, asNumber(ctxRecord.total_messages) === 0)
9491
+ ];
9397
9492
  const nextCommands = [];
9398
9493
  if (params.window !== undefined && params.window > CONTEXT_MAX_WINDOW) {
9399
9494
  const center = asNumber(asRecord(ctxRecord.context)?.center_index) ?? params.msg_index ?? 0;
@@ -10053,7 +10148,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
10053
10148
  function telemetryCommandName(definition) {
10054
10149
  return definition.telemetryCommand ?? definition.name;
10055
10150
  }
10056
- var OFFLINE_PROMPTS_SUBCOMMANDS = new Set(["init", "status", "diff"]);
10151
+ var OFFLINE_PROMPTS_SUBCOMMANDS = new Set(["init", "status", "diff", "migrate"]);
10057
10152
  function legacyCommand(metadata) {
10058
10153
  return {
10059
10154
  ...metadata,
@@ -10147,7 +10242,7 @@ var commandRegistry = createCommandRegistry([
10147
10242
  resetApiRequestCountBeforeRun: true,
10148
10243
  telemetry: "result",
10149
10244
  handler: async (context) => {
10150
- const { runInit } = await import("./index-z0jpjcsm.js");
10245
+ const { runInit } = await import("./index-hn9t95tr.js");
10151
10246
  if (context.outputMode === "agent-stream") {
10152
10247
  context.output.writeEvent({
10153
10248
  event: "started",
@@ -10188,7 +10283,7 @@ var commandRegistry = createCommandRegistry([
10188
10283
  resetApiRequestCountBeforeRun: true,
10189
10284
  telemetry: "result-and-error",
10190
10285
  handler: async (context) => {
10191
- const { runProvision } = await import("./provision-qkazpt0c.js");
10286
+ const { runProvision } = await import("./provision-d1dfj6as.js");
10192
10287
  return runProvision(context, {
10193
10288
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
10194
10289
  });
@@ -10652,6 +10747,7 @@ var commandRegistry = createCommandRegistry([
10652
10747
  examples: [
10653
10748
  "moda context <conversation_id> --window=3",
10654
10749
  "moda context <conversation_id> --msg-index=40 --window=0",
10750
+ "moda context <conversation_id> --metadata-only # summary + total_messages, no messages",
10655
10751
  "moda context <conversation_id> --all",
10656
10752
  "moda context <conversation_id> --all --from=500 --max-messages=500"
10657
10753
  ],
@@ -10900,18 +10996,18 @@ var commandRegistry = createCommandRegistry([
10900
10996
  legacyCommand({
10901
10997
  name: "prompts",
10902
10998
  description: "Manage prompt versions and labels",
10903
- examples: ["moda prompts init", "moda prompts status", "moda prompts sync", "moda prompts ab --baseline=old.md --candidate=new.md"],
10999
+ examples: ["moda prompts init", "moda prompts status", "moda prompts migrate --dry-run", "moda prompts sync", "moda prompts ab --baseline=old.md --candidate=new.md"],
10904
11000
  subcommands: [
10905
11001
  {
10906
11002
  name: "init",
10907
- description: "Create .moda/prompts.yml in the current directory (never overwrites)",
11003
+ description: "Create a version 2 .moda/prompts.yml in the current directory (never overwrites). prompt_paths are exact fast-glob patterns from the repository root; sources: maps prompts defined in code (key, path, selector.symbol|pointer, kind, dependencies).",
10908
11004
  usage: "moda prompts init [--from-harness=<report>]",
10909
- flags: [{ name: "--from-harness=<report>", description: "Register verified source mappings from a harness report; source files stay in place." }],
11005
+ flags: [{ name: "--from-harness=<report>", description: "Register verified source mappings from a harness report (older reports are normalized; prompts without a promptSource are mapped from sourcePath when unambiguous). Unresolvable prompts are returned in imported.skipped with reasons; source files stay in place." }],
10910
11006
  examples: ["moda prompts init", "cd /path/to/project && moda prompts init"]
10911
11007
  },
10912
11008
  {
10913
11009
  name: "status",
10914
- description: "Show prompt files that changed since the last sync",
11010
+ description: "Show prompt files that changed since the last sync. Also reports prompt_paths patterns that match no files (zeroMatchPatterns) and files only older CLIs discovered (legacyOnlyFiles), with a warning pointing at `moda prompts migrate`.",
10915
11011
  usage: "moda prompts status",
10916
11012
  examples: ["moda prompts status"]
10917
11013
  },
@@ -10921,6 +11017,16 @@ var commandRegistry = createCommandRegistry([
10921
11017
  usage: "moda prompts diff",
10922
11018
  examples: ["moda prompts diff"]
10923
11019
  },
11020
+ {
11021
+ name: "migrate",
11022
+ description: "Rewrite .moda/prompts.yml to version 2: keeps every pattern and source, adds explicit paths for prompt files only the older repo-wide discovery matched (so their lockfile keys keep resolving), and ensures a sources: list. Comments are kept; the write is atomic.",
11023
+ usage: "moda prompts migrate [--dry-run] [--discover]",
11024
+ flags: [
11025
+ { name: "--dry-run", description: "Print the migrated manifest without writing it." },
11026
+ { name: "--discover", description: "Also scan for code-defined prompts (deterministic, no agent calls). Adds only mappings that need no semantic verification; other candidates are listed under pendingSources with the command that verifies them." }
11027
+ ],
11028
+ examples: ["moda prompts migrate --dry-run", "moda prompts migrate", "moda prompts migrate --discover"]
11029
+ },
10924
11030
  {
10925
11031
  name: "sync",
10926
11032
  description: "Analyze prompt sources and upload verified versions to Moda Cloud",
@@ -10929,7 +11035,7 @@ var commandRegistry = createCommandRegistry([
10929
11035
  { name: "--analyst=local-scan|claude|codex|cursor|auto", description: "Defaults to auto: deterministic discovery, installed-agent extension, and independent verification. Use local-scan for no agent calls." },
10930
11036
  { name: "--assist=none", description: "Disable agent fallback, including with an explicit analyst." },
10931
11037
  { name: "--no-analyze", description: "Skip discovery and sync only configured sources." },
10932
- { name: "--from-harness=<report>", description: "Read and register harness prompt source mappings before sync." },
11038
+ { name: "--from-harness=<report>", description: "Read and register harness prompt source mappings before sync; unresolvable prompts are listed in harnessImport.skipped. Fails only when none resolve (regenerate with `moda harness analyze --experimental --concern=prompts`)." },
10933
11039
  { name: "--allow-untrack", description: "Explicitly remove missing keys from local tracking; registry history remains." },
10934
11040
  { name: "--watch", description: "Analyze before syncing; re-upload when mapped prompt files change." },
10935
11041
  { name: "--dry-run", description: "Preview without saving mappings or registry versions; deterministic unless an analyst is explicitly selected." }
@@ -11062,7 +11168,15 @@ var commandRegistry = createCommandRegistry([
11062
11168
  }
11063
11169
  ]);
11064
11170
  function classifyCliError(error) {
11065
- if (error instanceof z2.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError || error instanceof CliAuthError || error instanceof CliAccessError) {
11171
+ if (error instanceof CliAuthError)
11172
+ return "auth_error";
11173
+ if (error instanceof CliAccessError)
11174
+ return "access_error";
11175
+ if (error instanceof ApiError && error.statusCode === 401)
11176
+ return "auth_error";
11177
+ if (error instanceof ApiError && error.statusCode === 403)
11178
+ return "access_error";
11179
+ if (error instanceof z2.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError) {
11066
11180
  return "validation_error";
11067
11181
  }
11068
11182
  if (error instanceof ApiError || isApiLikeError(error)) {
@@ -11073,6 +11187,21 @@ function classifyCliError(error) {
11073
11187
  }
11074
11188
  return "unknown_error";
11075
11189
  }
11190
+ function cliValidationReason(error) {
11191
+ if (error instanceof z2.ZodError) {
11192
+ const issue = error.issues[0];
11193
+ if (!issue)
11194
+ return "zod";
11195
+ const path = issue.path.join(".") || "_";
11196
+ return issue.code === "invalid_enum_value" ? `bad_enum:${path}` : `zod:${path}:${issue.code}`;
11197
+ }
11198
+ if (error instanceof CliInputRequiredError)
11199
+ return "input_required";
11200
+ if (error instanceof CliInputError) {
11201
+ return error.reason ?? (/^<[^>]+> is required/.test(error.message) ? "missing_positional" : "input_error");
11202
+ }
11203
+ return;
11204
+ }
11076
11205
  function printCliError(error) {
11077
11206
  if (error instanceof CliInputError) {
11078
11207
  safeWriteStderr(`Error: ${error.message}
@@ -11256,6 +11385,7 @@ async function dispatchParsedCommandInner(parsed, startedAt) {
11256
11385
  flags: commandFlags,
11257
11386
  status: "error",
11258
11387
  errorType: classifyCliError(error),
11388
+ validationReason: cliValidationReason(error),
11259
11389
  exitCode: exitCodeForError(error),
11260
11390
  durationMs: Date.now() - startedAt,
11261
11391
  apiRequestCount: getApiRequestCount(),
@@ -11316,6 +11446,7 @@ async function dispatchParsedCommandInner(parsed, startedAt) {
11316
11446
  flags: commandFlags,
11317
11447
  status: "error",
11318
11448
  errorType: classifyCliError(error),
11449
+ validationReason: cliValidationReason(error),
11319
11450
  exitCode: exitCodeForError(error),
11320
11451
  durationMs: Date.now() - startedAt,
11321
11452
  apiRequestCount: getApiRequestCount(),
@@ -11383,6 +11514,7 @@ export {
11383
11514
  runCommand,
11384
11515
  resolveTailSignal,
11385
11516
  printCliError,
11517
+ parseContextRequest,
11386
11518
  parseCommandFlags,
11387
11519
  parseArgs,
11388
11520
  initFlagsForContext,
@@ -11391,6 +11523,7 @@ export {
11391
11523
  detectCallerAgent,
11392
11524
  describeLinearLink,
11393
11525
  commandRegistry,
11526
+ cliValidationReason,
11394
11527
  classifyCliError,
11395
11528
  capProblemsBlocks,
11396
11529
  buildResumeCommand,
@@ -11398,5 +11531,6 @@ export {
11398
11531
  TAIL_LIMITS,
11399
11532
  LEGACY_WINDOW_MAX_MESSAGES,
11400
11533
  FULL_TRANSCRIPT_DEFAULT_MAX_MESSAGES,
11401
- CliInputError
11534
+ CliInputError,
11535
+ CONTEXT_MAX_WINDOW
11402
11536
  };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-x0x0n35w.js";
4
- import"./cli-xrs02c0t.js";
3
+ } from "./cli-9250ckvg.js";
4
+ import"./cli-ac3p2byq.js";
5
5
  import"./cli-0v6na3yp.js";
6
6
 
7
7
  // src/harness-github-actions.ts
@@ -42,8 +42,8 @@ import {
42
42
  writeHarnessAnalyzeResult,
43
43
  writeHarnessArtifacts,
44
44
  writeHumanProgress
45
- } from "./cli-x0x0n35w.js";
46
- import"./cli-xrs02c0t.js";
45
+ } from "./cli-9250ckvg.js";
46
+ import"./cli-ac3p2byq.js";
47
47
  import"./cli-0v6na3yp.js";
48
48
  export {
49
49
  writeHumanProgress,
@@ -3,7 +3,8 @@ import {
3
3
  initPrompts,
4
4
  runPromptSync,
5
5
  runSkillSync
6
- } from "./cli-jqfm8dp4.js";
6
+ } from "./cli-a2jq9yd5.js";
7
+ import"./cli-mm48br00.js";
7
8
  import {
8
9
  codingAgentDisplayName,
9
10
  describeCodingAgentEvent,
@@ -22,7 +23,7 @@ import {
22
23
  runHarnessCommand,
23
24
  startRemoteAnalyze,
24
25
  stripAnsi
25
- } from "./cli-x0x0n35w.js";
26
+ } from "./cli-9250ckvg.js";
26
27
  import {
27
28
  bundledSkillsDir,
28
29
  installIntegrationSkill,
@@ -34,14 +35,14 @@ import {
34
35
  } from "./cli-ssfq84k5.js";
35
36
  import {
36
37
  selectTenantAndCreateKey
37
- } from "./cli-h4k23fb0.js";
38
+ } from "./cli-sq6g0tk5.js";
38
39
  import {
39
40
  ConnectCodeError,
40
41
  connectWithCode,
41
42
  loadAuthSession,
42
43
  loadToken,
43
44
  login
44
- } from "./cli-7kbzqact.js";
45
+ } from "./cli-kxwm7y62.js";
45
46
  import {
46
47
  CliAuthError,
47
48
  CliInputError,
@@ -49,7 +50,7 @@ import {
49
50
  createCommandContext,
50
51
  resolveIngestUrl,
51
52
  resolveModaBaseUrl
52
- } from "./cli-xrs02c0t.js";
53
+ } from "./cli-ac3p2byq.js";
53
54
  import"./cli-0v6na3yp.js";
54
55
 
55
56
  // src/init/index.ts