@moda-ai/cli 1.55.17 → 1.55.19

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 (29) hide show
  1. package/dist/{agent-cha3kg9d.js → agent-mj622k8s.js} +9 -9
  2. package/dist/{cli-1exddmc0.js → cli-033n2mpb.js} +2 -2
  3. package/dist/{cli-5hq827jt.js → cli-569hj0bj.js} +1 -1
  4. package/dist/{cli-3ezzeqcy.js → cli-5ke3xe6y.js} +47 -3
  5. package/dist/{cli-av3dqgj5.js → cli-5km7j04z.js} +4 -4
  6. package/dist/{cli-eazeanvt.js → cli-7ea02wca.js} +1 -1
  7. package/dist/{cli-qmjnh4z9.js → cli-9x9adrtj.js} +1 -1
  8. package/dist/{cli-a1mv0ypm.js → cli-a5c9te95.js} +5 -5
  9. package/dist/cli-cehskjde.js +1302 -0
  10. package/dist/{cli-5q1gyvxn.js → cli-pc5cw7mx.js} +5 -5
  11. package/dist/{cli-c8p69n55.js → cli-rqk6f6n6.js} +2 -2
  12. package/dist/{cli-0e8bfvn7.js → cli-wf7gfa1e.js} +8 -8
  13. package/dist/cli.js +346 -921
  14. package/dist/{doctor-kg0yq1wf.js → doctor-mx6jf435.js} +9 -9
  15. package/dist/{fix-q8er8egx.js → fix-9fmy6p2x.js} +7 -7
  16. package/dist/{harness-github-actions-ver6cprq.js → harness-github-actions-c826bfxs.js} +6 -6
  17. package/dist/{harness-v9s0k9s7.js → harness-xvg6ws6x.js} +6 -6
  18. package/dist/{index-7zqa7t5c.js → index-6qqmjqb2.js} +11 -11
  19. package/dist/{production-intelligence-k36jsvqx.js → production-intelligence-dbe9dmc5.js} +3 -3
  20. package/dist/{profile-commands-88sdwzbg.js → profile-commands-kmmd9y86.js} +3 -3
  21. package/dist/prompt-source-mcp.js +6 -6
  22. package/dist/{prompts-2r756vtd.js → prompts-1tkhrxkq.js} +7 -7
  23. package/dist/{provision-n3r7yway.js → provision-wzttap58.js} +4 -4
  24. package/dist/{registry-5v63ga01.js → registry-atqyb5fa.js} +4 -4
  25. package/dist/{skills-fed17et3.js → skills-d35nnm66.js} +6 -6
  26. package/dist/{sync-r4tncne4.js → sync-n2psdffz.js} +8 -8
  27. package/package.json +1 -1
  28. package/skills/integration/index.json +2 -2
  29. package/dist/cli-kg0kz05e.js +0 -496
package/dist/cli.js CHANGED
@@ -5,27 +5,55 @@ import {
5
5
  import {
6
6
  createCommandContext,
7
7
  parseBooleanFlagValue
8
- } from "./cli-5hq827jt.js";
8
+ } from "./cli-569hj0bj.js";
9
9
  import {
10
+ AuditSchema,
11
+ COMMAND_FLAG_SPECS,
12
+ DETECTION_VERDICTS,
13
+ DetectionReviewSchema,
14
+ FALSE_POSITIVE_KINDS,
15
+ FEEDBACK_USAGE,
16
+ FalsePositiveSchema,
17
+ PROBLEM_FEEDBACK_ACTIONS,
18
+ ProblemFeedbackSchema,
19
+ ProblemImpactSchema,
20
+ ProblemLinearFileSchema,
21
+ ProblemsRemainderSchema,
10
22
  SIGNALS_MANAGEMENT_SUBCOMMANDS,
23
+ SIGNAL_LABELS,
24
+ SignalLabelSchema,
25
+ StepScoresSchema,
26
+ UUID_RE,
11
27
  assertFlags,
12
28
  assertPositionals,
29
+ buildFeedbackRequest,
30
+ closestMatches,
31
+ describeSpecFlags,
32
+ flagSpecFor,
33
+ isFeedbackRefFlag,
34
+ kebabFlag,
35
+ manifestFlagFields,
36
+ renderFlagHelp,
13
37
  runProblemReopenCommand,
14
38
  runSignalsManagementCommand,
15
39
  runUserCommand,
16
40
  runUsersCommand,
41
+ schemaShape,
42
+ specFlagKeys,
43
+ specFlagNames,
44
+ subcommandHelpFlags,
17
45
  unknownSignalsSubcommandError
18
- } from "./cli-kg0kz05e.js";
46
+ } from "./cli-cehskjde.js";
19
47
  import {
20
48
  ApiError,
21
49
  callControlAPI,
22
50
  callDataAPI
23
- } from "./cli-c8p69n55.js";
51
+ } from "./cli-rqk6f6n6.js";
24
52
  import {
25
53
  apiKeyHeaders,
26
54
  isPlatformApiKey,
27
55
  setPlatformTenantOverride
28
- } from "./cli-eazeanvt.js";
56
+ } from "./cli-7ea02wca.js";
29
57
  import {
30
58
  AGENT_ERROR_CODES,
31
59
  BATCH_CONCURRENCY,
@@ -50,6 +78,7 @@ import {
50
78
  asNumber,
51
79
  asRecord,
52
80
  asString,
81
+ attachInputDetails,
53
82
  collectBatchTargets,
54
83
  compactProblemDossier,
55
84
  contextTarget,
@@ -79,434 +108,14 @@ import {
79
108
  withFrustrationAnchors,
80
109
  withToolFailureAnchors,
81
110
  withoutDetectionWindows
82
- } from "./cli-3ezzeqcy.js";
111
+ } from "./cli-5ke3xe6y.js";
83
112
  import {
84
113
  __require
85
114
  } from "./cli-0v6na3yp.js";
86
115
 
87
116
  // src/cli.ts
88
117
  import { randomUUID as randomUUID2 } from "node:crypto";
89
- import { z as z2 } from "zod";
90
-
91
- // src/schemas.ts
92
118
  import { z } from "zod";
93
- var boolFlag = () => z.preprocess((val) => {
94
- const text = String(val).toLowerCase();
95
- if (["true", "1", "yes", "on"].includes(text))
96
- return true;
97
- if (["false", "0", "no", "off"].includes(text))
98
- return false;
99
- return val;
100
- }, z.boolean()).optional();
101
- var DAYS_BACK_MESSAGE = "must be a whole number from 1 to 90 (e.g. --days-back=7)";
102
- var daysBackFlag = (fallback) => {
103
- const days = z.number({ invalid_type_error: DAYS_BACK_MESSAGE }).int(DAYS_BACK_MESSAGE).min(1, DAYS_BACK_MESSAGE).max(90, DAYS_BACK_MESSAGE);
104
- return fallback === undefined ? days.optional() : days.default(fallback).optional();
105
- };
106
- var OverviewSchema = z.object({
107
- days_back: daysBackFlag(7)
108
- });
109
- var ClustersSchema = z.object({
110
- parent_id: z.string().optional(),
111
- time_range: z.enum(["all", "1h", "3d", "7d", "24h", "30d", "90d"]).default("all").optional(),
112
- search: z.string().min(2).max(200).optional(),
113
- node_id: z.string().min(1).max(512).optional(),
114
- mode: z.enum(["fuzzy", "semantic", "hybrid"]).optional(),
115
- limit: z.number().min(1).max(50).optional()
116
- });
117
- var ClusterConversationsSchema = z.object({
118
- node_id: z.string(),
119
- limit: z.number().min(1).max(100).default(10).optional(),
120
- offset: z.number().min(0).default(0).optional()
121
- });
122
- var ConversationsSchema = z.object({
123
- search: z.string().optional(),
124
- cluster_id: z.string().optional(),
125
- user_id: z.string().optional(),
126
- time_range: z.enum(["all", "1h", "3d", "24h", "7d", "30d", "90d"]).default("all").optional(),
127
- environment: z.enum(["all", "development", "staging", "production"]).default("all").optional(),
128
- world_state: z.string().max(200).optional(),
129
- outcome: z.enum(["any", "positive", "negative"]).default("any").optional(),
130
- include_world_state: boolFlag(),
131
- sort: z.enum(["recent", "longest", "slowest"]).optional(),
132
- limit: z.number().min(1).max(100).default(20).optional(),
133
- offset: z.number().min(0).default(0).optional()
134
- });
135
- var WorldStateSchema = z.object({
136
- conversation_id: z.string(),
137
- summary_only: boolFlag(),
138
- event_limit: z.number().min(1).max(5000).default(2000).optional(),
139
- snapshot: boolFlag(),
140
- msg_index: z.number().min(0).max(1e5).optional(),
141
- block_index: z.number().min(0).max(1e5).optional(),
142
- segment_index: z.number().min(0).max(65535).optional(),
143
- replay: boolFlag(),
144
- format: z.enum(["frames", "fold-inputs"]).optional(),
145
- message_count: z.number().min(1).max(1e6).optional()
146
- });
147
- var ContextSchema = z.object({
148
- conversation_id: z.string().min(1),
149
- msg_index: z.number().int().min(0).optional(),
150
- window: z.number().int().min(0).optional(),
151
- metadata_only: boolFlag(),
152
- all: boolFlag(),
153
- from: z.number().int().min(0).optional(),
154
- max_messages: z.number().int().min(1).max(5000).optional(),
155
- ids_from: z.string().min(1).optional()
156
- });
157
- var FrustrationsSchema = z.object({
158
- days_back: daysBackFlag(7),
159
- limit: z.number().min(1).max(20).default(10).optional(),
160
- offset: z.number().min(0).default(0).optional(),
161
- include_window: boolFlag(),
162
- window: z.number().min(1).max(5).default(1).optional(),
163
- user_id: z.string().min(1).max(256).optional(),
164
- conversation_id: z.string().min(1).max(256).optional()
165
- });
166
- var ToolFailuresSchema = z.object({
167
- days_back: daysBackFlag(7)
168
- });
169
- var ProblemsSchema = z.object({
170
- days_back: daysBackFlag(30),
171
- limit: z.number().min(1).max(25).default(25).optional()
172
- });
173
- var REMAINDER_FAMILIES = [
174
- "tool_failure",
175
- "emotion",
176
- "laziness",
177
- "hallucination",
178
- "prm_dip",
179
- "custom_signal",
180
- "conversation_reader"
181
- ];
182
- var ProblemsRemainderSchema = z.object({
183
- days_back: daysBackFlag(30),
184
- limit: z.number().min(1).max(25).default(25).optional(),
185
- family: z.enum(REMAINDER_FAMILIES).optional(),
186
- cursor: z.string().min(1).max(4096).optional()
187
- });
188
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
189
- var ProblemImpactSchema = z.object({
190
- node_id: z.string().min(1).max(256).optional(),
191
- problem_id: z.string().regex(UUID_RE).optional(),
192
- run_id: z.string().min(1).max(256).optional(),
193
- days_back: z.union([z.literal("all"), z.coerce.number().refine((n) => [1, 3, 7, 30, 90].includes(n), "Use all, 1, 3, 7, 30, or 90 days")]).default(7),
194
- mode: z.enum(["metrics", "trend", "evidence", "catalog", "overview", "affected-use-cases", "trace-use-cases"]).default("metrics"),
195
- to: z.string().datetime({ precision: 3 }).optional(),
196
- cursor: z.string().min(1).optional(),
197
- conversation_ids: z.string().transform((value, ctx) => {
198
- try {
199
- return z.array(z.string().min(1).max(512)).min(1).max(25).parse(JSON.parse(value));
200
- } catch {
201
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Use a JSON array of 1–25 conversation IDs" });
202
- return z.NEVER;
203
- }
204
- }).optional()
205
- }).refine((p) => p.mode !== "trace-use-cases" || p.problem_id && p.conversation_ids, {
206
- message: "Trace use cases require --problem-id and --conversation-ids"
207
- }).refine((p) => p.node_id || p.problem_id || ["catalog", "overview"].includes(p.mode), {
208
- message: "Select --node-id or --problem-id, or use --mode=catalog/overview"
209
- }).refine((p) => !p.cursor || p.mode === "evidence" && p.to && p.run_id, {
210
- message: "An evidence cursor requires --mode=evidence, --to, and --run-id from the previous response"
211
- });
212
- var PROBLEM_FAMILIES = REMAINDER_FAMILIES;
213
- var PROBLEM_DOORS = ["rubric_match", "local_causal_chain"];
214
- var ProblemSchema = z.object({
215
- id: z.string().min(1),
216
- evidence: boolFlag(),
217
- reports: boolFlag(),
218
- traces: boolFlag(),
219
- conversations: boolFlag(),
220
- feedback: boolFlag(),
221
- full: boolFlag(),
222
- limit: z.number().min(1).max(50).optional(),
223
- cursor: z.string().optional(),
224
- family: z.enum(PROBLEM_FAMILIES).optional(),
225
- door: z.enum(PROBLEM_DOORS).optional()
226
- });
227
- var PROBLEM_FEEDBACK_ACTIONS = [
228
- "mark_fixed",
229
- "dismiss",
230
- "flag_attribution",
231
- "rename"
232
- ];
233
- var ProblemFeedbackSchema = z.object({
234
- id: z.string().min(1),
235
- action: z.enum(PROBLEM_FEEDBACK_ACTIONS),
236
- reason: z.string().max(2000).optional(),
237
- attribution_id: z.string().max(64).optional(),
238
- new_name: z.string().max(255).optional(),
239
- actor: z.string().max(255).optional()
240
- });
241
- var ProblemLinearFileSchema = z.object({
242
- id: z.string().min(1),
243
- issue: z.string().max(2048).optional(),
244
- team_id: z.string().max(255).optional(),
245
- title: z.string().optional(),
246
- priority: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).max(4).optional())
247
- });
248
- var SignalSchema = z.object({
249
- id: z.string().min(1).max(255),
250
- detections: boolFlag(),
251
- days_back: daysBackFlag(),
252
- limit: z.number().min(1).max(20).optional(),
253
- offset: z.number().min(0).max(1e4).optional()
254
- });
255
- var SIGNAL_LABELS = ["fits", "does_not_fit"];
256
- var SignalLabelSchema = z.object({
257
- id: z.string().min(1).max(255),
258
- conversation_id: z.string().min(1).max(255),
259
- label: z.enum(SIGNAL_LABELS),
260
- note: z.string().max(2000).optional(),
261
- msg_index: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).optional()),
262
- msg_dedup_token: z.string().min(1).max(200).optional()
263
- });
264
- var DETECTION_VERDICTS = ["correct", "false_positive", "clear"];
265
- var DetectionReviewSchema = z.object({
266
- id: z.string().regex(UUID_RE, "Problem id must be a canonical UUID"),
267
- conversation_id: z.string().min(1).max(255),
268
- attribution_id: z.string().regex(UUID_RE, "Attribution id must be a UUID"),
269
- verdict: z.enum(DETECTION_VERDICTS),
270
- note: z.string().max(2000).optional()
271
- });
272
- var FALSE_POSITIVE_KINDS = ["problem", "problem-detection", "quote", "tool", "laziness", "hallucination", "custom-signal"];
273
- var FalsePositiveSchema = z.object({
274
- kind: z.enum(FALSE_POSITIVE_KINDS),
275
- target: z.string().min(1).max(255),
276
- undo: z.boolean(),
277
- reason: z.string().max(2000).optional(),
278
- conversation_id: z.string().min(1).max(255).optional(),
279
- attribution_id: z.string().regex(UUID_RE, "Attribution id must be a UUID").optional(),
280
- family: z.string().regex(/^[a-z_]{1,64}$/, "Family must be a lowercase emotion family").optional(),
281
- turn: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).optional()),
282
- quote: z.string().min(1).max(4000).optional(),
283
- tool: z.string().min(1).max(255).optional(),
284
- tool_use_id: z.string().min(1).max(255).optional(),
285
- msg_index: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).optional()),
286
- msg_dedup_token: z.string().min(1).max(200).optional()
287
- }).superRefine((v, ctx) => {
288
- const need = (ok, message) => {
289
- if (!ok)
290
- ctx.addIssue({ code: z.ZodIssueCode.custom, message });
291
- };
292
- if (v.kind === "problem") {
293
- need(UUID_RE.test(v.target), "Problem id must be a canonical UUID");
294
- need(!v.undo, "A problem dismissal cannot be undone from the CLI");
295
- }
296
- if (v.kind === "problem-detection") {
297
- need(UUID_RE.test(v.target), "Problem id must be a canonical UUID");
298
- need(v.conversation_id, "--conversation-id is required for problem-detection");
299
- need(v.attribution_id, "--attribution-id is required for problem-detection");
300
- }
301
- if (v.kind === "quote") {
302
- need(v.family && v.turn !== undefined && v.quote, "--family, --turn and --quote are required for quote (copy them from moda emotions)");
303
- }
304
- if (v.kind === "tool") {
305
- need(v.tool, "--tool is required for tool (the failing tool name)");
306
- need(v.tool_use_id || v.msg_index !== undefined, "--tool-use-id or --msg-index is required for tool (from moda tool-failure-detail)");
307
- }
308
- if (v.kind === "custom-signal") {
309
- need(v.conversation_id, "--conversation-id is required for custom-signal");
310
- }
311
- });
312
- var EMOTION_FAMILIES = [
313
- "frustration",
314
- "disapproval",
315
- "sadness",
316
- "confusion",
317
- "anxiety",
318
- "trust",
319
- "positive"
320
- ];
321
- var EmotionsSchema = z.object({
322
- days_back: daysBackFlag(7),
323
- limit: z.number().min(1).max(20).default(10).optional(),
324
- offset: z.number().min(0).max(1e4).optional(),
325
- family: z.enum(EMOTION_FAMILIES).optional(),
326
- user_id: z.string().min(1).max(256).optional(),
327
- conversation_id: z.string().min(1).max(256).optional(),
328
- include_window: boolFlag()
329
- });
330
- var HallucinationsSchema = z.object({
331
- days_back: daysBackFlag(7),
332
- limit: z.number().min(1).max(20).default(10).optional(),
333
- offset: z.number().min(0).max(1e4).optional(),
334
- conversation_id: z.string().max(200).optional(),
335
- kind: z.enum(["contradicted", "verified"]).optional()
336
- });
337
- var LAZINESS_FAMILIES = [
338
- "omission_comment",
339
- "omission_phrase",
340
- "stub_body",
341
- "refusal_prefix",
342
- "deflection",
343
- "data_quality_truncation",
344
- "promise_no_delivery",
345
- "capability_refusal_here",
346
- "capability_refusal_verb",
347
- "error_admission",
348
- "irreversibility",
349
- "stall_recheck",
350
- "diy_handoff",
351
- "tool_selection",
352
- "completion",
353
- "code_artifact",
354
- "repeated_tool_call",
355
- "target_overshoot",
356
- "data_regression"
357
- ];
358
- var LazinessSchema = z.object({
359
- days_back: daysBackFlag(7),
360
- limit: z.number().min(1).max(50).default(10).optional(),
361
- offset: z.number().min(0).max(1e4).optional(),
362
- conversation_id: z.string().max(200).optional(),
363
- family: z.enum(LAZINESS_FAMILIES).optional()
364
- });
365
- var StepScoresSchema = z.object({
366
- conversation_id: z.string().min(1)
367
- });
368
- var TAIL_SIGNALS = ["traces", "conversations", "emotions", "all"];
369
- var TailSchema = z.object({
370
- interval: z.number().min(5).max(3600).default(15).optional(),
371
- signal: z.enum(TAIL_SIGNALS).default("traces").optional(),
372
- once: boolFlag(),
373
- limit: z.number().min(1).max(50).default(20).optional(),
374
- max_events: z.number().min(1).max(1e5).optional(),
375
- full_scan: boolFlag()
376
- });
377
- var ToolFailureDetailSchema = z.object({
378
- tool_name: z.string(),
379
- subtype: z.string().optional(),
380
- days_back: daysBackFlag(7),
381
- limit: z.number().min(1).max(20).default(5).optional(),
382
- offset: z.number().min(0).default(0).optional(),
383
- include_window: boolFlag(),
384
- compact: boolFlag(),
385
- window: z.number().min(1).max(5).default(1).optional()
386
- });
387
- var AuditSchema = z.object({
388
- id: z.string().min(1),
389
- kind: z.enum(["auto", "trace", "conversation"]).default("auto").optional(),
390
- include_raw: boolFlag(),
391
- include_bodies: boolFlag(),
392
- limit: z.number().min(1).max(1000).default(200).optional(),
393
- cursor: z.string().min(1).max(512).optional(),
394
- ids_from: z.string().min(1).optional()
395
- });
396
- var TIME_RANGES = ["all", "1h", "3d", "7d", "24h", "30d", "90d"];
397
- var SEARCH_MODES = ["keyword", "semantic", "hybrid"];
398
- var SearchSchema = z.object({
399
- q: z.string().min(1).max(500),
400
- mode: z.enum(SEARCH_MODES).default("hybrid").optional(),
401
- user_id: z.string().optional(),
402
- conversation_id: z.string().min(1).max(256).optional(),
403
- time_range: z.enum(TIME_RANGES).default("all").optional(),
404
- limit: z.number().min(1).max(100).default(20).optional(),
405
- include_tool_io: boolFlag(),
406
- offset: z.number().min(0).max(1e4).optional()
407
- });
408
-
409
- // ../../packages/database/src/agent-feedback.ts
410
- var FEEDBACK_CATEGORIES = [
411
- "bad_cluster_label",
412
- "mismatched_frustration",
413
- "missing_data",
414
- "noisy_data",
415
- "wrong_tool_failure",
416
- "incorrect_loop",
417
- "api_quirk",
418
- "false_positive_attribution",
419
- "misrouted_fix",
420
- "harness_bug",
421
- "other"
422
- ];
423
- var FEEDBACK_SEVERITIES = ["info", "low", "medium", "high"];
424
- var DEFAULT_FEEDBACK_CATEGORY = "other";
425
- var RAW_FEEDBACK_CATEGORY_MAX = 64;
426
- function isFeedbackCategory(value) {
427
- return typeof value === "string" && FEEDBACK_CATEGORIES.includes(value);
428
- }
429
- function normalizeFeedbackCategory(value) {
430
- if (value === undefined || value === null || value === "")
431
- return { category: DEFAULT_FEEDBACK_CATEGORY };
432
- if (isFeedbackCategory(value))
433
- return { category: value };
434
- const raw = String(value).trim().slice(0, RAW_FEEDBACK_CATEGORY_MAX);
435
- return raw ? { category: DEFAULT_FEEDBACK_CATEGORY, raw_category: raw } : { category: DEFAULT_FEEDBACK_CATEGORY };
436
- }
437
-
438
- // src/feedback.ts
439
- var FEEDBACK_FLAGS = ["category", "severity", "note", "cluster-id", "conversation-id", "run-id", "tool-name"];
440
- var FEEDBACK_USAGE = `Usage: moda feedback "<note>" [--category=${FEEDBACK_CATEGORIES.join("|")}] ` + `[--severity=${FEEDBACK_SEVERITIES.join("|")}] [--conversation-id=ID] [--cluster-id=ID] ` + "[--tool-name=NAME] [--run-id=ID] [--<name>-id=ID]";
441
- var NOTE_MAX = 4000;
442
- var REF_VALUE_MAX = 256;
443
- var REF_FLAG_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*-(?:id|ids|index|token)$/;
444
- var REF_FLAG_WORDS = new Set(["turn", "tool", "family", "kind"]);
445
- function isFeedbackRefFlag(flag) {
446
- return REF_FLAG_PATTERN.test(flag) || REF_FLAG_WORDS.has(flag);
447
- }
448
- function feedbackCategoryHelp(indent = 35, width = 100) {
449
- const lines = [];
450
- let line = "";
451
- FEEDBACK_CATEGORIES.forEach((category, index) => {
452
- const piece = index < FEEDBACK_CATEGORIES.length - 1 ? `${category}|` : `${category} (default other)`;
453
- if (line && indent + line.length + piece.length > width) {
454
- lines.push(line);
455
- line = "";
456
- }
457
- line += piece;
458
- });
459
- lines.push(line);
460
- return lines.join(`
461
- ${" ".repeat(indent)}`);
462
- }
463
- function buildFeedbackRequest(positionals, flags, bareFlags) {
464
- const isBare = (flag) => bareFlags ? bareFlags.includes(flag) : flags[flag] === "true";
465
- const flagNote = flags.note !== undefined && !isBare("note") ? flags.note.trim() : "";
466
- const note = [positionals.join(" ").trim(), flagNote].filter(Boolean).join(`
467
- `);
468
- if (note === "")
469
- throw new CliInputError("<note> is required", FEEDBACK_USAGE);
470
- if (note.length > NOTE_MAX) {
471
- throw new CliInputError(`<note> is ${note.length} characters; the limit is ${NOTE_MAX}.`, FEEDBACK_USAGE);
472
- }
473
- const severity = flags.severity ?? "low";
474
- if (!FEEDBACK_SEVERITIES.includes(severity)) {
475
- throw new CliInputError(`Invalid --severity '${severity}'. Valid severities: ${FEEDBACK_SEVERITIES.join(", ")}.`, FEEDBACK_USAGE);
476
- }
477
- const refs = {};
478
- for (const [flag, value] of Object.entries(flags)) {
479
- if (flag === "category" || flag === "severity" || flag === "note")
480
- continue;
481
- if (!FEEDBACK_FLAGS.includes(flag) && !isFeedbackRefFlag(flag))
482
- continue;
483
- const trimmed = value.trim();
484
- if (value === "true" || trimmed === "") {
485
- throw new CliInputError(`--${flag} needs a value, e.g. --${flag}=<id>.`, FEEDBACK_USAGE);
486
- }
487
- if (trimmed.length > REF_VALUE_MAX) {
488
- throw new CliInputError(`--${flag} is ${trimmed.length} characters; the limit is ${REF_VALUE_MAX}.`, FEEDBACK_USAGE);
489
- }
490
- refs[flag.replace(/-/g, "_")] = trimmed;
491
- }
492
- const warnings = [];
493
- const { category, raw_category: rawCategory } = normalizeFeedbackCategory(flags.category);
494
- if (rawCategory !== undefined) {
495
- refs.raw_category = rawCategory;
496
- warnings.push(`Unknown category '${rawCategory}': sent as 'other' with refs.raw_category. ` + `Valid categories: ${FEEDBACK_CATEGORIES.join(", ")}.`);
497
- }
498
- const hint = dedicatedCommandHint(category, rawCategory);
499
- if (hint)
500
- warnings.push(hint);
501
- return { category, severity, note, refs, warnings };
502
- }
503
- var MISROUTE_CATEGORIES = new Set(["false_positive_attribution", "misrouted_fix"]);
504
- var MISROUTE_WORDS = /attribut|misrout|false[\s_-]?positive|wrong[\s_-]?(?:problem|fix)/i;
505
- function dedicatedCommandHint(category, rawCategory) {
506
- if (!MISROUTE_CATEGORIES.has(category) && !(rawCategory && MISROUTE_WORDS.test(rawCategory)))
507
- return;
508
- return "Feedback is read by the Moda team but does not change the problem. To act on it directly, use " + "`moda problem-feedback <problem_id> --action=flag_attribution --attribution-id=<uuid> --reason=TEXT` (a trace wrongly " + "attributed to a problem), `moda false-positive <kind> <target> --reason=TEXT` (a detection that should not " + "have fired), or `moda fix dismiss <fix_id> --reason=TEXT` (a fix aimed at the wrong problem).";
509
- }
510
119
 
511
120
  // src/replays.ts
512
121
  var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -706,7 +315,7 @@ var SEARCH_SURFACE_BY_COMMAND = {
706
315
  "world-state": "world_state",
707
316
  context: "context"
708
317
  };
709
- var SEARCH_MODES2 = ["keyword", "semantic", "hybrid"];
318
+ var SEARCH_MODES = ["keyword", "semantic", "hybrid"];
710
319
  function termCount(query2) {
711
320
  return query2.trim().split(/\s+/).filter(Boolean).length;
712
321
  }
@@ -738,7 +347,7 @@ function buildSearchAdoptionTelemetry(input) {
738
347
  }
739
348
  if (command === "search") {
740
349
  const requested = (flags.mode ?? "").toLowerCase();
741
- adoption.search_mode_requested = SEARCH_MODES2.includes(requested) ? requested : "hybrid";
350
+ adoption.search_mode_requested = SEARCH_MODES.includes(requested) ? requested : "hybrid";
742
351
  }
743
352
  if (command === "context") {
744
353
  adoption.used_msg_index = flags["msg-index"] !== undefined || flags["message-index"] !== undefined ? 1 : 0;
@@ -1591,12 +1200,7 @@ var PROBLEMS_SUBCOMMAND_HELP = [
1591
1200
  name: "remainder",
1592
1201
  description: "Signals no Problem explains yet, grouped by family (read-only)",
1593
1202
  usage: "moda problems remainder [--family=<family>] [--days-back=N] [--limit=N] [--cursor=<token>]",
1594
- flags: [
1595
- { name: "--family=<family>", description: "One of tool_failure, emotion, laziness, hallucination, prm_dip, custom_signal, conversation_reader (frustration is under emotion)." },
1596
- { name: "--days-back=<n>", description: "Window in days, 1-90 (default 30)." },
1597
- { name: "--limit=<n>", description: "Groups per page, 1-25 (default 25)." },
1598
- { name: "--cursor=<token>", description: "The next_cursor from the previous page, verbatim." }
1599
- ],
1203
+ flags: subcommandHelpFlags(COMMAND_FLAG_SPECS.problems.subcommands.remainder),
1600
1204
  examples: ["moda problems remainder", "moda problems remainder --family=emotion --days-back=7"]
1601
1205
  }
1602
1206
  ];
@@ -1806,6 +1410,23 @@ var agentErrorSchema = {
1806
1410
  message: { type: "string" },
1807
1411
  cause: { type: "string" },
1808
1412
  suggested_commands: { type: "array", items: { type: "string" } },
1413
+ field: { type: "string", description: "input_error: the rejected flag (e.g. --days-back) or argument (e.g. <command>)." },
1414
+ allowed: {
1415
+ type: "array",
1416
+ items: { type: "string" },
1417
+ description: "input_error: accepted values for field (enum members, valid flag names, or command names)."
1418
+ },
1419
+ range: {
1420
+ type: "object",
1421
+ additionalProperties: false,
1422
+ description: "input_error: accepted numeric range for field.",
1423
+ properties: { min: { type: "number" }, max: { type: "number" } }
1424
+ },
1425
+ did_you_mean: {
1426
+ type: "array",
1427
+ items: { type: "string" },
1428
+ description: "input_error: closest valid spellings of the rejected flag or command, best first."
1429
+ },
1809
1430
  input_request: agentInputRequestSchema,
1810
1431
  auth: agentAuthSchema,
1811
1432
  blocking: { type: "boolean" }
@@ -2158,7 +1779,8 @@ function buildManifest(commands) {
2158
1779
  auth: command.auth,
2159
1780
  ...command.authNote ? { auth_note: command.authNote } : {},
2160
1781
  mutability: command.mutability,
2161
- exit_codes: exitCodesForCommand(command.name)
1782
+ exit_codes: exitCodesForCommand(command.name),
1783
+ ...commandFlagFields(command)
2162
1784
  })),
2163
1785
  concepts: [
2164
1786
  { term: "tenant", meaning: "A Moda organization/workspace that owns data, prompts, skills, and API keys." },
@@ -2190,6 +1812,29 @@ function renderManifestHuman(manifest) {
2190
1812
  ].join(`
2191
1813
  `);
2192
1814
  }
1815
+ function commandFlagFields(command) {
1816
+ const spec = flagSpecFor(command.name);
1817
+ if (spec)
1818
+ return manifestFlagFields(spec);
1819
+ if (command.documentedFlags?.length) {
1820
+ return { flags: command.documentedFlags.map(documentedFlag) };
1821
+ }
1822
+ return {
1823
+ flags_help: command.subcommands?.length ? `moda ${command.name} <subcommand> --help` : `moda ${command.name} --help`
1824
+ };
1825
+ }
1826
+ function documentedFlag(flag) {
1827
+ const [name, value] = flag.name.split("=", 2);
1828
+ const values = value?.split("|");
1829
+ const type = value === undefined ? "boolean" : values && values.length > 1 && values.every((entry) => /^[a-z0-9_-]+$/.test(entry)) ? "enum" : "string";
1830
+ return {
1831
+ name,
1832
+ type,
1833
+ ...type === "enum" ? { enum: values } : {},
1834
+ description: flag.description,
1835
+ required: false
1836
+ };
1837
+ }
2193
1838
  function event(name, when, terminal, deprecated = false) {
2194
1839
  return { name, event_version: 1, when, terminal, ...deprecated ? { deprecated: true } : {} };
2195
1840
  }
@@ -2205,46 +1850,46 @@ function exitCodesForCommand(command) {
2205
1850
  import { fileURLToPath } from "url";
2206
1851
  import { realpathSync } from "fs";
2207
1852
  async function runPromptsCommand(...args) {
2208
- return (await import("./prompts-2r756vtd.js")).runPromptsCommand(...args);
1853
+ return (await import("./prompts-1tkhrxkq.js")).runPromptsCommand(...args);
2209
1854
  }
2210
1855
  async function runSkillsCommand(...args) {
2211
- return (await import("./skills-fed17et3.js")).runSkillsCommand(...args);
1856
+ return (await import("./skills-d35nnm66.js")).runSkillsCommand(...args);
2212
1857
  }
2213
1858
  async function runFixCommand(...args) {
2214
- return (await import("./fix-q8er8egx.js")).runFixCommand(...args);
1859
+ return (await import("./fix-9fmy6p2x.js")).runFixCommand(...args);
2215
1860
  }
2216
1861
  async function runFixesCommand(...args) {
2217
- return (await import("./fix-q8er8egx.js")).runFixesCommand(...args);
1862
+ return (await import("./fix-9fmy6p2x.js")).runFixesCommand(...args);
2218
1863
  }
2219
1864
  async function runHarnessCommand(...args) {
2220
- return (await import("./harness-v9s0k9s7.js")).runHarnessCommand(...args);
1865
+ return (await import("./harness-xvg6ws6x.js")).runHarnessCommand(...args);
2221
1866
  }
2222
1867
  async function runSyncCommand(...args) {
2223
- return (await import("./sync-r4tncne4.js")).runSyncCommand(...args);
1868
+ return (await import("./sync-n2psdffz.js")).runSyncCommand(...args);
2224
1869
  }
2225
1870
  async function runRegistryCommand(...args) {
2226
- return (await import("./registry-5v63ga01.js")).runRegistryCommand(...args);
1871
+ return (await import("./registry-atqyb5fa.js")).runRegistryCommand(...args);
2227
1872
  }
2228
1873
  async function runDoctorCommand(...args) {
2229
- return (await import("./doctor-kg0yq1wf.js")).runDoctorCommand(...args);
1874
+ return (await import("./doctor-mx6jf435.js")).runDoctorCommand(...args);
2230
1875
  }
2231
1876
  async function runStatusCommand(...args) {
2232
- return (await import("./doctor-kg0yq1wf.js")).runStatusCommand(...args);
1877
+ return (await import("./doctor-mx6jf435.js")).runStatusCommand(...args);
2233
1878
  }
2234
1879
  async function runAuthCommand(...args) {
2235
- return (await import("./profile-commands-88sdwzbg.js")).runAuthCommand(...args);
1880
+ return (await import("./profile-commands-kmmd9y86.js")).runAuthCommand(...args);
2236
1881
  }
2237
1882
  async function runConfigCommand(...args) {
2238
- return (await import("./profile-commands-88sdwzbg.js")).runConfigCommand(...args);
1883
+ return (await import("./profile-commands-kmmd9y86.js")).runConfigCommand(...args);
2239
1884
  }
2240
1885
  async function runProfilesCommand(...args) {
2241
- return (await import("./profile-commands-88sdwzbg.js")).runProfilesCommand(...args);
1886
+ return (await import("./profile-commands-kmmd9y86.js")).runProfilesCommand(...args);
2242
1887
  }
2243
1888
  async function runAgentCommand(...args) {
2244
- return (await import("./agent-cha3kg9d.js")).runAgentCommand(...args);
1889
+ return (await import("./agent-mj622k8s.js")).runAgentCommand(...args);
2245
1890
  }
2246
1891
  async function runProductionCommand(...args) {
2247
- return (await import("./production-intelligence-k36jsvqx.js")).runProductionCommand(...args);
1892
+ return (await import("./production-intelligence-dbe9dmc5.js")).runProductionCommand(...args);
2248
1893
  }
2249
1894
  function parseArgs(argv) {
2250
1895
  const args = argv.slice(2);
@@ -2449,401 +2094,101 @@ function buildResumeCommand(command, flags) {
2449
2094
  function printHelp() {
2450
2095
  console.log(`Usage: moda <command> [options]
2451
2096
 
2452
- Commands:
2453
- init Set up Moda in your project
2454
- provision Headless tenant + API key provisioning (JSON credentials on stdout)
2455
- status Show concise local Moda setup status
2456
- manifest Describe the CLI machine protocol and commands
2457
- doctor Diagnose local Moda setup and data flow
2458
- auth login Authenticate with Moda (browser)
2459
- auth login --api-key Non-interactive: validate MODA_API_KEY (or --api-key=<key>) and save it
2460
- auth status Show auth state for both credentials (exit 4 when neither is usable); --online probes the API
2461
- auth token Print the raw bearer token for $(moda auth token)
2462
- auth api-key Print the saved API key for $(moda auth api-key)
2463
- auth logout Clear cached Moda auth
2464
- auth whoami Show the authenticated Moda identity (session or API key)
2465
- profiles list List local Moda profiles
2466
- profiles use <name> Switch active Moda profile
2467
- profiles create <name> Create or update a local Moda profile
2468
- profiles doctor [name] Validate a local Moda profile
2469
- config show Show resolved Moda config
2470
- harness analyze Produce a cited structured harness report
2471
- harness pull Fetch a server-side analyze run (status, or result when done)
2472
- harness validate-report Validate .moda/harness-report.json citations
2473
- harness approve Approve a validated harness report for sync
2474
- harness scan Discover local runtime agents and write .moda/harness.json
2475
- harness candidates Static (no-LLM) harness candidate pre-pass with file:line citations
2476
- harness sync Sync the local harness graph to Moda Cloud
2477
- harness delete <id-or-key> Permanently delete a synced harness from Moda Cloud
2478
- harness list|show|versions|diff List synced harnesses, show one, its versions, or a version diff
2479
- harness register [name] Bundle this repo for Replay Environments and upload it (--dry-run to review)
2480
- harness registration list|status List registrations, or show one with what Moda still needs
2481
- harness agents List detected runtime agents and families
2482
- harness explain Explain the discovered harness graph
2483
- agent context Emit local Moda context for coding agents
2484
- agent next-action Emit prioritized next commands for agents
2485
- agent evidence <ref> Expand one evidence reference
2097
+ Start here (goal -> command):
2098
+ find something in traces moda search "<query>" (whole traces: moda traces --search=TEXT)
2099
+ read one trace moda context <conversation_id> (whole trace: --all)
2100
+ what is broken moda overview, then moda problems
2101
+ tool errors moda tool-failures, then moda tool-failure-detail <tool_name>
2102
+ user emotion and frustration moda emotions
2103
+ raw spans for one trace moda audit <conversation_id|trace_id>
2104
+ every flag of a command moda <command> --help (all commands and flags: moda manifest --json)
2105
+
2106
+ Production data:
2107
+ overview Harness health briefing with production signals
2486
2108
  investigate Rank production issues (tool failures, frustrations, top Problems)
2487
2109
  failures Tool failures only, ranked (no frustrations or Problems)
2488
- ask "question" Ask Moda a production/harness question
2489
- sync Sync the local harness graph to Moda Cloud
2490
- sync harness Sync the local harness graph to Moda Cloud
2491
- sync prompts Sync prompt versions to Moda Cloud
2492
- doctor --json Emit structured diagnostic checks
2493
- status --json Emit concise setup state
2494
- manifest --json Emit the CLI machine protocol manifest
2495
- overview Harness health briefing with production signals
2496
- clusters Browse topic cluster hierarchy
2497
- cluster-traces <node_id> List traces in a cluster
2498
- traces Search and filter traces (agent runs)
2499
- traces --sort=longest Sort traces: recent (default), longest, slowest
2110
+ ask "<question>" Ask Moda a production question (one paid agent run)
2500
2111
  search "<query>" Search trace messages (keyword/semantic/hybrid)
2501
- world-state <conversation_id> Get a trace's world state (slots/threads/events)
2502
- context <conversation_id> Get windowed trace context (--metadata-only: summary + counts only)
2503
- context <conversation_id> --all Whole transcript in order (first 500; --from=N --max-messages=N to continue)
2112
+ traces Search and filter traces (agent runs)
2113
+ context <conversation_id> Messages around one turn, or the whole trace with --all
2504
2114
  context <id>[@N] <id>[@N] ... Batch: up to 25 traces in one call (or --ids-from=-|<file>)
2505
2115
  audit <conversation_id|trace_id> Raw span audit (spans, hierarchy, orphans, duplicates)
2506
2116
  audit <id> <id> ... Batch audit: up to 25 ids in one call (or --ids-from=-|<file>)
2117
+ world-state <conversation_id> A trace's world state (slots, threads, events)
2118
+ clusters Browse or search topic clusters
2119
+ cluster-traces <node_id> List traces in a cluster
2120
+ users / user <user_id> End users with health and activity (the dashboard Users page)
2121
+ tail Live-tail new traces/detections as NDJSON (one line per item)
2122
+
2123
+ Detections:
2124
+ emotions Emotion detections (frustration, disapproval, confusion, ...)
2507
2125
  frustrations Frustration detections (same data as emotions --family=frustration)
2508
- emotions Multi-family emotion detections (frustration, disapproval, sadness, confusion, anxiety, trust, positive)
2509
- hallucinations Grounding detections: contradicted/verified outputs with rule breakdown
2126
+ hallucinations Grounding detections: contradicted/verified outputs
2510
2127
  laziness Laziness detections per trace (repeated calls, premature handoffs, ...)
2511
- tool-failures Get tool failure overview
2512
- tool-failure-detail <tool_name> Get per-tool failure detail (--limit=N examples, 1-20, default 5)
2128
+ tool-failures Tool failure overview
2129
+ tool-failure-detail <tool_name> Per-tool failure examples
2130
+
2131
+ Problems, signals and review:
2513
2132
  problems Rank cross-signal Problems by root cause (what to fix first)
2514
- problems remainder Signals no Problem explains yet (--family, --cursor)
2515
- problem-impact Live problem/use-case impact (--node-id, --problem-id, --mode, --days-back)
2516
- problem <problem_id> Open one Problem: dossier, or --evidence/--reports/--traces/--feedback
2133
+ problem <problem_id> One Problem: dossier, or its evidence/reports/traces/feedback
2134
+ problem-impact Live problem/use-case impact, trend and evidence
2517
2135
  problem-feedback <problem_id> Mark a Problem fixed, dismiss, rename, or flag a bad attribution
2518
- problem-reopen <problem_id> Reopen a Problem marked fixed (--reason)
2519
- false-positive <kind> <target> Mark any detection as a false positive, optional --reason (problem, problem-detection, quote, tool, laziness, hallucination, custom-signal)
2520
- false-positives [conv_id] Current false-positive marks: all (--kind, --all, --limit) or one trace
2521
- problem-linear <problem_id> Show the Linear issue linked to a Problem (key, state, URL)
2522
- problem-linear-file <problem_id> File a Problem as a Linear issue, or link an existing one (--issue)
2136
+ problem-reopen <problem_id> Reopen a Problem marked fixed
2137
+ problem-linear <problem_id> Show the Linear issue linked to a Problem
2138
+ problem-linear-file <problem_id> File a Problem as a Linear issue, or link an existing one
2523
2139
  detection-reviews <conv_id> Problem detections on a trace with their review state
2524
- detection-review <problem_id> Mark a problem detection correct, a false positive, or clear the review
2525
- signals List custom signals (name, criteria, status, 7-day stats)
2140
+ detection-review <problem_id> Mark a problem detection correct, a false positive, or clear it
2141
+ false-positive <kind> <target> Mark any detection as a false positive
2142
+ false-positives [conv_id] Current false-positive marks (workspace or one trace)
2143
+ signals List and manage custom signals
2526
2144
  signal <signal_id> One custom signal, or --detections for its recent hits
2527
- signals create|update|activate|pause|delete ...
2528
- Manage custom signals (also draft, examples, refine, revise,
2529
- proposals, accept, reject, search, preview); writes take --dry-run
2530
- users / user <user_id> End users with health and activity (the dashboard Users page)
2531
2145
  trace-signals <conversation_id> Custom signal hits on one trace
2532
2146
  signal-label <signal_id> Label a trace fits / does_not_fit (false positive) for a signal
2533
- tail Live-tail new traces/detections as NDJSON (one line per item)
2534
2147
  feedback "<note>" Flag wrong/missing data or CLI quirks to the Moda team
2535
2148
 
2536
- Legacy aliases (same behavior): conversations = traces,
2537
- cluster-conversations = cluster-traces, --conversations = --traces,
2538
- --signal=conversations = --signal=traces. <conversation_id> is the trace ID.
2539
-
2540
- Prompt management:
2541
- prompts init Create .moda/prompts.yml (version 2: prompt_paths + sources)
2542
- prompts status Show local prompt changes; warns on globs that match nothing
2543
- prompts diff Only changed/new/deleted prompts since last sync
2544
- prompts migrate [--dry-run] Rewrite a version 1 .moda/prompts.yml to version 2
2545
- prompts sync Analyze prompt sources and upload versions
2546
- prompts sync --watch Upload again when prompt files change
2547
- prompts list|show|proposals|usage|replay-runs|decide
2548
- Read the prompt registry; decide merges/rejects a proposal
2549
- prompts promote <key> Move a dev/staging/prod label
2550
- prompts ab Run a judged prompt A/B replay experiment
2551
- prompts propose Revise a prompt from a run's failures (--gate to auto-A/B, --promote-on-win)
2552
-
2553
- Replays (read-only results):
2554
- replays sets List replay sets
2555
- replays runs <set_id> Run history for a set (every status)
2556
- replays run <set_id> <run_id> One run: per-case and per-seed verdicts, playout count
2557
- replays playouts <set_id> <run_id>
2558
- Playouts per case/arm/seed (--transcript inlines messages and tool calls)
2559
- replays playout <set_id> <run_id> <playout_id>
2560
- One playout transcript
2561
-
2562
- Skills:
2563
- skills gen Kick off tenant-wide skill generation
2564
- skills status [run-id] Show a generation run's status, outcome, and recent events (default: latest run)
2565
- skills pull Pull tenant-generated skills into .claude/skills (and .cursor/rules)
2566
- skills install <id...> Install bundled integration guides into .claude/skills (--list to browse)
2567
- skills pull --status=proposed Include not-yet-promoted skills (default: approved)
2568
- skills sync Push local .claude/skills/**/SKILL.md up to Moda
2569
- skills sync --dry-run Show what would be pushed without writing
2570
- skills list|show|policy List pushed skills, show one, or set --live/--local
2571
- registry push Push prompts, skills, tools, and agent wiring from one JSON manifest
2572
-
2573
- Options:
2574
- --help Show this help message
2575
- --version Show version number
2576
- --json-schemas Print JSON Schemas for the agent output contract
2577
-
2578
- Common flags (a command rejects any it does not take; see 'moda <command> --help'):
2579
- --days-back=N Whole days to look back, 1-90 (overview, problems, emotions, laziness, tool-failures, ...)
2580
- --time-range=RANGE Window for traces, search, clusters instead (all|1h|3d|7d|24h|30d|90d)
2581
- --limit=N Maximum results to return (users: alias of --page-size)
2582
- --offset=N Number of results to skip (paged lists)
2583
- --profile=NAME Use a named local Moda profile
2584
- --json Emit machine-readable JSON
2585
- --agent Emit schema-versioned agent JSON
2586
- --stream With --agent, emit NDJSON agent events
2587
- --human Force human prose (overrides auto-detection)
2588
- --no-stream Disable live ask progress (buffered request)
2589
-
2590
- Output auto-detection (no flags needed):
2591
- Piped/redirected stdout, CI, or an agent env (CLAUDECODE/CURSOR/MODA_AGENT)
2592
- => schema-versioned agent JSON. An interactive terminal => human prose.
2593
- Override with the flags above or MODA_FORMAT=human|json|agent|agent-stream.
2594
- Exit codes: 0 ok, 1 error (errors[0].code says which, e.g. not_found), 3 degraded (local fallback),
2595
- 4 auth required (no key or key rejected), 5 input required, 130 cancelled.
2596
- --dry-run Show the planned mutation when supported
2597
- --yes Accept explicit automation defaults
2598
- --tui Force the human analyst dashboard when supported
2599
- --no-tui Show raw analyst stream instead of dashboard
2600
- --no-update-check Skip the daily new-version check (or MODA_CLI_UPDATE_CHECK=0)
2601
-
2602
- Traces flags:
2603
- --search=TEXT Ranked trace search (hybrid when embeddings exist, else keyword)
2604
- --world-state=KEYWORDS Match world-state content (slots + durable profile); comma = AND
2605
- --outcome=any|positive|negative Filter by trace outcome (trajectory + frustration)
2606
- --include-world-state Attach each result's world-state summary
2607
- --user-id=ID Filter to a single user
2608
- --environment=ENV Filter by environment (all|development|staging|production)
2609
-
2610
- Search flags:
2611
- --mode=keyword|semantic|hybrid Search mode (default hybrid)
2612
- --user-id=ID Filter to a single user
2613
- --conversation-id=ID Search inside one trace only
2614
- --time-range=RANGE Time range filter (all|1h|3d|7d|24h|30d|90d)
2615
- --limit=N Maximum results to return (1-100, default 20)
2616
-
2617
- World-state flags:
2618
- --summary-only Return segment summaries only (omit the event stream)
2619
- --event-limit=N Max world-state events to return (1-5000, default 2000)
2620
- --snapshot Folded slots at an exact tick (what the agent believed at that turn)
2621
- --msg-index=N --block-index=M Snapshot tick (defaults 0; --segment-index=K scopes to a segment)
2622
- --replay State-over-time replay; frames mode REQUIRES --message-count=N
2623
- --format=frames|fold-inputs Replay format (default frames)
2624
- --message-count=N Number of frames to fold (frames mode)
2625
-
2626
- Emotions flags:
2627
- --family=F frustration|disapproval|sadness|confusion|anxiety|trust|positive
2628
- --days-back=N --limit=N Window 1-90 (default 7); page size 1-20 (default 10)
2629
- --offset=N Skip N detections (0-10000)
2630
- --include-window Keep each detection's conversation window in agent output
2631
- (also frustrations; omitted by default, use context_command)
2632
-
2633
- Laziness flags:
2634
- --family=F One laziness family (e.g. omission_phrase, stub_body, deflection, completion, tool_selection)
2635
- --conversation-id=ID One trace's detections
2636
- --days-back=N --limit=N Window 1-90 (default 7); page size 1-50 (default 10)
2637
-
2638
- Hallucinations flags:
2639
- --kind=contradicted|verified Narrow the detections list
2640
- --conversation-id=ID Scope summary + list to one trace ID
2641
- --days-back=N --limit=N Window 1-90 (default 7); page size 1-20 (default 10)
2642
-
2643
- Problem flags (moda problem <id>):
2644
- --full Whole dossier in agent output (default there: header, summary,
2645
- top 5 evidence anchors, report titles)
2646
- --evidence|--reports|--traces|--feedback
2647
- Open one sub-resource page (at most one)
2648
- --limit=N --cursor=TOKEN Keyset paging (1-50; pass next_cursor back verbatim)
2649
- --family=F --door=D Filter --traces (families: tool_failure|emotion|laziness|hallucination|prm_dip|custom_signal|conversation_reader)
2650
-
2651
- Problem-feedback flags:
2652
- --action=A mark_fixed|dismiss|flag_attribution|rename (required)
2653
- --reason=TEXT Required for flag_attribution; optional for dismiss
2654
- --attribution-id=UUID Required for flag_attribution (ids come from problem --evidence)
2655
- --new-name=NAME Required for rename
2656
-
2657
- False-positive flags (moda false-positive <kind> <target>):
2658
- --reason=TEXT Why it is wrong (optional)
2659
- --undo Remove an earlier mark (every kind except problem)
2660
- problem <problem_id> Dismiss the problem: hidden at once, logged for review, folded into reconcile
2661
- problem-detection <problem_id> One detection on a trace; needs --conversation-id and --attribution-id; teaches the problem
2662
- quote <conversation_id> A user quote; needs --family, --turn and --quote (from moda emotions); audit only
2663
- tool <conversation_id> One failing tool call; needs --tool and --tool-use-id (or --msg-index); audit only
2664
- laziness <conversation_id> Laziness on that trace; audit only
2665
- hallucination <conversation_id> Hallucinations on that trace; audit only
2666
- custom-signal <signal_id> A hit on that trace (--conversation-id); saved as does_not_fit, a labelled counterexample for the signal
2667
-
2668
- Problem-linear-file flags (needs Linear connected: Integrations -> Linear):
2669
- --issue=ENG-123|URL Link an existing Linear issue instead of filing a new one
2670
- --team-id=ID File into this Linear team (default: the integration's default team)
2671
- --title=TEXT Issue title (default: the Problem's name)
2672
- --priority=N 0 none, 1 urgent, 2 high, 3 medium, 4 low
2673
- --issue excludes --team-id/--title/--priority
2674
-
2675
- Detection-review flags (moda detection-review <problem_id>):
2676
- --conversation-id=ID Trace the detection is on (required)
2677
- --attribution-id=UUID Detection id (from problem --evidence or detection-reviews; required)
2678
- --verdict=V correct|false_positive|clear (required; clear undoes a review)
2679
- --note=TEXT Why (optional; kept with the review)
2680
-
2681
- Signal flags:
2682
- --detections moda signal <id>: list recent hits instead of the summary
2683
- --days-back=N --limit=N --offset=N
2684
- Hits window 1-90 (default 7); page size 1-20 (default 10)
2685
-
2686
- Signal-label flags (moda signal-label <signal_id>):
2687
- --conversation-id=ID Trace to label (required)
2688
- --label=fits|does_not_fit does_not_fit marks a false positive and retracts the hit (required)
2689
- --note=TEXT Why (recommended for does_not_fit)
2690
- --msg-index=N --msg-dedup-token=T
2691
- Anchor message (from the hit's anchor_msg_index / anchor_dedup_token)
2692
-
2693
- Tail flags:
2694
- --signal=S traces|emotions|all (default traces)
2695
- --interval=N Poll every N seconds (5-3600, default 15)
2696
- --once One poll, then exit (baseline page)
2697
- --limit=N --max-events=N Page size per poll; stop after N stdout records
2698
- (metadata included; a slot is reserved for the
2699
- emotions coverage record, which falls back to
2700
- stderr if the bound leaves no room)
2701
- --full-scan Emotions: scan the whole window instead of the
2702
- top-scoring prefix (many more requests). /emotions
2703
- is score-ranked with no cursor, so the default
2704
- follows the highest-scoring detections and emits a
2705
- tail_coverage line stating exactly what it saw.
2706
-
2707
- Clusters search flags:
2708
- --search="query" Find clusters by name/meaning (task-cluster search)
2709
- --node-id=ID Deterministically resolve one cluster node (deep link)
2710
- --mode=fuzzy|semantic|hybrid Cluster search mode (default hybrid)
2711
-
2712
- Feedback flags:
2713
- --category=CAT ${feedbackCategoryHelp()}
2714
- An unknown category is sent as other (with refs.raw_category)
2715
- --severity=info|low|medium|high How bad it is (default low)
2716
- --note=TEXT The note, if not given as the positional argument
2717
- --conversation-id=ID Attach the trace ID you were looking at
2718
- --cluster-id=ID Attach a cluster node id
2719
- --tool-name=NAME Attach a tool name
2720
- --run-id=ID Attach a run id
2721
- --<name>-id=ID Any other id (--problem-id, --fix-id, --attribution-id,
2722
- --trace-id, --span-id, --message-index, ...) goes into refs
2723
- (set MODA_CLI_TIPS=0 to hide the feedback tip line)
2724
-
2725
- Init flags:
2726
- --yes Accept all defaults (non-interactive)
2727
- --analyst=auto|claude|codex|cursor|local-scan
2728
- Choose harness analyst adapter
2729
- --analyst-model=MODEL Model for the claude analyst (default: sonnet;
2730
- "default" = the claude CLI's own default;
2731
- env: MODA_HARNESS_ANALYST_MODEL)
2732
- --assist=none Disable agent fallback for prompt discovery
2733
- --concern=topology|tools|prompts|evals
2734
- Harness analyze: restrict the pass to one
2735
- concern (whole repo, one report scope); an
2736
- orchestrator merges the per-concern reports
2737
- (env: MODA_HARNESS_CONCERN, flag wins)
2738
- --allow-no-agents Allow harness sync to push a graph with zero
2739
- runtime agents despite detected LLM usage
2740
- --remote Run harness analysis server-side (Moda-hosted,
2741
- the default): upload a safe source snapshot; no
2742
- local coding agent required
2743
- --local Run harness analysis with a LOCAL coding agent
2744
- instead of server-side (opt out of remote)
2745
- --tui Show full-screen analyst dashboard in human TTYs
2746
- --no-tui Show raw external analyst output
2747
- --sdk-integrate Run your coding agent to install the Moda SDK and instrument LLM calls
2748
- --no-sdk-integrate Skip SDK integration (alias: --no-sdk-guide)
2749
- --verification-id=ID Tag the SDK integration's test trace with this id
2750
- (the onb_ id from the Moda onboarding page)
2751
- --connect-code=CODE Sign in with the one-time mcc_ code from the Moda
2752
- onboarding page instead of the browser (10 min, single use)
2753
- --ci-cd Create GitHub Actions Moda validation workflow
2754
- --no-ci-cd Skip CI/CD workflow creation
2755
- --autosync Create GitHub Actions workflow to sync prompts + skills to Moda on push to main
2756
- --no-autosync Skip autosync workflow creation
2757
- --harness-rescan Create GitHub Actions workflow to re-scan the harness and sync it to Moda on push to main
2758
- --no-harness-rescan Skip harness rescan workflow creation
2759
- --harness-rescan-paths=GLOBS Comma-separated path globs that scope which pushes trigger the
2760
- harness rescan workflow (implies --harness-rescan)
2761
- --offline Run final validation offline (skip the online telemetry check)
2149
+ Setup:
2150
+ init Set up Moda in your project
2151
+ provision Headless tenant + API key provisioning (JSON credentials on stdout)
2152
+ auth Log in (browser or --api-key), status, token, whoami, logout
2153
+ status Show concise local Moda setup status
2154
+ doctor Diagnose local Moda setup and data flow
2155
+ profiles List, switch, create and check local profiles
2156
+ config Show resolved Moda config
2157
+ manifest The CLI machine contract: commands, flags, events, exit codes
2158
+ agent Context, next actions and evidence for coding agents
2762
2159
 
2763
- Provision flags (headless; requires an existing "moda auth login" session):
2764
- --tenant-id=ID Organization to provision (required with multiple
2765
- organizations; MODA_TENANT_ID env is also honored,
2766
- flag wins). Never prompts, even on a TTY.
2767
- --label=TEXT API key label (default: machine hostname)
2768
- --save Also persist the key to ~/.moda/config.json
2769
- (default: print only; headless callers own storage)
2160
+ Groups with their own subcommands (run 'moda <group> --help'):
2161
+ harness Analyze, scan, validate, approve, sync and register the agent harness
2162
+ prompts Code-first prompt versions: init, status, sync, promote, A/B, propose
2163
+ replays Replay results: sets, runs, playouts and transcripts
2164
+ skills Generate, pull, install and sync agent skills
2165
+ sync Sync the harness graph and prompts to Moda Cloud
2166
+ registry Push prompts, skills, tools and agent wiring from one JSON manifest
2770
2167
 
2771
- Examples:
2772
- moda init
2773
- moda auth login --api-key=$MODA_API_KEY
2774
- moda auth whoami
2775
- moda provision --tenant-id=<org-id>
2776
- moda status
2777
- moda manifest --json
2778
- moda doctor --json
2779
- moda profiles list
2780
- moda profiles use staging
2781
- moda config show --profile=prod
2782
- moda harness analyze --experimental --summary
2783
- moda harness analyze --experimental --remote
2784
- moda harness analyze --experimental --analyst=claude --tui
2785
- moda harness analyze --experimental --analyst=claude --no-tui
2786
- moda harness analyze --experimental --analyst=claude --summary
2787
- moda harness analyze --experimental --analyst=local-scan --summary
2788
- moda harness pull --sync
2789
- moda harness validate-report
2790
- moda harness approve --yes
2791
- moda harness sync --from-report .moda/harness-report.json
2792
- moda harness delete my-harness-key --yes
2793
- moda --agent doctor
2794
- moda agent context
2795
- moda agent next-action
2796
- moda agent evidence doctor:api_key_resolves
2797
- moda investigate
2798
- moda failures
2799
- moda ask "what should I fix first?"
2800
- moda sync --dry-run
2801
- moda sync harness --profile=prod
2802
- moda harness scan --json
2803
- moda harness candidates --out=.moda/harness-candidates.json
2804
- moda harness explain --agent=agent_support
2805
- moda init --ci-cd
2806
- moda init --autosync
2807
- moda init --harness-rescan --harness-rescan-paths='src/agents/**'
2808
- moda overview --days-back=30
2809
- moda clusters --time-range=7d
2810
- moda traces --search="error" --limit=5
2811
- moda traces --world-state="enterprise" --outcome=positive
2812
- moda traces --world-state="refund,billing" --include-world-state
2813
- moda search "billing error" --mode=hybrid
2814
- moda search "refund flow" --mode=semantic --time-range=7d --limit=10
2815
- moda world-state <conversation_id> --summary-only
2816
- moda world-state <conversation_id> --snapshot --msg-index=42
2817
- moda world-state <conversation_id> --replay --message-count=50
2818
- moda clusters --search="billing disputes"
2819
- moda emotions --family=confusion --days-back=14
2820
- moda hallucinations --kind=contradicted
2821
- moda problems --days-back=7
2822
- moda problem <problem_id> --evidence --limit=10
2823
- moda problem-feedback <problem_id> --action=mark_fixed
2824
- moda problem-linear <problem_id>
2825
- moda problem-linear-file <problem_id> --priority=2
2826
- moda detection-reviews <conversation_id>
2827
- moda detection-review <problem_id> --conversation-id=<id> --attribution-id=<uuid> --verdict=false_positive --note="expected retry"
2828
- moda signals
2829
- moda signal <signal_id> --detections --days-back=30
2830
- moda signal-label <signal_id> --conversation-id=<id> --label=does_not_fit --note="refund was approved"
2831
- moda tail --signal=all --interval=30
2832
- moda frustrations --days-back=14 --limit=20
2833
- moda feedback "cluster label looks wrong" --category=bad_cluster_label --cluster-id=<node_id>
2834
- moda context <conversation_id> --window=3
2835
- moda audit <conversation_id|trace_id>
2836
- moda audit <trace_id> --kind=trace --json
2837
- moda prompts status
2838
- moda prompts sync
2839
- moda prompts promote support.triage --label=prod --version=pver_abc123
2840
- moda prompts ab --baseline=prompts/agent.prompt.md --candidate=prompts/agent-v2.prompt.md --traces=conv_1,conv_2
2841
- moda prompts ab --baseline=prompts/agent.prompt.md --candidate=prompts/agent-v2.prompt.md --traces=conv_1@412 # replay from msg 412
2842
- moda skills pull
2168
+ Legacy aliases (same behavior): conversations = traces, cluster-conversations = cluster-traces,
2169
+ trace = audit, --conversations = --traces, --signal=conversations = --signal=traces.
2170
+ <conversation_id> is the trace ID.
2843
2171
 
2844
- Run \`moda <command> --help\` for a command's subcommands, and
2845
- \`moda <command> <subcommand> --help\` for that subcommand's flags
2846
- (e.g. \`moda auth login --help\`).`);
2172
+ Output: piped stdout, CI or an agent env (CLAUDECODE/CURSOR/MODA_AGENT) => agent JSON; a terminal => prose.
2173
+ --json | --agent [--stream] | --human Force an output mode (or MODA_FORMAT=human|json|agent|agent-stream)
2174
+ --profile=NAME --quiet --no-update-check --version --json-schemas
2175
+ Exit codes: 0 ok, 1 error (errors[0].code says which), 3 degraded, 4 auth required, 5 input required, 130 cancelled.
2176
+ A command rejects any flag it does not take; the error lists errors[0].allowed and errors[0].did_you_mean.`);
2177
+ }
2178
+ function globalFlagHelpLines(commandFlags = []) {
2179
+ const own = new Set(commandFlags.map((key) => kebabFlag(key).slice(2)));
2180
+ const flags = [...GLOBAL_FLAG_NAMES].filter((flag) => flag !== "help" && !own.has(flag)).map((flag) => flag === "profile" ? "--profile=NAME" : flag === "format" ? "--format=ndjson" : `--${flag}`);
2181
+ const lines = [];
2182
+ let line = "Global flags (every command):";
2183
+ for (const flag of flags) {
2184
+ if (line.length + flag.length + 1 > 100) {
2185
+ lines.push(line);
2186
+ line = " ";
2187
+ }
2188
+ line += ` ${flag}`;
2189
+ }
2190
+ lines.push(line);
2191
+ return lines;
2847
2192
  }
2848
2193
  function printCommandHelp(definition) {
2849
2194
  const lines = [];
@@ -2857,6 +2202,17 @@ function printCommandHelp(definition) {
2857
2202
  for (const note of definition.helpNotes ?? []) {
2858
2203
  lines.push("", note);
2859
2204
  }
2205
+ const flagSpec = flagSpecFor(definition.name);
2206
+ if (flagSpec) {
2207
+ lines.push("", ...renderFlagHelp(definition.name, flagSpec));
2208
+ } else if (definition.documentedFlags && definition.documentedFlags.length > 0) {
2209
+ lines.push("", "Flags:");
2210
+ const width = Math.min(34, Math.max(...definition.documentedFlags.map((flag) => flag.name.length)));
2211
+ for (const flag of definition.documentedFlags) {
2212
+ lines.push(flag.name.length > width ? ` ${flag.name}
2213
+ ${" ".repeat(width)} ${flag.description}` : ` ${flag.name.padEnd(width)} ${flag.description}`);
2214
+ }
2215
+ }
2860
2216
  if (definition.subcommands && definition.subcommands.length > 0) {
2861
2217
  lines.push("", "Subcommands:");
2862
2218
  const width = Math.max(...definition.subcommands.map((entry) => entry.name.length));
@@ -2871,7 +2227,7 @@ function printCommandHelp(definition) {
2871
2227
  lines.push(` ${example}`);
2872
2228
  }
2873
2229
  }
2874
- lines.push("", "Run 'moda --help' for the full command list and the output flags every command", "takes (--json, --agent, --human, --profile). Window and paging flags (--days-back,", "--time-range, --limit, --offset) differ by command; an unsupported one is rejected.");
2230
+ lines.push("", ...globalFlagHelpLines(flagSpec ? specFlagKeys(flagSpec) : []), flagSpec ? "Any other flag is rejected." : "Run 'moda --help' for the command list.");
2875
2231
  console.log(lines.join(`
2876
2232
  `));
2877
2233
  }
@@ -3254,7 +2610,7 @@ function recordSearchTelemetry(context, data) {
3254
2610
  const pagination = asRecord(record.pagination);
3255
2611
  const hasMore = pagination?.has_more;
3256
2612
  context.recordTelemetry({
3257
- search_mode_effective: SEARCH_MODES2.includes(effective) ? effective : undefined,
2613
+ search_mode_effective: SEARCH_MODES.includes(effective) ? effective : undefined,
3258
2614
  result_count: results.length,
3259
2615
  has_more: hasMore === true ? "yes" : hasMore === false ? "no" : "na",
3260
2616
  ...typeof record.degrade_reason === "string" && record.degrade_reason ? { degrade_reason: record.degrade_reason.slice(0, 64) } : {}
@@ -3335,7 +2691,6 @@ var GLOBAL_FLAG_NAMES = new Set([
3335
2691
  "no-telemetry",
3336
2692
  "no-update-check"
3337
2693
  ]);
3338
- var OVERVIEW_PRODUCTION_FLAGS = ["raw"];
3339
2694
  var WINDOW_FLAG_HINTS = {
3340
2695
  days_back: "This command takes --time-range (e.g. --time-range=7d), not --days-back.",
3341
2696
  time_range: "This command takes --days-back=N (1-90), not --time-range."
@@ -3346,27 +2701,8 @@ var COMMAND_FLAG_HINTS = {
3346
2701
  cursor: "'moda problems' has no cursor; 'moda problems remainder --cursor=<next_cursor>' pages the unexplained signals."
3347
2702
  }
3348
2703
  };
3349
- function editDistance(a, b) {
3350
- const row = Array.from({ length: b.length + 1 }, (_, index) => index);
3351
- for (let i = 1;i <= a.length; i++) {
3352
- let previous = row[0];
3353
- row[0] = i;
3354
- for (let j = 1;j <= b.length; j++) {
3355
- const current = row[j];
3356
- row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
3357
- previous = current;
3358
- }
3359
- }
3360
- return row[b.length];
3361
- }
3362
- function schemaFlagKeys(schema) {
3363
- let current = schema;
3364
- while (current instanceof z2.ZodEffects)
3365
- current = current.innerType();
3366
- return current instanceof z2.ZodObject ? Object.keys(current.shape) : [];
3367
- }
3368
2704
  function parseCommandFlags(schema, args, command, options = {}) {
3369
- const schemaKeys = schemaFlagKeys(schema);
2705
+ const schemaKeys = Object.keys(schemaShape(schema));
3370
2706
  const known = new Set([
3371
2707
  ...schemaKeys,
3372
2708
  ...[...GLOBAL_FLAG_NAMES, ...options.extraFlags ?? []].map((flag) => flag.replace(/-/g, "_"))
@@ -3376,24 +2712,70 @@ function parseCommandFlags(schema, args, command, options = {}) {
3376
2712
  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/register, prompts sync/decide, skills sync/policy, signals <write subcommands>, problem-reopen.`, "unsupported_dry_run");
3377
2713
  }
3378
2714
  if (unknown.length > 0) {
3379
- const flagKeys = schemaKeys.filter((key) => key !== options.positionalKey);
3380
- const valid = flagKeys.map((key) => `--${key.replace(/_/g, "-")}`);
2715
+ const flagKeys = [
2716
+ ...schemaKeys.filter((key) => key !== options.positionalKey),
2717
+ ...(options.extraFlags ?? []).map((flag) => flag.replace(/-/g, "_"))
2718
+ ];
2719
+ const valid = flagKeys.map(kebabFlag);
2720
+ const candidates = [...valid, ...Object.keys(options.flagAliases ?? {}).map((alias) => `--${alias}`)];
2721
+ const didYouMean = [];
3381
2722
  const hints = unknown.map((key) => {
3382
2723
  const commandHint = COMMAND_FLAG_HINTS[command]?.[key];
3383
2724
  if (commandHint)
3384
2725
  return commandHint;
3385
2726
  const windowAlternative = key === "days_back" ? "time_range" : key === "time_range" ? "days_back" : undefined;
3386
- if (windowAlternative && WINDOW_FLAG_HINTS[key] && flagKeys.includes(windowAlternative))
2727
+ if (windowAlternative && WINDOW_FLAG_HINTS[key] && flagKeys.includes(windowAlternative)) {
2728
+ didYouMean.push(kebabFlag(windowAlternative));
3387
2729
  return WINDOW_FLAG_HINTS[key];
2730
+ }
3388
2731
  if (windowAlternative)
3389
2732
  return `This command has no time-window flag.`;
3390
- const close = flagKeys.map((candidate) => ({ candidate, distance: editDistance(key, candidate) })).filter(({ distance }) => distance <= 2).sort((left, right) => left.distance - right.distance)[0];
3391
- return close ? `Did you mean --${close.candidate.replace(/_/g, "-")}?` : "";
2733
+ const close = closestMatches(kebabFlag(key), candidates, 1)[0];
2734
+ if (close)
2735
+ didYouMean.push(close);
2736
+ return close ? `Did you mean ${close}?` : "";
3392
2737
  }).filter(Boolean);
3393
- const names = unknown.map((key) => `--${key.replace(/_/g, "-")}`).join(", ");
3394
- 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, "-")}`);
2738
+ const names = unknown.map(kebabFlag).join(", ");
2739
+ const helpCommand = `moda ${command} --help`;
2740
+ throw new CliInputError(`Unknown flag${unknown.length > 1 ? "s" : ""} ${names} for 'moda ${command}'.` + (didYouMean.length > 0 ? ` Did you mean ${didYouMean.join(", ")}?` : ""), [...hints, `Valid flags: ${valid.join(", ") || "(none)"}. Run '${helpCommand}'.`].join(" "), `unknown_flag:${unknown[0].replace(/_/g, "-")}`, {
2741
+ field: kebabFlag(unknown[0]),
2742
+ allowed: valid,
2743
+ ...didYouMean.length > 0 ? { didYouMean: [...new Set(didYouMean)] } : {},
2744
+ suggestedCommands: [helpCommand]
2745
+ });
3395
2746
  }
3396
- return schema.parse(args);
2747
+ try {
2748
+ return schema.parse(args);
2749
+ } catch (error) {
2750
+ if (error instanceof z.ZodError)
2751
+ attachFlagDetails(error, schema, command);
2752
+ throw error;
2753
+ }
2754
+ }
2755
+ function attachFlagDetails(error, schema, command) {
2756
+ const key = error.issues[0]?.path[0];
2757
+ if (typeof key !== "string")
2758
+ return;
2759
+ const field = describeSpecFlags({ schema }).find((flag) => flag.name === kebabFlag(key));
2760
+ if (!field)
2761
+ return;
2762
+ attachInputDetails(error, {
2763
+ field: field.name,
2764
+ ...field.enum ? { allowed: field.enum } : {},
2765
+ ...field.min !== undefined || field.max !== undefined ? { range: { ...field.min !== undefined ? { min: field.min } : {}, ...field.max !== undefined ? { max: field.max } : {} } } : {},
2766
+ suggestedCommands: [`moda ${command} --help`]
2767
+ });
2768
+ }
2769
+ function parseSpecFlags(name, args, command = name) {
2770
+ return parseCommandFlags(COMMAND_FLAG_SPECS[name].schema, args, command, specParseOptions(COMMAND_FLAG_SPECS[name]));
2771
+ }
2772
+ function specParseOptions(spec) {
2773
+ const positional = spec.positionals?.find((entry) => entry.key && !entry.alsoFlag);
2774
+ return {
2775
+ extraFlags: Object.keys(spec.extra?.shape ?? {}),
2776
+ ...positional?.key ? { positionalKey: positional.key } : {},
2777
+ ...spec.flagAliases ? { flagAliases: spec.flagAliases } : {}
2778
+ };
3397
2779
  }
3398
2780
  function withStringIdFlags(args, flags) {
3399
2781
  for (const flag of ["user-id", "conversation-id"]) {
@@ -3478,6 +2860,10 @@ async function searchFallbackToTraces(params) {
3478
2860
  query2.set("user_id", params.user_id);
3479
2861
  if (params.time_range)
3480
2862
  query2.set("time_range", params.time_range);
2863
+ if (params.since)
2864
+ query2.set("since", params.since);
2865
+ if (params.until)
2866
+ query2.set("until", params.until);
3481
2867
  query2.set("limit", String(limit));
3482
2868
  if (offset > 0)
3483
2869
  query2.set("offset", String(offset));
@@ -3485,6 +2871,8 @@ async function searchFallbackToTraces(params) {
3485
2871
  `moda traces --search=${shellArg(params.q)}`,
3486
2872
  params.user_id ? `--user-id=${shellArg(params.user_id)}` : "",
3487
2873
  params.time_range ? `--time-range=${shellArg(params.time_range)}` : "",
2874
+ params.since ? `--since=${shellArg(params.since)}` : "",
2875
+ params.until ? `--until=${shellArg(params.until)}` : "",
3488
2876
  `--limit=${limit}`
3489
2877
  ].filter(Boolean).join(" ");
3490
2878
  let traces;
@@ -3575,36 +2963,12 @@ function serverWarnings(data) {
3575
2963
  function isDefinedRecord(value) {
3576
2964
  return value !== undefined && value !== null;
3577
2965
  }
3578
- var HAND_PARSED_COMMAND_FLAGS = {
3579
- investigate: ["days-back", "tool", "trace", "conversation"],
3580
- failures: ["days-back", "tool"],
3581
- ask: ["days-back", "stream"],
3582
- "step-scores": [],
3583
- "trace-signals": [],
3584
- signals: [],
3585
- "problem-feedback": ["action", "actor", "reason", "attribution-id", "new-name"],
3586
- "problem-linear": [],
3587
- "problem-linear-file": ["issue", "priority", "title", "team-id"],
3588
- "signal-label": ["label", "note", "conversation-id", "msg-dedup-token", "msg-index"],
3589
- "detection-reviews": ["attribution-id"],
3590
- "detection-review": ["note", "verdict", "attribution-id", "conversation-id"],
3591
- "false-positive": [
3592
- "family",
3593
- "quote",
3594
- "reason",
3595
- "tool",
3596
- "turn",
3597
- "undo",
3598
- "attribution-id",
3599
- "conversation-id",
3600
- "msg-dedup-token",
3601
- "msg-index",
3602
- "tool-use-id"
3603
- ],
3604
- "false-positives": ["all", "kind", "limit"],
3605
- feedback: FEEDBACK_FLAGS,
3606
- "problem-impact": ["mode", "node-id", "problem-id", "run-id", "to", "cursor", "conversation-ids", "days-back"]
3607
- };
2966
+ function handParsedFlags(command) {
2967
+ const spec = flagSpecFor(command);
2968
+ if (!spec?.handParsed || ["users", "user", "problem-reopen"].includes(command))
2969
+ return;
2970
+ return { spec, allowed: specFlagNames(spec) };
2971
+ }
3608
2972
  var NO_POSITIONAL_COMMANDS = new Set([
3609
2973
  "overview",
3610
2974
  "investigate",
@@ -3630,18 +2994,18 @@ function assertHandParsedFlags(command, flags, positionals) {
3630
2994
  if (NO_POSITIONAL_COMMANDS.has(command) && positionals.length > 0) {
3631
2995
  throw new CliInputError(`'moda ${command}' takes no arguments, but got '${positionals.join(" ")}'.`, `Nothing was run. See 'moda ${command} --help' for its flags.`);
3632
2996
  }
3633
- const allowed = HAND_PARSED_COMMAND_FLAGS[command];
3634
- if (!allowed)
2997
+ const hand = handParsedFlags(command);
2998
+ if (!hand)
3635
2999
  return;
3636
- const checked = command === "feedback" ? Object.keys(flags).filter((flag) => !isFeedbackRefFlag(flag)) : Object.keys(flags);
3637
- const shape = z2.object(Object.fromEntries(allowed.map((flag) => [flag.replace(/-/g, "_"), z2.unknown()])));
3000
+ const checked = hand.spec.idRefFlags ? Object.keys(flags).filter((flag) => !isFeedbackRefFlag(flag)) : Object.keys(flags);
3001
+ const shape = z.object(Object.fromEntries(hand.allowed.map((flag) => [flag.replace(/-/g, "_"), z.unknown()])));
3638
3002
  const args = Object.fromEntries(checked.map((flag) => [flag.replace(/-/g, "_"), true]));
3639
3003
  try {
3640
- parseCommandFlags(shape.passthrough(), args, command);
3004
+ parseCommandFlags(shape.passthrough(), args, command, { flagAliases: hand.spec.flagAliases });
3641
3005
  } catch (error) {
3642
3006
  if (command !== "feedback" || !(error instanceof CliInputError))
3643
3007
  throw error;
3644
- 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);
3008
+ 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, error.details);
3645
3009
  }
3646
3010
  }
3647
3011
  function normalizeBooleanFlags(target) {
@@ -3664,7 +3028,7 @@ function normalizeBooleanFlags(target) {
3664
3028
  }
3665
3029
  var PROFILE_MANAGING_COMMANDS = new Set(["profiles", "auth", "init", "provision", "status", "config", "manifest", "agent", "doctor"]);
3666
3030
  async function runProblemsRemainder(flags, context) {
3667
- const params = parseCommandFlags(ProblemsRemainderSchema, flagsToArgs(flags), "problems remainder");
3031
+ const params = parseCommandFlags(ProblemsRemainderSchema, flagsToArgs(flags), "problems remainder", specParseOptions(COMMAND_FLAG_SPECS.problems.subcommands.remainder));
3668
3032
  const query2 = new URLSearchParams;
3669
3033
  if (params.days_back)
3670
3034
  query2.set("days_back", params.days_back.toString());
@@ -3729,7 +3093,7 @@ function parseContextRequest(positional, rawFlags) {
3729
3093
  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.`);
3730
3094
  }
3731
3095
  const args = { ...flagsToArgs(flags), conversation_id: conversationId };
3732
- const params = parseCommandFlags(ContextSchema, args, "context", { positionalKey: "conversation_id" });
3096
+ const params = parseSpecFlags("context", args);
3733
3097
  if (params.metadata_only === true && params.window !== undefined) {
3734
3098
  throw new CliInputError("--metadata-only reads no messages, so it cannot be combined with --window; drop --window.", CONTEXT_USAGE, "flag_conflict");
3735
3099
  }
@@ -4165,7 +3529,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4165
3529
  }
4166
3530
  case "overview": {
4167
3531
  const args = flagsToArgs(flags);
4168
- parseCommandFlags(OverviewSchema, args, command, { extraFlags: OVERVIEW_PRODUCTION_FLAGS });
3532
+ parseSpecFlags("overview", args, command);
4169
3533
  return (await runProductionCommand(context)).exitCode;
4170
3534
  }
4171
3535
  case "investigate":
@@ -4175,7 +3539,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4175
3539
  }
4176
3540
  case "clusters": {
4177
3541
  const args = flagsToArgs(flags);
4178
- const params = parseCommandFlags(ClustersSchema, args, command);
3542
+ const params = parseSpecFlags("clusters", args, command);
4179
3543
  if (params.search !== undefined || params.node_id !== undefined) {
4180
3544
  const query3 = new URLSearchParams;
4181
3545
  if (params.search !== undefined)
@@ -4209,7 +3573,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4209
3573
  throw new CliInputError("<node_id> is required", "Usage: moda cluster-traces <node_id> [--limit=N] [--offset=N]");
4210
3574
  }
4211
3575
  const args = flagsToArgs(flags, "node_id", positional);
4212
- const params = parseCommandFlags(ClusterConversationsSchema, args, command, { positionalKey: "node_id" });
3576
+ const params = parseSpecFlags("cluster-traces", args, command);
4213
3577
  const query2 = new URLSearchParams;
4214
3578
  if (params.limit)
4215
3579
  query2.set("limit", params.limit.toString());
@@ -4225,7 +3589,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4225
3589
  case "traces":
4226
3590
  case "conversations": {
4227
3591
  const args = withStringIdFlags(flagsToArgs(flags), flags);
4228
- const params = parseCommandFlags(ConversationsSchema, args, command);
3592
+ const params = parseSpecFlags("traces", args, command);
4229
3593
  const query2 = new URLSearchParams;
4230
3594
  if (params.search)
4231
3595
  query2.set("search", params.search);
@@ -4235,6 +3599,10 @@ async function runCommand(command, positional, flags, positionals = positional ?
4235
3599
  query2.set("user_id", params.user_id);
4236
3600
  if (params.time_range)
4237
3601
  query2.set("time_range", params.time_range);
3602
+ if (params.since)
3603
+ query2.set("since", params.since);
3604
+ if (params.until)
3605
+ query2.set("until", params.until);
4238
3606
  if (params.environment)
4239
3607
  query2.set("environment", params.environment);
4240
3608
  if (params.world_state)
@@ -4280,10 +3648,10 @@ async function runCommand(command, positional, flags, positionals = positional ?
4280
3648
  }
4281
3649
  case "search": {
4282
3650
  if (!positional || positional.trim() === "") {
4283
- throw new CliInputError("<query> is required", 'Usage: moda search "<query>" [--mode=keyword|semantic|hybrid] [--user-id=ID] [--conversation-id=ID] [--time-range=RANGE] [--include-tool-io] [--limit=N]');
3651
+ throw new CliInputError("<query> is required", 'Usage: moda search "<query>" [--mode=keyword|semantic|hybrid] [--user-id=ID] [--conversation-id=ID] [--time-range=RANGE] [--since=DATE] [--until=DATE] [--include-tool-io] [--limit=N]');
4284
3652
  }
4285
3653
  const args = withStringIdFlags(flagsToArgs(flags, "q", positional), flags);
4286
- const params = parseCommandFlags(SearchSchema, args, command, { positionalKey: "q" });
3654
+ const params = parseSpecFlags("search", args, command);
4287
3655
  const query2 = new URLSearchParams;
4288
3656
  query2.set("q", params.q);
4289
3657
  if (params.mode)
@@ -4294,6 +3662,10 @@ async function runCommand(command, positional, flags, positionals = positional ?
4294
3662
  query2.set("conversation_id", params.conversation_id);
4295
3663
  if (params.time_range)
4296
3664
  query2.set("time_range", params.time_range);
3665
+ if (params.since)
3666
+ query2.set("since", params.since);
3667
+ if (params.until)
3668
+ query2.set("until", params.until);
4297
3669
  if (params.limit)
4298
3670
  query2.set("limit", params.limit.toString());
4299
3671
  if (params.include_tool_io)
@@ -4335,7 +3707,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4335
3707
  throw new CliInputError("<conversation_id> is required", "Usage: moda world-state <conversation_id> [--summary-only] [--event-limit=N]");
4336
3708
  }
4337
3709
  const args = flagsToArgs(flags, "conversation_id", positional);
4338
- const params = parseCommandFlags(WorldStateSchema, args, command, { positionalKey: "conversation_id" });
3710
+ const params = parseSpecFlags("world-state", args, command);
4339
3711
  if (params.snapshot === true && params.replay === true) {
4340
3712
  throw new CliInputError("Choose either --snapshot or --replay, not both.", "Usage: moda world-state <conversation_id> [--snapshot --msg-index=N [--block-index=M] [--segment-index=K]] | [--replay --message-count=N [--format=frames|fold-inputs]]");
4341
3713
  }
@@ -4393,7 +3765,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4393
3765
  throw new CliInputError("<conversation_id|trace_id> is required", AUDIT_USAGE);
4394
3766
  }
4395
3767
  const args = flagsToArgs(flags, "id", positional);
4396
- const params = parseCommandFlags(AuditSchema, args, command, { positionalKey: "id" });
3768
+ const params = parseSpecFlags("audit", args, command);
4397
3769
  const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
4398
3770
  const page = await readAuditItem(command, params, agentMode ? {
4399
3771
  maxBytes: Math.max(AUDIT_MIN_PAGE_BYTES, agentMaxOutputBytes() - AUDIT_AGENT_RESERVE_BYTES),
@@ -4404,7 +3776,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4404
3776
  }
4405
3777
  case "frustrations": {
4406
3778
  const args = withStringIdFlags(flagsToArgs(flags), flags);
4407
- const params = parseCommandFlags(FrustrationsSchema, args, command);
3779
+ const params = parseSpecFlags("frustrations", args, command);
4408
3780
  const query2 = new URLSearchParams;
4409
3781
  if (params.days_back)
4410
3782
  query2.set("days_back", params.days_back.toString());
@@ -4426,7 +3798,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4426
3798
  }
4427
3799
  case "tool-failures": {
4428
3800
  const args = flagsToArgs(flags);
4429
- const params = parseCommandFlags(ToolFailuresSchema, args, command);
3801
+ const params = parseSpecFlags("tool-failures", args, command);
4430
3802
  const queryString = params.days_back ? `?days_back=${params.days_back}` : "";
4431
3803
  const data = await callDataAPI(`/tool-failures${queryString}`);
4432
3804
  context.output.writeData(data);
@@ -4444,7 +3816,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4444
3816
  toolFlags["include-window"] = "false";
4445
3817
  }
4446
3818
  const args = flagsToArgs(toolFlags, "tool_name", positional);
4447
- const params = parseCommandFlags(ToolFailureDetailSchema, args, command, { positionalKey: "tool_name" });
3819
+ const params = parseSpecFlags("tool-failure-detail", args, command);
4448
3820
  const dropConversation = params.compact === true || params.include_window === false;
4449
3821
  if (params.compact === true && params.include_window === true) {
4450
3822
  throw new CliInputError("--compact drops the conversation window; drop --include-window, or drop --compact.");
@@ -4524,7 +3896,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4524
3896
  throw new CliInputError(`Unknown problems subcommand '${positional}'.`, "Usage: moda problems [--days-back=N] [--limit=N] | moda problems remainder [--family=F] [--days-back=N] [--limit=N] [--cursor=TOKEN]. For one Problem use 'moda problem <id>'.");
4525
3897
  }
4526
3898
  const args = flagsToArgs(flags);
4527
- const params = parseCommandFlags(ProblemsSchema, args, command);
3899
+ const params = parseSpecFlags("problems", args, command);
4528
3900
  const query2 = new URLSearchParams;
4529
3901
  if (params.days_back)
4530
3902
  query2.set("days_back", params.days_back.toString());
@@ -4551,7 +3923,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4551
3923
  throw new CliInputError("<problem_id> is required", "Usage: moda problem <problem_id> [--full | --evidence|--reports|--traces|--feedback] [--limit=N] [--cursor=TOKEN] [--family=F] [--door=D]");
4552
3924
  }
4553
3925
  const args = flagsToArgs(flags, "id", positional);
4554
- const params = parseCommandFlags(ProblemSchema, args, command, { positionalKey: "id" });
3926
+ const params = parseSpecFlags("problem", args, command);
4555
3927
  const traceView = params.traces === true || params.conversations === true;
4556
3928
  const views = ["evidence", "reports", "conversations", "feedback"].filter((view2) => view2 === "conversations" ? traceView : params[view2] === true);
4557
3929
  if (views.length > 1) {
@@ -4725,7 +4097,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4725
4097
  }
4726
4098
  const args = flagsToArgs(flags, "id", positional);
4727
4099
  args.id = positional;
4728
- const params = parseCommandFlags(SignalSchema, args, command, { positionalKey: "id" });
4100
+ const params = parseSpecFlags("signal", args, command);
4729
4101
  const id = encodeURIComponent(params.id);
4730
4102
  if (params.detections !== true) {
4731
4103
  const data2 = await callDataAPI(`/custom-signals/${id}`);
@@ -4918,7 +4290,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4918
4290
  }
4919
4291
  case "emotions": {
4920
4292
  const args = withStringIdFlags(flagsToArgs(flags), flags);
4921
- const params = parseCommandFlags(EmotionsSchema, args, command);
4293
+ const params = parseSpecFlags("emotions", args, command);
4922
4294
  const query2 = new URLSearchParams;
4923
4295
  if (params.days_back)
4924
4296
  query2.set("days_back", params.days_back.toString());
@@ -4946,7 +4318,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4946
4318
  if (flags["conversation-id"] !== undefined) {
4947
4319
  args.conversation_id = flags["conversation-id"];
4948
4320
  }
4949
- const params = parseCommandFlags(LazinessSchema, args, command);
4321
+ const params = parseSpecFlags("laziness", args, command);
4950
4322
  const query2 = new URLSearchParams;
4951
4323
  if (params.days_back)
4952
4324
  query2.set("days_back", params.days_back.toString());
@@ -4968,7 +4340,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4968
4340
  if (flags["conversation-id"] !== undefined) {
4969
4341
  args.conversation_id = flags["conversation-id"];
4970
4342
  }
4971
- const params = parseCommandFlags(HallucinationsSchema, args, command);
4343
+ const params = parseSpecFlags("hallucinations", args, command);
4972
4344
  const query2 = new URLSearchParams;
4973
4345
  if (params.days_back)
4974
4346
  query2.set("days_back", params.days_back.toString());
@@ -5002,7 +4374,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5002
4374
  }
5003
4375
  case "tail": {
5004
4376
  const args = flagsToArgs(flags);
5005
- const params = parseCommandFlags(TailSchema, args, command);
4377
+ const params = parseSpecFlags("tail", args, command);
5006
4378
  await runTailCommand(params, context);
5007
4379
  break;
5008
4380
  }
@@ -5027,7 +4399,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5027
4399
  break;
5028
4400
  }
5029
4401
  default:
5030
- throw new CliInputError(`Unknown command '${command}'`, 'Run "moda --help" for usage information.');
4402
+ throw unknownCommandError(command);
5031
4403
  }
5032
4404
  return 0;
5033
4405
  }
@@ -5130,6 +4502,30 @@ var commandRegistry = createCommandRegistry([
5130
4502
  name: "init",
5131
4503
  description: "Set up Moda in your project",
5132
4504
  examples: ["moda init", "moda init --sdk-integrate", "moda init --ci-cd", "moda init --autosync", "moda init --harness-rescan"],
4505
+ documentedFlags: [
4506
+ { name: "--yes", description: "Accept all defaults (non-interactive)" },
4507
+ { name: "--analyst=auto|claude|codex|cursor|local-scan", description: "Choose the harness analyst adapter" },
4508
+ { name: "--analyst-model=MODEL", description: 'Model for the claude analyst (default sonnet; "default" = the claude CLI default; env MODA_HARNESS_ANALYST_MODEL)' },
4509
+ { name: "--assist=none", description: "Disable agent fallback for prompt discovery" },
4510
+ { name: "--concern=topology|tools|prompts|evals", description: "Harness analyze: restrict the pass to one concern (env MODA_HARNESS_CONCERN, flag wins)" },
4511
+ { name: "--allow-no-agents", description: "Allow harness sync to push a graph with zero runtime agents despite detected LLM usage" },
4512
+ { name: "--remote", description: "Run harness analysis server-side (the default): upload a safe source snapshot" },
4513
+ { name: "--local", description: "Run harness analysis with a local coding agent instead of server-side" },
4514
+ { name: "--tui", description: "Show the full-screen analyst dashboard in human TTYs" },
4515
+ { name: "--no-tui", description: "Show raw external analyst output" },
4516
+ { name: "--sdk-integrate", description: "Run your coding agent to install the Moda SDK and instrument LLM calls" },
4517
+ { name: "--no-sdk-integrate", description: "Skip SDK integration (alias: --no-sdk-guide)" },
4518
+ { name: "--verification-id=ID", description: "Tag the SDK integration's test trace with this id (the onb_ id from the onboarding page)" },
4519
+ { name: "--connect-code=CODE", description: "Sign in with the one-time mcc_ code from the onboarding page instead of the browser (10 min, single use)" },
4520
+ { name: "--ci-cd", description: "Create the GitHub Actions Moda validation workflow" },
4521
+ { name: "--no-ci-cd", description: "Skip CI/CD workflow creation" },
4522
+ { name: "--autosync", description: "Create a GitHub Actions workflow that syncs prompts + skills to Moda on push to main" },
4523
+ { name: "--no-autosync", description: "Skip autosync workflow creation" },
4524
+ { name: "--harness-rescan", description: "Create a GitHub Actions workflow that re-scans the harness and syncs it on push to main" },
4525
+ { name: "--no-harness-rescan", description: "Skip harness rescan workflow creation" },
4526
+ { name: "--harness-rescan-paths=GLOBS", description: "Comma-separated path globs that scope which pushes trigger the rescan (implies --harness-rescan)" },
4527
+ { name: "--offline", description: "Run final validation offline (skip the online telemetry check)" }
4528
+ ],
5133
4529
  auth: "none",
5134
4530
  outputModes: ["human", "json", "agent"],
5135
4531
  mutability: "write",
@@ -5137,7 +4533,7 @@ var commandRegistry = createCommandRegistry([
5137
4533
  resetApiRequestCountBeforeRun: true,
5138
4534
  telemetry: "result-and-error",
5139
4535
  handler: async (context) => {
5140
- const { runInit } = await import("./index-7zqa7t5c.js");
4536
+ const { runInit } = await import("./index-6qqmjqb2.js");
5141
4537
  if (context.outputMode === "agent-stream") {
5142
4538
  context.output.writeEvent({
5143
4539
  event: "started",
@@ -5171,6 +4567,12 @@ var commandRegistry = createCommandRegistry([
5171
4567
  "moda provision --tenant-id=<org-id> --label=ci-runner --save",
5172
4568
  "KEY=$(moda provision --tenant-id <org-id> | jq -r .apiKey)"
5173
4569
  ],
4570
+ helpNotes: ['Headless: requires an existing "moda auth login" session and never prompts, even on a TTY.'],
4571
+ documentedFlags: [
4572
+ { name: "--tenant-id=ID", description: "Organization to provision (required with multiple organizations; MODA_TENANT_ID is also honored, flag wins)" },
4573
+ { name: "--label=TEXT", description: "API key label (default: machine hostname)" },
4574
+ { name: "--save", description: "Also persist the key to ~/.moda/config.json (default: print only; headless callers own storage)" }
4575
+ ],
5174
4576
  auth: "none",
5175
4577
  outputModes: ["human", "json", "agent"],
5176
4578
  mutability: "write",
@@ -5178,7 +4580,7 @@ var commandRegistry = createCommandRegistry([
5178
4580
  resetApiRequestCountBeforeRun: true,
5179
4581
  telemetry: "result-and-error",
5180
4582
  handler: async (context) => {
5181
- const { runProvision } = await import("./provision-n3r7yway.js");
4583
+ const { runProvision } = await import("./provision-wzttap58.js");
5182
4584
  return runProvision(context, {
5183
4585
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
5184
4586
  });
@@ -5621,7 +5023,8 @@ var commandRegistry = createCommandRegistry([
5621
5023
  description: "Search trace messages (keyword, semantic, or hybrid)",
5622
5024
  examples: [
5623
5025
  'moda search "billing error"',
5624
- 'moda search "refund flow" --mode=semantic --time-range=7d --limit=10'
5026
+ 'moda search "refund flow" --mode=semantic --time-range=7d --limit=10',
5027
+ 'moda search "area code" --since=2026-10-07 --until=2026-10-07'
5625
5028
  ],
5626
5029
  ...dataApiDefaults
5627
5030
  }),
@@ -5776,6 +5179,9 @@ var commandRegistry = createCommandRegistry([
5776
5179
  legacyCommand({
5777
5180
  name: "false-positive",
5778
5181
  description: "Flag a detection as a false positive with a reason: problem, problem-detection, quote, tool, laziness, hallucination, or custom-signal",
5182
+ helpNotes: [
5183
+ "Kinds: problem <problem_id> dismisses the Problem (hidden at once, logged for review); problem-detection <problem_id> marks one detection on a trace (needs --conversation-id and --attribution-id); quote <conversation_id> needs --family, --turn and --quote (from moda emotions); tool <conversation_id> needs --tool and --tool-use-id or --msg-index; laziness and hallucination <conversation_id> mark that trace; custom-signal <signal_id> needs --conversation-id and is saved as a does_not_fit label. quote, tool, laziness and hallucination marks are audit-only."
5184
+ ],
5779
5185
  examples: [
5780
5186
  'moda false-positive problem <problem_id> --reason="two unrelated tools"',
5781
5187
  'moda false-positive problem-detection <problem_id> --conversation-id=<id> --attribution-id=<uuid> --reason="refund was approved"',
@@ -5893,6 +5299,9 @@ var commandRegistry = createCommandRegistry([
5893
5299
  'moda feedback "search finds nothing for a trace I can open" --category=missing_data --conversation-id=<id>',
5894
5300
  'moda feedback "trace is about refunds, not this problem" --category=false_positive_attribution --problem-id=<id> --conversation-id=<id>'
5895
5301
  ],
5302
+ helpNotes: [
5303
+ "Any other id flag (--problem-id, --fix-id, --attribution-id, --trace-id, --span-id, --message-index, ...) is attached as a ref. Set MODA_CLI_TIPS=0 to hide the feedback tip line."
5304
+ ],
5896
5305
  ...dataApiDefaults,
5897
5306
  mutability: "write"
5898
5307
  }),
@@ -6092,7 +5501,7 @@ function classifyCliError(error) {
6092
5501
  return "auth_error";
6093
5502
  if (error instanceof ApiError && error.statusCode === 403)
6094
5503
  return "access_error";
6095
- if (error instanceof z2.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError) {
5504
+ if (error instanceof z.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError) {
6096
5505
  return "validation_error";
6097
5506
  }
6098
5507
  if (error instanceof ApiError || isApiLikeError(error)) {
@@ -6104,7 +5513,7 @@ function classifyCliError(error) {
6104
5513
  return "unknown_error";
6105
5514
  }
6106
5515
  function cliValidationReason(error) {
6107
- if (error instanceof z2.ZodError) {
5516
+ if (error instanceof z.ZodError) {
6108
5517
  const issue = error.issues[0];
6109
5518
  if (!issue)
6110
5519
  return "zod";
@@ -6131,7 +5540,7 @@ function printCliError(error) {
6131
5540
  if (error.guidance)
6132
5541
  safeWriteStderr(`${error.guidance}
6133
5542
  `);
6134
- } else if (error instanceof z2.ZodError) {
5543
+ } else if (error instanceof z.ZodError) {
6135
5544
  const issues = error.errors.map((e) => {
6136
5545
  const field = e.path.length ? e.path.join(".") : "input";
6137
5546
  return ` ${field}: ${e.message}`;
@@ -6175,6 +5584,21 @@ function printFeedbackTip(commandName, context) {
6175
5584
  ${colorOk ? `\x1B[2m${text}\x1B[0m` : text}
6176
5585
  `);
6177
5586
  }
5587
+ function unknownCommandError(command) {
5588
+ const visible = commandRegistry.all().filter((entry) => !entry.hidden);
5589
+ const names = visible.flatMap((entry) => [entry.name, ...entry.aliases ?? []]);
5590
+ const matches = closestMatches(command, names);
5591
+ const suggestion = matches.length > 0 ? ` Did you mean ${matches.map((name) => `'${name}'`).join(" or ")}?` : "";
5592
+ return new CliInputError(`Unknown command '${command}'.${suggestion}`, [
5593
+ ...matches.map((name) => `\`moda ${name} --help\``),
5594
+ "Run `moda --help` for the command list."
5595
+ ].join(" "), "unknown_command", {
5596
+ field: "<command>",
5597
+ allowed: visible.map((entry) => entry.name),
5598
+ ...matches.length > 0 ? { didYouMean: matches } : {},
5599
+ suggestedCommands: [...matches.map((name) => `moda ${name} --help`), "moda --help"]
5600
+ });
5601
+ }
6178
5602
  function printAgentCliError(command, error, mode = "agent") {
6179
5603
  const output = createCliOutput({
6180
5604
  command: command || "unknown",
@@ -6272,9 +5696,8 @@ async function dispatchParsedCommandInner(parsed, startedAt) {
6272
5696
  return 1;
6273
5697
  };
6274
5698
  const definition = commandRegistry.find(command);
6275
- if (!definition) {
6276
- return failEarly(new CliInputError(`Unknown command '${command}'`, 'Run "moda --help" for usage information.'));
6277
- }
5699
+ if (!definition)
5700
+ return failEarly(unknownCommandError(command));
6278
5701
  if (parsed.shortFlags?.length) {
6279
5702
  return failEarly(new CliInputError(`Short options are not supported (${parsed.shortFlags.join(", ")}), so nothing was run.`, `Use the long form, e.g. --dry-run, --json, --quiet. See 'moda ${command} --help'.`, "short_flag"), definition);
6280
5703
  }
@@ -6461,6 +5884,7 @@ if (isMain) {
6461
5884
  });
6462
5885
  }
6463
5886
  export {
5887
+ unknownCommandError,
6464
5888
  telemetrySubcommandNames,
6465
5889
  telemetryCommandName,
6466
5890
  stripLoneSurrogates,
@@ -6475,6 +5899,7 @@ export {
6475
5899
  parseArgs,
6476
5900
  normalizeBooleanFlags,
6477
5901
  initFlagsForContext,
5902
+ globalFlagHelpLines,
6478
5903
  flagsToArgs,
6479
5904
  dispatchParsedCommand,
6480
5905
  detectCallerAgent,