@moda-ai/cli 1.55.18 → 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 +329 -928
  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,441 +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 ISO_BOUND_MESSAGE = "must be an ISO 8601 date (2026-10-07) or datetime (2026-10-07T14:30:00Z)";
107
- var ISO_BOUND = /^\d{4}-\d{2}-\d{2}(?:[Tt ]\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:[Zz]|[+-]\d{2}:?\d{2})?)?$/;
108
- var isoBoundFlag = () => z.string().trim().regex(ISO_BOUND, ISO_BOUND_MESSAGE).optional();
109
- var OverviewSchema = z.object({
110
- days_back: daysBackFlag(7)
111
- });
112
- var ClustersSchema = z.object({
113
- parent_id: z.string().optional(),
114
- time_range: z.enum(["all", "1h", "3d", "7d", "24h", "30d", "90d"]).default("all").optional(),
115
- search: z.string().min(2).max(200).optional(),
116
- node_id: z.string().min(1).max(512).optional(),
117
- mode: z.enum(["fuzzy", "semantic", "hybrid"]).optional(),
118
- limit: z.number().min(1).max(50).optional()
119
- });
120
- var ClusterConversationsSchema = z.object({
121
- node_id: z.string(),
122
- limit: z.number().min(1).max(100).default(10).optional(),
123
- offset: z.number().min(0).default(0).optional()
124
- });
125
- var ConversationsSchema = z.object({
126
- search: z.string().optional(),
127
- cluster_id: z.string().optional(),
128
- user_id: z.string().optional(),
129
- time_range: z.enum(["all", "1h", "3d", "24h", "7d", "30d", "90d"]).default("all").optional(),
130
- since: isoBoundFlag(),
131
- until: isoBoundFlag(),
132
- environment: z.enum(["all", "development", "staging", "production"]).default("all").optional(),
133
- world_state: z.string().max(200).optional(),
134
- outcome: z.enum(["any", "positive", "negative"]).default("any").optional(),
135
- include_world_state: boolFlag(),
136
- sort: z.enum(["recent", "longest", "slowest"]).optional(),
137
- limit: z.number().min(1).max(100).default(20).optional(),
138
- offset: z.number().min(0).default(0).optional()
139
- });
140
- var WorldStateSchema = z.object({
141
- conversation_id: z.string(),
142
- summary_only: boolFlag(),
143
- event_limit: z.number().min(1).max(5000).default(2000).optional(),
144
- snapshot: boolFlag(),
145
- msg_index: z.number().min(0).max(1e5).optional(),
146
- block_index: z.number().min(0).max(1e5).optional(),
147
- segment_index: z.number().min(0).max(65535).optional(),
148
- replay: boolFlag(),
149
- format: z.enum(["frames", "fold-inputs"]).optional(),
150
- message_count: z.number().min(1).max(1e6).optional()
151
- });
152
- var ContextSchema = z.object({
153
- conversation_id: z.string().min(1),
154
- msg_index: z.number().int().min(0).optional(),
155
- window: z.number().int().min(0).optional(),
156
- metadata_only: boolFlag(),
157
- all: boolFlag(),
158
- from: z.number().int().min(0).optional(),
159
- max_messages: z.number().int().min(1).max(5000).optional(),
160
- ids_from: z.string().min(1).optional()
161
- });
162
- var FrustrationsSchema = z.object({
163
- days_back: daysBackFlag(7),
164
- limit: z.number().min(1).max(20).default(10).optional(),
165
- offset: z.number().min(0).default(0).optional(),
166
- include_window: boolFlag(),
167
- window: z.number().min(1).max(5).default(1).optional(),
168
- user_id: z.string().min(1).max(256).optional(),
169
- conversation_id: z.string().min(1).max(256).optional()
170
- });
171
- var ToolFailuresSchema = z.object({
172
- days_back: daysBackFlag(7)
173
- });
174
- var ProblemsSchema = z.object({
175
- days_back: daysBackFlag(30),
176
- limit: z.number().min(1).max(25).default(25).optional()
177
- });
178
- var REMAINDER_FAMILIES = [
179
- "tool_failure",
180
- "emotion",
181
- "laziness",
182
- "hallucination",
183
- "prm_dip",
184
- "custom_signal",
185
- "conversation_reader"
186
- ];
187
- var ProblemsRemainderSchema = z.object({
188
- days_back: daysBackFlag(30),
189
- limit: z.number().min(1).max(25).default(25).optional(),
190
- family: z.enum(REMAINDER_FAMILIES).optional(),
191
- cursor: z.string().min(1).max(4096).optional()
192
- });
193
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
194
- var ProblemImpactSchema = z.object({
195
- node_id: z.string().min(1).max(256).optional(),
196
- problem_id: z.string().regex(UUID_RE).optional(),
197
- run_id: z.string().min(1).max(256).optional(),
198
- 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),
199
- mode: z.enum(["metrics", "trend", "evidence", "catalog", "overview", "affected-use-cases", "trace-use-cases"]).default("metrics"),
200
- to: z.string().datetime({ precision: 3 }).optional(),
201
- cursor: z.string().min(1).optional(),
202
- conversation_ids: z.string().transform((value, ctx) => {
203
- try {
204
- return z.array(z.string().min(1).max(512)).min(1).max(25).parse(JSON.parse(value));
205
- } catch {
206
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Use a JSON array of 1–25 conversation IDs" });
207
- return z.NEVER;
208
- }
209
- }).optional()
210
- }).refine((p) => p.mode !== "trace-use-cases" || p.problem_id && p.conversation_ids, {
211
- message: "Trace use cases require --problem-id and --conversation-ids"
212
- }).refine((p) => p.node_id || p.problem_id || ["catalog", "overview"].includes(p.mode), {
213
- message: "Select --node-id or --problem-id, or use --mode=catalog/overview"
214
- }).refine((p) => !p.cursor || p.mode === "evidence" && p.to && p.run_id, {
215
- message: "An evidence cursor requires --mode=evidence, --to, and --run-id from the previous response"
216
- });
217
- var PROBLEM_FAMILIES = REMAINDER_FAMILIES;
218
- var PROBLEM_DOORS = ["rubric_match", "local_causal_chain"];
219
- var ProblemSchema = z.object({
220
- id: z.string().min(1),
221
- evidence: boolFlag(),
222
- reports: boolFlag(),
223
- traces: boolFlag(),
224
- conversations: boolFlag(),
225
- feedback: boolFlag(),
226
- full: boolFlag(),
227
- limit: z.number().min(1).max(50).optional(),
228
- cursor: z.string().optional(),
229
- family: z.enum(PROBLEM_FAMILIES).optional(),
230
- door: z.enum(PROBLEM_DOORS).optional()
231
- });
232
- var PROBLEM_FEEDBACK_ACTIONS = [
233
- "mark_fixed",
234
- "dismiss",
235
- "flag_attribution",
236
- "rename"
237
- ];
238
- var ProblemFeedbackSchema = z.object({
239
- id: z.string().min(1),
240
- action: z.enum(PROBLEM_FEEDBACK_ACTIONS),
241
- reason: z.string().max(2000).optional(),
242
- attribution_id: z.string().max(64).optional(),
243
- new_name: z.string().max(255).optional(),
244
- actor: z.string().max(255).optional()
245
- });
246
- var ProblemLinearFileSchema = z.object({
247
- id: z.string().min(1),
248
- issue: z.string().max(2048).optional(),
249
- team_id: z.string().max(255).optional(),
250
- title: z.string().optional(),
251
- priority: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).max(4).optional())
252
- });
253
- var SignalSchema = z.object({
254
- id: z.string().min(1).max(255),
255
- detections: boolFlag(),
256
- days_back: daysBackFlag(),
257
- limit: z.number().min(1).max(20).optional(),
258
- offset: z.number().min(0).max(1e4).optional()
259
- });
260
- var SIGNAL_LABELS = ["fits", "does_not_fit"];
261
- var SignalLabelSchema = z.object({
262
- id: z.string().min(1).max(255),
263
- conversation_id: z.string().min(1).max(255),
264
- label: z.enum(SIGNAL_LABELS),
265
- note: z.string().max(2000).optional(),
266
- msg_index: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).optional()),
267
- msg_dedup_token: z.string().min(1).max(200).optional()
268
- });
269
- var DETECTION_VERDICTS = ["correct", "false_positive", "clear"];
270
- var DetectionReviewSchema = z.object({
271
- id: z.string().regex(UUID_RE, "Problem id must be a canonical UUID"),
272
- conversation_id: z.string().min(1).max(255),
273
- attribution_id: z.string().regex(UUID_RE, "Attribution id must be a UUID"),
274
- verdict: z.enum(DETECTION_VERDICTS),
275
- note: z.string().max(2000).optional()
276
- });
277
- var FALSE_POSITIVE_KINDS = ["problem", "problem-detection", "quote", "tool", "laziness", "hallucination", "custom-signal"];
278
- var FalsePositiveSchema = z.object({
279
- kind: z.enum(FALSE_POSITIVE_KINDS),
280
- target: z.string().min(1).max(255),
281
- undo: z.boolean(),
282
- reason: z.string().max(2000).optional(),
283
- conversation_id: z.string().min(1).max(255).optional(),
284
- attribution_id: z.string().regex(UUID_RE, "Attribution id must be a UUID").optional(),
285
- family: z.string().regex(/^[a-z_]{1,64}$/, "Family must be a lowercase emotion family").optional(),
286
- turn: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).optional()),
287
- quote: z.string().min(1).max(4000).optional(),
288
- tool: z.string().min(1).max(255).optional(),
289
- tool_use_id: z.string().min(1).max(255).optional(),
290
- msg_index: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).optional()),
291
- msg_dedup_token: z.string().min(1).max(200).optional()
292
- }).superRefine((v, ctx) => {
293
- const need = (ok, message) => {
294
- if (!ok)
295
- ctx.addIssue({ code: z.ZodIssueCode.custom, message });
296
- };
297
- if (v.kind === "problem") {
298
- need(UUID_RE.test(v.target), "Problem id must be a canonical UUID");
299
- need(!v.undo, "A problem dismissal cannot be undone from the CLI");
300
- }
301
- if (v.kind === "problem-detection") {
302
- need(UUID_RE.test(v.target), "Problem id must be a canonical UUID");
303
- need(v.conversation_id, "--conversation-id is required for problem-detection");
304
- need(v.attribution_id, "--attribution-id is required for problem-detection");
305
- }
306
- if (v.kind === "quote") {
307
- need(v.family && v.turn !== undefined && v.quote, "--family, --turn and --quote are required for quote (copy them from moda emotions)");
308
- }
309
- if (v.kind === "tool") {
310
- need(v.tool, "--tool is required for tool (the failing tool name)");
311
- need(v.tool_use_id || v.msg_index !== undefined, "--tool-use-id or --msg-index is required for tool (from moda tool-failure-detail)");
312
- }
313
- if (v.kind === "custom-signal") {
314
- need(v.conversation_id, "--conversation-id is required for custom-signal");
315
- }
316
- });
317
- var EMOTION_FAMILIES = [
318
- "frustration",
319
- "disapproval",
320
- "sadness",
321
- "confusion",
322
- "anxiety",
323
- "trust",
324
- "positive"
325
- ];
326
- var EmotionsSchema = z.object({
327
- days_back: daysBackFlag(7),
328
- limit: z.number().min(1).max(20).default(10).optional(),
329
- offset: z.number().min(0).max(1e4).optional(),
330
- family: z.enum(EMOTION_FAMILIES).optional(),
331
- user_id: z.string().min(1).max(256).optional(),
332
- conversation_id: z.string().min(1).max(256).optional(),
333
- include_window: boolFlag()
334
- });
335
- var HallucinationsSchema = z.object({
336
- days_back: daysBackFlag(7),
337
- limit: z.number().min(1).max(20).default(10).optional(),
338
- offset: z.number().min(0).max(1e4).optional(),
339
- conversation_id: z.string().max(200).optional(),
340
- kind: z.enum(["contradicted", "verified"]).optional()
341
- });
342
- var LAZINESS_FAMILIES = [
343
- "omission_comment",
344
- "omission_phrase",
345
- "stub_body",
346
- "refusal_prefix",
347
- "deflection",
348
- "data_quality_truncation",
349
- "promise_no_delivery",
350
- "capability_refusal_here",
351
- "capability_refusal_verb",
352
- "error_admission",
353
- "irreversibility",
354
- "stall_recheck",
355
- "diy_handoff",
356
- "tool_selection",
357
- "completion",
358
- "code_artifact",
359
- "repeated_tool_call",
360
- "target_overshoot",
361
- "data_regression"
362
- ];
363
- var LazinessSchema = z.object({
364
- days_back: daysBackFlag(7),
365
- limit: z.number().min(1).max(50).default(10).optional(),
366
- offset: z.number().min(0).max(1e4).optional(),
367
- conversation_id: z.string().max(200).optional(),
368
- family: z.enum(LAZINESS_FAMILIES).optional()
369
- });
370
- var StepScoresSchema = z.object({
371
- conversation_id: z.string().min(1)
372
- });
373
- var TAIL_SIGNALS = ["traces", "conversations", "emotions", "all"];
374
- var TailSchema = z.object({
375
- interval: z.number().min(5).max(3600).default(15).optional(),
376
- signal: z.enum(TAIL_SIGNALS).default("traces").optional(),
377
- once: boolFlag(),
378
- limit: z.number().min(1).max(50).default(20).optional(),
379
- max_events: z.number().min(1).max(1e5).optional(),
380
- full_scan: boolFlag()
381
- });
382
- var ToolFailureDetailSchema = z.object({
383
- tool_name: z.string(),
384
- subtype: z.string().optional(),
385
- days_back: daysBackFlag(7),
386
- limit: z.number().min(1).max(20).default(5).optional(),
387
- offset: z.number().min(0).default(0).optional(),
388
- include_window: boolFlag(),
389
- compact: boolFlag(),
390
- window: z.number().min(1).max(5).default(1).optional()
391
- });
392
- var AuditSchema = z.object({
393
- id: z.string().min(1),
394
- kind: z.enum(["auto", "trace", "conversation"]).default("auto").optional(),
395
- include_raw: boolFlag(),
396
- include_bodies: boolFlag(),
397
- limit: z.number().min(1).max(1000).default(200).optional(),
398
- cursor: z.string().min(1).max(512).optional(),
399
- ids_from: z.string().min(1).optional()
400
- });
401
- var TIME_RANGES = ["all", "1h", "3d", "7d", "24h", "30d", "90d"];
402
- var SEARCH_MODES = ["keyword", "semantic", "hybrid"];
403
- var SearchSchema = z.object({
404
- q: z.string().min(1).max(500),
405
- mode: z.enum(SEARCH_MODES).default("hybrid").optional(),
406
- user_id: z.string().optional(),
407
- conversation_id: z.string().min(1).max(256).optional(),
408
- time_range: z.enum(TIME_RANGES).default("all").optional(),
409
- since: isoBoundFlag(),
410
- until: isoBoundFlag(),
411
- limit: z.number().min(1).max(100).default(20).optional(),
412
- include_tool_io: boolFlag(),
413
- offset: z.number().min(0).max(1e4).optional()
414
- });
415
-
416
- // ../../packages/database/src/agent-feedback.ts
417
- var FEEDBACK_CATEGORIES = [
418
- "bad_cluster_label",
419
- "mismatched_frustration",
420
- "missing_data",
421
- "noisy_data",
422
- "wrong_tool_failure",
423
- "incorrect_loop",
424
- "api_quirk",
425
- "false_positive_attribution",
426
- "misrouted_fix",
427
- "harness_bug",
428
- "other"
429
- ];
430
- var FEEDBACK_SEVERITIES = ["info", "low", "medium", "high"];
431
- var DEFAULT_FEEDBACK_CATEGORY = "other";
432
- var RAW_FEEDBACK_CATEGORY_MAX = 64;
433
- function isFeedbackCategory(value) {
434
- return typeof value === "string" && FEEDBACK_CATEGORIES.includes(value);
435
- }
436
- function normalizeFeedbackCategory(value) {
437
- if (value === undefined || value === null || value === "")
438
- return { category: DEFAULT_FEEDBACK_CATEGORY };
439
- if (isFeedbackCategory(value))
440
- return { category: value };
441
- const raw = String(value).trim().slice(0, RAW_FEEDBACK_CATEGORY_MAX);
442
- return raw ? { category: DEFAULT_FEEDBACK_CATEGORY, raw_category: raw } : { category: DEFAULT_FEEDBACK_CATEGORY };
443
- }
444
-
445
- // src/feedback.ts
446
- var FEEDBACK_FLAGS = ["category", "severity", "note", "cluster-id", "conversation-id", "run-id", "tool-name"];
447
- 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]";
448
- var NOTE_MAX = 4000;
449
- var REF_VALUE_MAX = 256;
450
- var REF_FLAG_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*-(?:id|ids|index|token)$/;
451
- var REF_FLAG_WORDS = new Set(["turn", "tool", "family", "kind"]);
452
- function isFeedbackRefFlag(flag) {
453
- return REF_FLAG_PATTERN.test(flag) || REF_FLAG_WORDS.has(flag);
454
- }
455
- function feedbackCategoryHelp(indent = 35, width = 100) {
456
- const lines = [];
457
- let line = "";
458
- FEEDBACK_CATEGORIES.forEach((category, index) => {
459
- const piece = index < FEEDBACK_CATEGORIES.length - 1 ? `${category}|` : `${category} (default other)`;
460
- if (line && indent + line.length + piece.length > width) {
461
- lines.push(line);
462
- line = "";
463
- }
464
- line += piece;
465
- });
466
- lines.push(line);
467
- return lines.join(`
468
- ${" ".repeat(indent)}`);
469
- }
470
- function buildFeedbackRequest(positionals, flags, bareFlags) {
471
- const isBare = (flag) => bareFlags ? bareFlags.includes(flag) : flags[flag] === "true";
472
- const flagNote = flags.note !== undefined && !isBare("note") ? flags.note.trim() : "";
473
- const note = [positionals.join(" ").trim(), flagNote].filter(Boolean).join(`
474
- `);
475
- if (note === "")
476
- throw new CliInputError("<note> is required", FEEDBACK_USAGE);
477
- if (note.length > NOTE_MAX) {
478
- throw new CliInputError(`<note> is ${note.length} characters; the limit is ${NOTE_MAX}.`, FEEDBACK_USAGE);
479
- }
480
- const severity = flags.severity ?? "low";
481
- if (!FEEDBACK_SEVERITIES.includes(severity)) {
482
- throw new CliInputError(`Invalid --severity '${severity}'. Valid severities: ${FEEDBACK_SEVERITIES.join(", ")}.`, FEEDBACK_USAGE);
483
- }
484
- const refs = {};
485
- for (const [flag, value] of Object.entries(flags)) {
486
- if (flag === "category" || flag === "severity" || flag === "note")
487
- continue;
488
- if (!FEEDBACK_FLAGS.includes(flag) && !isFeedbackRefFlag(flag))
489
- continue;
490
- const trimmed = value.trim();
491
- if (value === "true" || trimmed === "") {
492
- throw new CliInputError(`--${flag} needs a value, e.g. --${flag}=<id>.`, FEEDBACK_USAGE);
493
- }
494
- if (trimmed.length > REF_VALUE_MAX) {
495
- throw new CliInputError(`--${flag} is ${trimmed.length} characters; the limit is ${REF_VALUE_MAX}.`, FEEDBACK_USAGE);
496
- }
497
- refs[flag.replace(/-/g, "_")] = trimmed;
498
- }
499
- const warnings = [];
500
- const { category, raw_category: rawCategory } = normalizeFeedbackCategory(flags.category);
501
- if (rawCategory !== undefined) {
502
- refs.raw_category = rawCategory;
503
- warnings.push(`Unknown category '${rawCategory}': sent as 'other' with refs.raw_category. ` + `Valid categories: ${FEEDBACK_CATEGORIES.join(", ")}.`);
504
- }
505
- const hint = dedicatedCommandHint(category, rawCategory);
506
- if (hint)
507
- warnings.push(hint);
508
- return { category, severity, note, refs, warnings };
509
- }
510
- var MISROUTE_CATEGORIES = new Set(["false_positive_attribution", "misrouted_fix"]);
511
- var MISROUTE_WORDS = /attribut|misrout|false[\s_-]?positive|wrong[\s_-]?(?:problem|fix)/i;
512
- function dedicatedCommandHint(category, rawCategory) {
513
- if (!MISROUTE_CATEGORIES.has(category) && !(rawCategory && MISROUTE_WORDS.test(rawCategory)))
514
- return;
515
- 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).";
516
- }
517
119
 
518
120
  // src/replays.ts
519
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;
@@ -713,7 +315,7 @@ var SEARCH_SURFACE_BY_COMMAND = {
713
315
  "world-state": "world_state",
714
316
  context: "context"
715
317
  };
716
- var SEARCH_MODES2 = ["keyword", "semantic", "hybrid"];
318
+ var SEARCH_MODES = ["keyword", "semantic", "hybrid"];
717
319
  function termCount(query2) {
718
320
  return query2.trim().split(/\s+/).filter(Boolean).length;
719
321
  }
@@ -745,7 +347,7 @@ function buildSearchAdoptionTelemetry(input) {
745
347
  }
746
348
  if (command === "search") {
747
349
  const requested = (flags.mode ?? "").toLowerCase();
748
- adoption.search_mode_requested = SEARCH_MODES2.includes(requested) ? requested : "hybrid";
350
+ adoption.search_mode_requested = SEARCH_MODES.includes(requested) ? requested : "hybrid";
749
351
  }
750
352
  if (command === "context") {
751
353
  adoption.used_msg_index = flags["msg-index"] !== undefined || flags["message-index"] !== undefined ? 1 : 0;
@@ -1598,12 +1200,7 @@ var PROBLEMS_SUBCOMMAND_HELP = [
1598
1200
  name: "remainder",
1599
1201
  description: "Signals no Problem explains yet, grouped by family (read-only)",
1600
1202
  usage: "moda problems remainder [--family=<family>] [--days-back=N] [--limit=N] [--cursor=<token>]",
1601
- flags: [
1602
- { name: "--family=<family>", description: "One of tool_failure, emotion, laziness, hallucination, prm_dip, custom_signal, conversation_reader (frustration is under emotion)." },
1603
- { name: "--days-back=<n>", description: "Window in days, 1-90 (default 30)." },
1604
- { name: "--limit=<n>", description: "Groups per page, 1-25 (default 25)." },
1605
- { name: "--cursor=<token>", description: "The next_cursor from the previous page, verbatim." }
1606
- ],
1203
+ flags: subcommandHelpFlags(COMMAND_FLAG_SPECS.problems.subcommands.remainder),
1607
1204
  examples: ["moda problems remainder", "moda problems remainder --family=emotion --days-back=7"]
1608
1205
  }
1609
1206
  ];
@@ -1813,6 +1410,23 @@ var agentErrorSchema = {
1813
1410
  message: { type: "string" },
1814
1411
  cause: { type: "string" },
1815
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
+ },
1816
1430
  input_request: agentInputRequestSchema,
1817
1431
  auth: agentAuthSchema,
1818
1432
  blocking: { type: "boolean" }
@@ -2165,7 +1779,8 @@ function buildManifest(commands) {
2165
1779
  auth: command.auth,
2166
1780
  ...command.authNote ? { auth_note: command.authNote } : {},
2167
1781
  mutability: command.mutability,
2168
- exit_codes: exitCodesForCommand(command.name)
1782
+ exit_codes: exitCodesForCommand(command.name),
1783
+ ...commandFlagFields(command)
2169
1784
  })),
2170
1785
  concepts: [
2171
1786
  { term: "tenant", meaning: "A Moda organization/workspace that owns data, prompts, skills, and API keys." },
@@ -2197,6 +1812,29 @@ function renderManifestHuman(manifest) {
2197
1812
  ].join(`
2198
1813
  `);
2199
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
+ }
2200
1838
  function event(name, when, terminal, deprecated = false) {
2201
1839
  return { name, event_version: 1, when, terminal, ...deprecated ? { deprecated: true } : {} };
2202
1840
  }
@@ -2212,46 +1850,46 @@ function exitCodesForCommand(command) {
2212
1850
  import { fileURLToPath } from "url";
2213
1851
  import { realpathSync } from "fs";
2214
1852
  async function runPromptsCommand(...args) {
2215
- return (await import("./prompts-2r756vtd.js")).runPromptsCommand(...args);
1853
+ return (await import("./prompts-1tkhrxkq.js")).runPromptsCommand(...args);
2216
1854
  }
2217
1855
  async function runSkillsCommand(...args) {
2218
- return (await import("./skills-fed17et3.js")).runSkillsCommand(...args);
1856
+ return (await import("./skills-d35nnm66.js")).runSkillsCommand(...args);
2219
1857
  }
2220
1858
  async function runFixCommand(...args) {
2221
- return (await import("./fix-q8er8egx.js")).runFixCommand(...args);
1859
+ return (await import("./fix-9fmy6p2x.js")).runFixCommand(...args);
2222
1860
  }
2223
1861
  async function runFixesCommand(...args) {
2224
- return (await import("./fix-q8er8egx.js")).runFixesCommand(...args);
1862
+ return (await import("./fix-9fmy6p2x.js")).runFixesCommand(...args);
2225
1863
  }
2226
1864
  async function runHarnessCommand(...args) {
2227
- return (await import("./harness-v9s0k9s7.js")).runHarnessCommand(...args);
1865
+ return (await import("./harness-xvg6ws6x.js")).runHarnessCommand(...args);
2228
1866
  }
2229
1867
  async function runSyncCommand(...args) {
2230
- return (await import("./sync-r4tncne4.js")).runSyncCommand(...args);
1868
+ return (await import("./sync-n2psdffz.js")).runSyncCommand(...args);
2231
1869
  }
2232
1870
  async function runRegistryCommand(...args) {
2233
- return (await import("./registry-5v63ga01.js")).runRegistryCommand(...args);
1871
+ return (await import("./registry-atqyb5fa.js")).runRegistryCommand(...args);
2234
1872
  }
2235
1873
  async function runDoctorCommand(...args) {
2236
- return (await import("./doctor-kg0yq1wf.js")).runDoctorCommand(...args);
1874
+ return (await import("./doctor-mx6jf435.js")).runDoctorCommand(...args);
2237
1875
  }
2238
1876
  async function runStatusCommand(...args) {
2239
- return (await import("./doctor-kg0yq1wf.js")).runStatusCommand(...args);
1877
+ return (await import("./doctor-mx6jf435.js")).runStatusCommand(...args);
2240
1878
  }
2241
1879
  async function runAuthCommand(...args) {
2242
- return (await import("./profile-commands-88sdwzbg.js")).runAuthCommand(...args);
1880
+ return (await import("./profile-commands-kmmd9y86.js")).runAuthCommand(...args);
2243
1881
  }
2244
1882
  async function runConfigCommand(...args) {
2245
- return (await import("./profile-commands-88sdwzbg.js")).runConfigCommand(...args);
1883
+ return (await import("./profile-commands-kmmd9y86.js")).runConfigCommand(...args);
2246
1884
  }
2247
1885
  async function runProfilesCommand(...args) {
2248
- return (await import("./profile-commands-88sdwzbg.js")).runProfilesCommand(...args);
1886
+ return (await import("./profile-commands-kmmd9y86.js")).runProfilesCommand(...args);
2249
1887
  }
2250
1888
  async function runAgentCommand(...args) {
2251
- return (await import("./agent-cha3kg9d.js")).runAgentCommand(...args);
1889
+ return (await import("./agent-mj622k8s.js")).runAgentCommand(...args);
2252
1890
  }
2253
1891
  async function runProductionCommand(...args) {
2254
- return (await import("./production-intelligence-k36jsvqx.js")).runProductionCommand(...args);
1892
+ return (await import("./production-intelligence-dbe9dmc5.js")).runProductionCommand(...args);
2255
1893
  }
2256
1894
  function parseArgs(argv) {
2257
1895
  const args = argv.slice(2);
@@ -2456,403 +2094,101 @@ function buildResumeCommand(command, flags) {
2456
2094
  function printHelp() {
2457
2095
  console.log(`Usage: moda <command> [options]
2458
2096
 
2459
- Commands:
2460
- init Set up Moda in your project
2461
- provision Headless tenant + API key provisioning (JSON credentials on stdout)
2462
- status Show concise local Moda setup status
2463
- manifest Describe the CLI machine protocol and commands
2464
- doctor Diagnose local Moda setup and data flow
2465
- auth login Authenticate with Moda (browser)
2466
- auth login --api-key Non-interactive: validate MODA_API_KEY (or --api-key=<key>) and save it
2467
- auth status Show auth state for both credentials (exit 4 when neither is usable); --online probes the API
2468
- auth token Print the raw bearer token for $(moda auth token)
2469
- auth api-key Print the saved API key for $(moda auth api-key)
2470
- auth logout Clear cached Moda auth
2471
- auth whoami Show the authenticated Moda identity (session or API key)
2472
- profiles list List local Moda profiles
2473
- profiles use <name> Switch active Moda profile
2474
- profiles create <name> Create or update a local Moda profile
2475
- profiles doctor [name] Validate a local Moda profile
2476
- config show Show resolved Moda config
2477
- harness analyze Produce a cited structured harness report
2478
- harness pull Fetch a server-side analyze run (status, or result when done)
2479
- harness validate-report Validate .moda/harness-report.json citations
2480
- harness approve Approve a validated harness report for sync
2481
- harness scan Discover local runtime agents and write .moda/harness.json
2482
- harness candidates Static (no-LLM) harness candidate pre-pass with file:line citations
2483
- harness sync Sync the local harness graph to Moda Cloud
2484
- harness delete <id-or-key> Permanently delete a synced harness from Moda Cloud
2485
- harness list|show|versions|diff List synced harnesses, show one, its versions, or a version diff
2486
- harness register [name] Bundle this repo for Replay Environments and upload it (--dry-run to review)
2487
- harness registration list|status List registrations, or show one with what Moda still needs
2488
- harness agents List detected runtime agents and families
2489
- harness explain Explain the discovered harness graph
2490
- agent context Emit local Moda context for coding agents
2491
- agent next-action Emit prioritized next commands for agents
2492
- 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
2493
2108
  investigate Rank production issues (tool failures, frustrations, top Problems)
2494
2109
  failures Tool failures only, ranked (no frustrations or Problems)
2495
- ask "question" Ask Moda a production/harness question
2496
- sync Sync the local harness graph to Moda Cloud
2497
- sync harness Sync the local harness graph to Moda Cloud
2498
- sync prompts Sync prompt versions to Moda Cloud
2499
- doctor --json Emit structured diagnostic checks
2500
- status --json Emit concise setup state
2501
- manifest --json Emit the CLI machine protocol manifest
2502
- overview Harness health briefing with production signals
2503
- clusters Browse topic cluster hierarchy
2504
- cluster-traces <node_id> List traces in a cluster
2505
- traces Search and filter traces (agent runs)
2506
- traces --sort=longest Sort traces: recent (default), longest, slowest
2110
+ ask "<question>" Ask Moda a production question (one paid agent run)
2507
2111
  search "<query>" Search trace messages (keyword/semantic/hybrid)
2508
- world-state <conversation_id> Get a trace's world state (slots/threads/events)
2509
- context <conversation_id> Get windowed trace context (--metadata-only: summary + counts only)
2510
- 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
2511
2114
  context <id>[@N] <id>[@N] ... Batch: up to 25 traces in one call (or --ids-from=-|<file>)
2512
2115
  audit <conversation_id|trace_id> Raw span audit (spans, hierarchy, orphans, duplicates)
2513
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, ...)
2514
2125
  frustrations Frustration detections (same data as emotions --family=frustration)
2515
- emotions Multi-family emotion detections (frustration, disapproval, sadness, confusion, anxiety, trust, positive)
2516
- hallucinations Grounding detections: contradicted/verified outputs with rule breakdown
2126
+ hallucinations Grounding detections: contradicted/verified outputs
2517
2127
  laziness Laziness detections per trace (repeated calls, premature handoffs, ...)
2518
- tool-failures Get tool failure overview
2519
- 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:
2520
2132
  problems Rank cross-signal Problems by root cause (what to fix first)
2521
- problems remainder Signals no Problem explains yet (--family, --cursor)
2522
- problem-impact Live problem/use-case impact (--node-id, --problem-id, --mode, --days-back)
2523
- 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
2524
2135
  problem-feedback <problem_id> Mark a Problem fixed, dismiss, rename, or flag a bad attribution
2525
- problem-reopen <problem_id> Reopen a Problem marked fixed (--reason)
2526
- false-positive <kind> <target> Mark any detection as a false positive, optional --reason (problem, problem-detection, quote, tool, laziness, hallucination, custom-signal)
2527
- false-positives [conv_id] Current false-positive marks: all (--kind, --all, --limit) or one trace
2528
- problem-linear <problem_id> Show the Linear issue linked to a Problem (key, state, URL)
2529
- 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
2530
2139
  detection-reviews <conv_id> Problem detections on a trace with their review state
2531
- detection-review <problem_id> Mark a problem detection correct, a false positive, or clear the review
2532
- 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
2533
2144
  signal <signal_id> One custom signal, or --detections for its recent hits
2534
- signals create|update|activate|pause|delete ...
2535
- Manage custom signals (also draft, examples, refine, revise,
2536
- proposals, accept, reject, search, preview); writes take --dry-run
2537
- users / user <user_id> End users with health and activity (the dashboard Users page)
2538
2145
  trace-signals <conversation_id> Custom signal hits on one trace
2539
2146
  signal-label <signal_id> Label a trace fits / does_not_fit (false positive) for a signal
2540
- tail Live-tail new traces/detections as NDJSON (one line per item)
2541
2147
  feedback "<note>" Flag wrong/missing data or CLI quirks to the Moda team
2542
2148
 
2543
- Legacy aliases (same behavior): conversations = traces,
2544
- cluster-conversations = cluster-traces, --conversations = --traces,
2545
- --signal=conversations = --signal=traces. <conversation_id> is the trace ID.
2546
-
2547
- Prompt management:
2548
- prompts init Create .moda/prompts.yml (version 2: prompt_paths + sources)
2549
- prompts status Show local prompt changes; warns on globs that match nothing
2550
- prompts diff Only changed/new/deleted prompts since last sync
2551
- prompts migrate [--dry-run] Rewrite a version 1 .moda/prompts.yml to version 2
2552
- prompts sync Analyze prompt sources and upload versions
2553
- prompts sync --watch Upload again when prompt files change
2554
- prompts list|show|proposals|usage|replay-runs|decide
2555
- Read the prompt registry; decide merges/rejects a proposal
2556
- prompts promote <key> Move a dev/staging/prod label
2557
- prompts ab Run a judged prompt A/B replay experiment
2558
- prompts propose Revise a prompt from a run's failures (--gate to auto-A/B, --promote-on-win)
2559
-
2560
- Replays (read-only results):
2561
- replays sets List replay sets
2562
- replays runs <set_id> Run history for a set (every status)
2563
- replays run <set_id> <run_id> One run: per-case and per-seed verdicts, playout count
2564
- replays playouts <set_id> <run_id>
2565
- Playouts per case/arm/seed (--transcript inlines messages and tool calls)
2566
- replays playout <set_id> <run_id> <playout_id>
2567
- One playout transcript
2568
-
2569
- Skills:
2570
- skills gen Kick off tenant-wide skill generation
2571
- skills status [run-id] Show a generation run's status, outcome, and recent events (default: latest run)
2572
- skills pull Pull tenant-generated skills into .claude/skills (and .cursor/rules)
2573
- skills install <id...> Install bundled integration guides into .claude/skills (--list to browse)
2574
- skills pull --status=proposed Include not-yet-promoted skills (default: approved)
2575
- skills sync Push local .claude/skills/**/SKILL.md up to Moda
2576
- skills sync --dry-run Show what would be pushed without writing
2577
- skills list|show|policy List pushed skills, show one, or set --live/--local
2578
- registry push Push prompts, skills, tools, and agent wiring from one JSON manifest
2579
-
2580
- Options:
2581
- --help Show this help message
2582
- --version Show version number
2583
- --json-schemas Print JSON Schemas for the agent output contract
2584
-
2585
- Common flags (a command rejects any it does not take; see 'moda <command> --help'):
2586
- --days-back=N Whole days to look back, 1-90 (overview, problems, emotions, laziness, tool-failures, ...)
2587
- --time-range=RANGE Window for traces, search, clusters instead (all|1h|3d|7d|24h|30d|90d)
2588
- --limit=N Maximum results to return (users: alias of --page-size)
2589
- --offset=N Number of results to skip (paged lists)
2590
- --profile=NAME Use a named local Moda profile
2591
- --json Emit machine-readable JSON
2592
- --agent Emit schema-versioned agent JSON
2593
- --stream With --agent, emit NDJSON agent events
2594
- --human Force human prose (overrides auto-detection)
2595
- --no-stream Disable live ask progress (buffered request)
2596
-
2597
- Output auto-detection (no flags needed):
2598
- Piped/redirected stdout, CI, or an agent env (CLAUDECODE/CURSOR/MODA_AGENT)
2599
- => schema-versioned agent JSON. An interactive terminal => human prose.
2600
- Override with the flags above or MODA_FORMAT=human|json|agent|agent-stream.
2601
- Exit codes: 0 ok, 1 error (errors[0].code says which, e.g. not_found), 3 degraded (local fallback),
2602
- 4 auth required (no key or key rejected), 5 input required, 130 cancelled.
2603
- --dry-run Show the planned mutation when supported
2604
- --yes Accept explicit automation defaults
2605
- --tui Force the human analyst dashboard when supported
2606
- --no-tui Show raw analyst stream instead of dashboard
2607
- --no-update-check Skip the daily new-version check (or MODA_CLI_UPDATE_CHECK=0)
2608
-
2609
- Traces flags:
2610
- --search=TEXT Ranked trace search (hybrid when embeddings exist, else keyword)
2611
- --world-state=KEYWORDS Match world-state content (slots + durable profile); comma = AND
2612
- --outcome=any|positive|negative Filter by trace outcome (trajectory + frustration)
2613
- --include-world-state Attach each result's world-state summary
2614
- --user-id=ID Filter to a single user
2615
- --environment=ENV Filter by environment (all|development|staging|production)
2616
- --since=DATE --until=DATE Absolute UTC bounds: ISO date or datetime, inclusive; a date --until covers that whole day
2617
-
2618
- Search flags:
2619
- --mode=keyword|semantic|hybrid Search mode (default hybrid)
2620
- --user-id=ID Filter to a single user
2621
- --conversation-id=ID Search inside one trace only
2622
- --time-range=RANGE Time range filter (all|1h|3d|7d|24h|30d|90d)
2623
- --since=DATE --until=DATE Absolute UTC bounds: ISO date or datetime, inclusive; a date --until covers that whole day
2624
- --limit=N Maximum results to return (1-100, default 20)
2625
-
2626
- World-state flags:
2627
- --summary-only Return segment summaries only (omit the event stream)
2628
- --event-limit=N Max world-state events to return (1-5000, default 2000)
2629
- --snapshot Folded slots at an exact tick (what the agent believed at that turn)
2630
- --msg-index=N --block-index=M Snapshot tick (defaults 0; --segment-index=K scopes to a segment)
2631
- --replay State-over-time replay; frames mode REQUIRES --message-count=N
2632
- --format=frames|fold-inputs Replay format (default frames)
2633
- --message-count=N Number of frames to fold (frames mode)
2634
-
2635
- Emotions flags:
2636
- --family=F frustration|disapproval|sadness|confusion|anxiety|trust|positive
2637
- --days-back=N --limit=N Window 1-90 (default 7); page size 1-20 (default 10)
2638
- --offset=N Skip N detections (0-10000)
2639
- --include-window Keep each detection's conversation window in agent output
2640
- (also frustrations; omitted by default, use context_command)
2641
-
2642
- Laziness flags:
2643
- --family=F One laziness family (e.g. omission_phrase, stub_body, deflection, completion, tool_selection)
2644
- --conversation-id=ID One trace's detections
2645
- --days-back=N --limit=N Window 1-90 (default 7); page size 1-50 (default 10)
2646
-
2647
- Hallucinations flags:
2648
- --kind=contradicted|verified Narrow the detections list
2649
- --conversation-id=ID Scope summary + list to one trace ID
2650
- --days-back=N --limit=N Window 1-90 (default 7); page size 1-20 (default 10)
2651
-
2652
- Problem flags (moda problem <id>):
2653
- --full Whole dossier in agent output (default there: header, summary,
2654
- top 5 evidence anchors, report titles)
2655
- --evidence|--reports|--traces|--feedback
2656
- Open one sub-resource page (at most one)
2657
- --limit=N --cursor=TOKEN Keyset paging (1-50; pass next_cursor back verbatim)
2658
- --family=F --door=D Filter --traces (families: tool_failure|emotion|laziness|hallucination|prm_dip|custom_signal|conversation_reader)
2659
-
2660
- Problem-feedback flags:
2661
- --action=A mark_fixed|dismiss|flag_attribution|rename (required)
2662
- --reason=TEXT Required for flag_attribution; optional for dismiss
2663
- --attribution-id=UUID Required for flag_attribution (ids come from problem --evidence)
2664
- --new-name=NAME Required for rename
2665
-
2666
- False-positive flags (moda false-positive <kind> <target>):
2667
- --reason=TEXT Why it is wrong (optional)
2668
- --undo Remove an earlier mark (every kind except problem)
2669
- problem <problem_id> Dismiss the problem: hidden at once, logged for review, folded into reconcile
2670
- problem-detection <problem_id> One detection on a trace; needs --conversation-id and --attribution-id; teaches the problem
2671
- quote <conversation_id> A user quote; needs --family, --turn and --quote (from moda emotions); audit only
2672
- tool <conversation_id> One failing tool call; needs --tool and --tool-use-id (or --msg-index); audit only
2673
- laziness <conversation_id> Laziness on that trace; audit only
2674
- hallucination <conversation_id> Hallucinations on that trace; audit only
2675
- custom-signal <signal_id> A hit on that trace (--conversation-id); saved as does_not_fit, a labelled counterexample for the signal
2676
-
2677
- Problem-linear-file flags (needs Linear connected: Integrations -> Linear):
2678
- --issue=ENG-123|URL Link an existing Linear issue instead of filing a new one
2679
- --team-id=ID File into this Linear team (default: the integration's default team)
2680
- --title=TEXT Issue title (default: the Problem's name)
2681
- --priority=N 0 none, 1 urgent, 2 high, 3 medium, 4 low
2682
- --issue excludes --team-id/--title/--priority
2683
-
2684
- Detection-review flags (moda detection-review <problem_id>):
2685
- --conversation-id=ID Trace the detection is on (required)
2686
- --attribution-id=UUID Detection id (from problem --evidence or detection-reviews; required)
2687
- --verdict=V correct|false_positive|clear (required; clear undoes a review)
2688
- --note=TEXT Why (optional; kept with the review)
2689
-
2690
- Signal flags:
2691
- --detections moda signal <id>: list recent hits instead of the summary
2692
- --days-back=N --limit=N --offset=N
2693
- Hits window 1-90 (default 7); page size 1-20 (default 10)
2694
-
2695
- Signal-label flags (moda signal-label <signal_id>):
2696
- --conversation-id=ID Trace to label (required)
2697
- --label=fits|does_not_fit does_not_fit marks a false positive and retracts the hit (required)
2698
- --note=TEXT Why (recommended for does_not_fit)
2699
- --msg-index=N --msg-dedup-token=T
2700
- Anchor message (from the hit's anchor_msg_index / anchor_dedup_token)
2701
-
2702
- Tail flags:
2703
- --signal=S traces|emotions|all (default traces)
2704
- --interval=N Poll every N seconds (5-3600, default 15)
2705
- --once One poll, then exit (baseline page)
2706
- --limit=N --max-events=N Page size per poll; stop after N stdout records
2707
- (metadata included; a slot is reserved for the
2708
- emotions coverage record, which falls back to
2709
- stderr if the bound leaves no room)
2710
- --full-scan Emotions: scan the whole window instead of the
2711
- top-scoring prefix (many more requests). /emotions
2712
- is score-ranked with no cursor, so the default
2713
- follows the highest-scoring detections and emits a
2714
- tail_coverage line stating exactly what it saw.
2715
-
2716
- Clusters search flags:
2717
- --search="query" Find clusters by name/meaning (task-cluster search)
2718
- --node-id=ID Deterministically resolve one cluster node (deep link)
2719
- --mode=fuzzy|semantic|hybrid Cluster search mode (default hybrid)
2720
-
2721
- Feedback flags:
2722
- --category=CAT ${feedbackCategoryHelp()}
2723
- An unknown category is sent as other (with refs.raw_category)
2724
- --severity=info|low|medium|high How bad it is (default low)
2725
- --note=TEXT The note, if not given as the positional argument
2726
- --conversation-id=ID Attach the trace ID you were looking at
2727
- --cluster-id=ID Attach a cluster node id
2728
- --tool-name=NAME Attach a tool name
2729
- --run-id=ID Attach a run id
2730
- --<name>-id=ID Any other id (--problem-id, --fix-id, --attribution-id,
2731
- --trace-id, --span-id, --message-index, ...) goes into refs
2732
- (set MODA_CLI_TIPS=0 to hide the feedback tip line)
2733
-
2734
- Init flags:
2735
- --yes Accept all defaults (non-interactive)
2736
- --analyst=auto|claude|codex|cursor|local-scan
2737
- Choose harness analyst adapter
2738
- --analyst-model=MODEL Model for the claude analyst (default: sonnet;
2739
- "default" = the claude CLI's own default;
2740
- env: MODA_HARNESS_ANALYST_MODEL)
2741
- --assist=none Disable agent fallback for prompt discovery
2742
- --concern=topology|tools|prompts|evals
2743
- Harness analyze: restrict the pass to one
2744
- concern (whole repo, one report scope); an
2745
- orchestrator merges the per-concern reports
2746
- (env: MODA_HARNESS_CONCERN, flag wins)
2747
- --allow-no-agents Allow harness sync to push a graph with zero
2748
- runtime agents despite detected LLM usage
2749
- --remote Run harness analysis server-side (Moda-hosted,
2750
- the default): upload a safe source snapshot; no
2751
- local coding agent required
2752
- --local Run harness analysis with a LOCAL coding agent
2753
- instead of server-side (opt out of remote)
2754
- --tui Show full-screen analyst dashboard in human TTYs
2755
- --no-tui Show raw external analyst output
2756
- --sdk-integrate Run your coding agent to install the Moda SDK and instrument LLM calls
2757
- --no-sdk-integrate Skip SDK integration (alias: --no-sdk-guide)
2758
- --verification-id=ID Tag the SDK integration's test trace with this id
2759
- (the onb_ id from the Moda onboarding page)
2760
- --connect-code=CODE Sign in with the one-time mcc_ code from the Moda
2761
- onboarding page instead of the browser (10 min, single use)
2762
- --ci-cd Create GitHub Actions Moda validation workflow
2763
- --no-ci-cd Skip CI/CD workflow creation
2764
- --autosync Create GitHub Actions workflow to sync prompts + skills to Moda on push to main
2765
- --no-autosync Skip autosync workflow creation
2766
- --harness-rescan Create GitHub Actions workflow to re-scan the harness and sync it to Moda on push to main
2767
- --no-harness-rescan Skip harness rescan workflow creation
2768
- --harness-rescan-paths=GLOBS Comma-separated path globs that scope which pushes trigger the
2769
- harness rescan workflow (implies --harness-rescan)
2770
- --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
2771
2159
 
2772
- Provision flags (headless; requires an existing "moda auth login" session):
2773
- --tenant-id=ID Organization to provision (required with multiple
2774
- organizations; MODA_TENANT_ID env is also honored,
2775
- flag wins). Never prompts, even on a TTY.
2776
- --label=TEXT API key label (default: machine hostname)
2777
- --save Also persist the key to ~/.moda/config.json
2778
- (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
2779
2167
 
2780
- Examples:
2781
- moda init
2782
- moda auth login --api-key=$MODA_API_KEY
2783
- moda auth whoami
2784
- moda provision --tenant-id=<org-id>
2785
- moda status
2786
- moda manifest --json
2787
- moda doctor --json
2788
- moda profiles list
2789
- moda profiles use staging
2790
- moda config show --profile=prod
2791
- moda harness analyze --experimental --summary
2792
- moda harness analyze --experimental --remote
2793
- moda harness analyze --experimental --analyst=claude --tui
2794
- moda harness analyze --experimental --analyst=claude --no-tui
2795
- moda harness analyze --experimental --analyst=claude --summary
2796
- moda harness analyze --experimental --analyst=local-scan --summary
2797
- moda harness pull --sync
2798
- moda harness validate-report
2799
- moda harness approve --yes
2800
- moda harness sync --from-report .moda/harness-report.json
2801
- moda harness delete my-harness-key --yes
2802
- moda --agent doctor
2803
- moda agent context
2804
- moda agent next-action
2805
- moda agent evidence doctor:api_key_resolves
2806
- moda investigate
2807
- moda failures
2808
- moda ask "what should I fix first?"
2809
- moda sync --dry-run
2810
- moda sync harness --profile=prod
2811
- moda harness scan --json
2812
- moda harness candidates --out=.moda/harness-candidates.json
2813
- moda harness explain --agent=agent_support
2814
- moda init --ci-cd
2815
- moda init --autosync
2816
- moda init --harness-rescan --harness-rescan-paths='src/agents/**'
2817
- moda overview --days-back=30
2818
- moda clusters --time-range=7d
2819
- moda traces --search="error" --limit=5
2820
- moda traces --world-state="enterprise" --outcome=positive
2821
- moda traces --world-state="refund,billing" --include-world-state
2822
- moda search "billing error" --mode=hybrid
2823
- moda search "refund flow" --mode=semantic --time-range=7d --limit=10
2824
- moda world-state <conversation_id> --summary-only
2825
- moda world-state <conversation_id> --snapshot --msg-index=42
2826
- moda world-state <conversation_id> --replay --message-count=50
2827
- moda clusters --search="billing disputes"
2828
- moda emotions --family=confusion --days-back=14
2829
- moda hallucinations --kind=contradicted
2830
- moda problems --days-back=7
2831
- moda problem <problem_id> --evidence --limit=10
2832
- moda problem-feedback <problem_id> --action=mark_fixed
2833
- moda problem-linear <problem_id>
2834
- moda problem-linear-file <problem_id> --priority=2
2835
- moda detection-reviews <conversation_id>
2836
- moda detection-review <problem_id> --conversation-id=<id> --attribution-id=<uuid> --verdict=false_positive --note="expected retry"
2837
- moda signals
2838
- moda signal <signal_id> --detections --days-back=30
2839
- moda signal-label <signal_id> --conversation-id=<id> --label=does_not_fit --note="refund was approved"
2840
- moda tail --signal=all --interval=30
2841
- moda frustrations --days-back=14 --limit=20
2842
- moda feedback "cluster label looks wrong" --category=bad_cluster_label --cluster-id=<node_id>
2843
- moda context <conversation_id> --window=3
2844
- moda audit <conversation_id|trace_id>
2845
- moda audit <trace_id> --kind=trace --json
2846
- moda prompts status
2847
- moda prompts sync
2848
- moda prompts promote support.triage --label=prod --version=pver_abc123
2849
- moda prompts ab --baseline=prompts/agent.prompt.md --candidate=prompts/agent-v2.prompt.md --traces=conv_1,conv_2
2850
- moda prompts ab --baseline=prompts/agent.prompt.md --candidate=prompts/agent-v2.prompt.md --traces=conv_1@412 # replay from msg 412
2851
- 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.
2852
2171
 
2853
- Run \`moda <command> --help\` for a command's subcommands, and
2854
- \`moda <command> <subcommand> --help\` for that subcommand's flags
2855
- (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;
2856
2192
  }
2857
2193
  function printCommandHelp(definition) {
2858
2194
  const lines = [];
@@ -2866,6 +2202,17 @@ function printCommandHelp(definition) {
2866
2202
  for (const note of definition.helpNotes ?? []) {
2867
2203
  lines.push("", note);
2868
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
+ }
2869
2216
  if (definition.subcommands && definition.subcommands.length > 0) {
2870
2217
  lines.push("", "Subcommands:");
2871
2218
  const width = Math.max(...definition.subcommands.map((entry) => entry.name.length));
@@ -2880,7 +2227,7 @@ function printCommandHelp(definition) {
2880
2227
  lines.push(` ${example}`);
2881
2228
  }
2882
2229
  }
2883
- 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.");
2884
2231
  console.log(lines.join(`
2885
2232
  `));
2886
2233
  }
@@ -3263,7 +2610,7 @@ function recordSearchTelemetry(context, data) {
3263
2610
  const pagination = asRecord(record.pagination);
3264
2611
  const hasMore = pagination?.has_more;
3265
2612
  context.recordTelemetry({
3266
- search_mode_effective: SEARCH_MODES2.includes(effective) ? effective : undefined,
2613
+ search_mode_effective: SEARCH_MODES.includes(effective) ? effective : undefined,
3267
2614
  result_count: results.length,
3268
2615
  has_more: hasMore === true ? "yes" : hasMore === false ? "no" : "na",
3269
2616
  ...typeof record.degrade_reason === "string" && record.degrade_reason ? { degrade_reason: record.degrade_reason.slice(0, 64) } : {}
@@ -3344,7 +2691,6 @@ var GLOBAL_FLAG_NAMES = new Set([
3344
2691
  "no-telemetry",
3345
2692
  "no-update-check"
3346
2693
  ]);
3347
- var OVERVIEW_PRODUCTION_FLAGS = ["raw"];
3348
2694
  var WINDOW_FLAG_HINTS = {
3349
2695
  days_back: "This command takes --time-range (e.g. --time-range=7d), not --days-back.",
3350
2696
  time_range: "This command takes --days-back=N (1-90), not --time-range."
@@ -3355,27 +2701,8 @@ var COMMAND_FLAG_HINTS = {
3355
2701
  cursor: "'moda problems' has no cursor; 'moda problems remainder --cursor=<next_cursor>' pages the unexplained signals."
3356
2702
  }
3357
2703
  };
3358
- function editDistance(a, b) {
3359
- const row = Array.from({ length: b.length + 1 }, (_, index) => index);
3360
- for (let i = 1;i <= a.length; i++) {
3361
- let previous = row[0];
3362
- row[0] = i;
3363
- for (let j = 1;j <= b.length; j++) {
3364
- const current = row[j];
3365
- row[j] = Math.min(row[j] + 1, row[j - 1] + 1, previous + (a[i - 1] === b[j - 1] ? 0 : 1));
3366
- previous = current;
3367
- }
3368
- }
3369
- return row[b.length];
3370
- }
3371
- function schemaFlagKeys(schema) {
3372
- let current = schema;
3373
- while (current instanceof z2.ZodEffects)
3374
- current = current.innerType();
3375
- return current instanceof z2.ZodObject ? Object.keys(current.shape) : [];
3376
- }
3377
2704
  function parseCommandFlags(schema, args, command, options = {}) {
3378
- const schemaKeys = schemaFlagKeys(schema);
2705
+ const schemaKeys = Object.keys(schemaShape(schema));
3379
2706
  const known = new Set([
3380
2707
  ...schemaKeys,
3381
2708
  ...[...GLOBAL_FLAG_NAMES, ...options.extraFlags ?? []].map((flag) => flag.replace(/-/g, "_"))
@@ -3385,24 +2712,70 @@ function parseCommandFlags(schema, args, command, options = {}) {
3385
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");
3386
2713
  }
3387
2714
  if (unknown.length > 0) {
3388
- const flagKeys = schemaKeys.filter((key) => key !== options.positionalKey);
3389
- 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 = [];
3390
2722
  const hints = unknown.map((key) => {
3391
2723
  const commandHint = COMMAND_FLAG_HINTS[command]?.[key];
3392
2724
  if (commandHint)
3393
2725
  return commandHint;
3394
2726
  const windowAlternative = key === "days_back" ? "time_range" : key === "time_range" ? "days_back" : undefined;
3395
- if (windowAlternative && WINDOW_FLAG_HINTS[key] && flagKeys.includes(windowAlternative))
2727
+ if (windowAlternative && WINDOW_FLAG_HINTS[key] && flagKeys.includes(windowAlternative)) {
2728
+ didYouMean.push(kebabFlag(windowAlternative));
3396
2729
  return WINDOW_FLAG_HINTS[key];
2730
+ }
3397
2731
  if (windowAlternative)
3398
2732
  return `This command has no time-window flag.`;
3399
- const close = flagKeys.map((candidate) => ({ candidate, distance: editDistance(key, candidate) })).filter(({ distance }) => distance <= 2).sort((left, right) => left.distance - right.distance)[0];
3400
- 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}?` : "";
3401
2737
  }).filter(Boolean);
3402
- const names = unknown.map((key) => `--${key.replace(/_/g, "-")}`).join(", ");
3403
- 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
+ });
3404
2746
  }
3405
- 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
+ };
3406
2779
  }
3407
2780
  function withStringIdFlags(args, flags) {
3408
2781
  for (const flag of ["user-id", "conversation-id"]) {
@@ -3590,36 +2963,12 @@ function serverWarnings(data) {
3590
2963
  function isDefinedRecord(value) {
3591
2964
  return value !== undefined && value !== null;
3592
2965
  }
3593
- var HAND_PARSED_COMMAND_FLAGS = {
3594
- investigate: ["days-back", "tool", "trace", "conversation"],
3595
- failures: ["days-back", "tool"],
3596
- ask: ["days-back", "stream"],
3597
- "step-scores": [],
3598
- "trace-signals": [],
3599
- signals: [],
3600
- "problem-feedback": ["action", "actor", "reason", "attribution-id", "new-name"],
3601
- "problem-linear": [],
3602
- "problem-linear-file": ["issue", "priority", "title", "team-id"],
3603
- "signal-label": ["label", "note", "conversation-id", "msg-dedup-token", "msg-index"],
3604
- "detection-reviews": ["attribution-id"],
3605
- "detection-review": ["note", "verdict", "attribution-id", "conversation-id"],
3606
- "false-positive": [
3607
- "family",
3608
- "quote",
3609
- "reason",
3610
- "tool",
3611
- "turn",
3612
- "undo",
3613
- "attribution-id",
3614
- "conversation-id",
3615
- "msg-dedup-token",
3616
- "msg-index",
3617
- "tool-use-id"
3618
- ],
3619
- "false-positives": ["all", "kind", "limit"],
3620
- feedback: FEEDBACK_FLAGS,
3621
- "problem-impact": ["mode", "node-id", "problem-id", "run-id", "to", "cursor", "conversation-ids", "days-back"]
3622
- };
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
+ }
3623
2972
  var NO_POSITIONAL_COMMANDS = new Set([
3624
2973
  "overview",
3625
2974
  "investigate",
@@ -3645,18 +2994,18 @@ function assertHandParsedFlags(command, flags, positionals) {
3645
2994
  if (NO_POSITIONAL_COMMANDS.has(command) && positionals.length > 0) {
3646
2995
  throw new CliInputError(`'moda ${command}' takes no arguments, but got '${positionals.join(" ")}'.`, `Nothing was run. See 'moda ${command} --help' for its flags.`);
3647
2996
  }
3648
- const allowed = HAND_PARSED_COMMAND_FLAGS[command];
3649
- if (!allowed)
2997
+ const hand = handParsedFlags(command);
2998
+ if (!hand)
3650
2999
  return;
3651
- const checked = command === "feedback" ? Object.keys(flags).filter((flag) => !isFeedbackRefFlag(flag)) : Object.keys(flags);
3652
- 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()])));
3653
3002
  const args = Object.fromEntries(checked.map((flag) => [flag.replace(/-/g, "_"), true]));
3654
3003
  try {
3655
- parseCommandFlags(shape.passthrough(), args, command);
3004
+ parseCommandFlags(shape.passthrough(), args, command, { flagAliases: hand.spec.flagAliases });
3656
3005
  } catch (error) {
3657
3006
  if (command !== "feedback" || !(error instanceof CliInputError))
3658
3007
  throw error;
3659
- 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);
3660
3009
  }
3661
3010
  }
3662
3011
  function normalizeBooleanFlags(target) {
@@ -3679,7 +3028,7 @@ function normalizeBooleanFlags(target) {
3679
3028
  }
3680
3029
  var PROFILE_MANAGING_COMMANDS = new Set(["profiles", "auth", "init", "provision", "status", "config", "manifest", "agent", "doctor"]);
3681
3030
  async function runProblemsRemainder(flags, context) {
3682
- const params = parseCommandFlags(ProblemsRemainderSchema, flagsToArgs(flags), "problems remainder");
3031
+ const params = parseCommandFlags(ProblemsRemainderSchema, flagsToArgs(flags), "problems remainder", specParseOptions(COMMAND_FLAG_SPECS.problems.subcommands.remainder));
3683
3032
  const query2 = new URLSearchParams;
3684
3033
  if (params.days_back)
3685
3034
  query2.set("days_back", params.days_back.toString());
@@ -3744,7 +3093,7 @@ function parseContextRequest(positional, rawFlags) {
3744
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.`);
3745
3094
  }
3746
3095
  const args = { ...flagsToArgs(flags), conversation_id: conversationId };
3747
- const params = parseCommandFlags(ContextSchema, args, "context", { positionalKey: "conversation_id" });
3096
+ const params = parseSpecFlags("context", args);
3748
3097
  if (params.metadata_only === true && params.window !== undefined) {
3749
3098
  throw new CliInputError("--metadata-only reads no messages, so it cannot be combined with --window; drop --window.", CONTEXT_USAGE, "flag_conflict");
3750
3099
  }
@@ -4180,7 +3529,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4180
3529
  }
4181
3530
  case "overview": {
4182
3531
  const args = flagsToArgs(flags);
4183
- parseCommandFlags(OverviewSchema, args, command, { extraFlags: OVERVIEW_PRODUCTION_FLAGS });
3532
+ parseSpecFlags("overview", args, command);
4184
3533
  return (await runProductionCommand(context)).exitCode;
4185
3534
  }
4186
3535
  case "investigate":
@@ -4190,7 +3539,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4190
3539
  }
4191
3540
  case "clusters": {
4192
3541
  const args = flagsToArgs(flags);
4193
- const params = parseCommandFlags(ClustersSchema, args, command);
3542
+ const params = parseSpecFlags("clusters", args, command);
4194
3543
  if (params.search !== undefined || params.node_id !== undefined) {
4195
3544
  const query3 = new URLSearchParams;
4196
3545
  if (params.search !== undefined)
@@ -4224,7 +3573,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4224
3573
  throw new CliInputError("<node_id> is required", "Usage: moda cluster-traces <node_id> [--limit=N] [--offset=N]");
4225
3574
  }
4226
3575
  const args = flagsToArgs(flags, "node_id", positional);
4227
- const params = parseCommandFlags(ClusterConversationsSchema, args, command, { positionalKey: "node_id" });
3576
+ const params = parseSpecFlags("cluster-traces", args, command);
4228
3577
  const query2 = new URLSearchParams;
4229
3578
  if (params.limit)
4230
3579
  query2.set("limit", params.limit.toString());
@@ -4240,7 +3589,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4240
3589
  case "traces":
4241
3590
  case "conversations": {
4242
3591
  const args = withStringIdFlags(flagsToArgs(flags), flags);
4243
- const params = parseCommandFlags(ConversationsSchema, args, command);
3592
+ const params = parseSpecFlags("traces", args, command);
4244
3593
  const query2 = new URLSearchParams;
4245
3594
  if (params.search)
4246
3595
  query2.set("search", params.search);
@@ -4302,7 +3651,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4302
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]');
4303
3652
  }
4304
3653
  const args = withStringIdFlags(flagsToArgs(flags, "q", positional), flags);
4305
- const params = parseCommandFlags(SearchSchema, args, command, { positionalKey: "q" });
3654
+ const params = parseSpecFlags("search", args, command);
4306
3655
  const query2 = new URLSearchParams;
4307
3656
  query2.set("q", params.q);
4308
3657
  if (params.mode)
@@ -4358,7 +3707,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4358
3707
  throw new CliInputError("<conversation_id> is required", "Usage: moda world-state <conversation_id> [--summary-only] [--event-limit=N]");
4359
3708
  }
4360
3709
  const args = flagsToArgs(flags, "conversation_id", positional);
4361
- const params = parseCommandFlags(WorldStateSchema, args, command, { positionalKey: "conversation_id" });
3710
+ const params = parseSpecFlags("world-state", args, command);
4362
3711
  if (params.snapshot === true && params.replay === true) {
4363
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]]");
4364
3713
  }
@@ -4416,7 +3765,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4416
3765
  throw new CliInputError("<conversation_id|trace_id> is required", AUDIT_USAGE);
4417
3766
  }
4418
3767
  const args = flagsToArgs(flags, "id", positional);
4419
- const params = parseCommandFlags(AuditSchema, args, command, { positionalKey: "id" });
3768
+ const params = parseSpecFlags("audit", args, command);
4420
3769
  const agentMode = context.output.mode === "agent" || context.output.mode === "agent-stream";
4421
3770
  const page = await readAuditItem(command, params, agentMode ? {
4422
3771
  maxBytes: Math.max(AUDIT_MIN_PAGE_BYTES, agentMaxOutputBytes() - AUDIT_AGENT_RESERVE_BYTES),
@@ -4427,7 +3776,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4427
3776
  }
4428
3777
  case "frustrations": {
4429
3778
  const args = withStringIdFlags(flagsToArgs(flags), flags);
4430
- const params = parseCommandFlags(FrustrationsSchema, args, command);
3779
+ const params = parseSpecFlags("frustrations", args, command);
4431
3780
  const query2 = new URLSearchParams;
4432
3781
  if (params.days_back)
4433
3782
  query2.set("days_back", params.days_back.toString());
@@ -4449,7 +3798,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4449
3798
  }
4450
3799
  case "tool-failures": {
4451
3800
  const args = flagsToArgs(flags);
4452
- const params = parseCommandFlags(ToolFailuresSchema, args, command);
3801
+ const params = parseSpecFlags("tool-failures", args, command);
4453
3802
  const queryString = params.days_back ? `?days_back=${params.days_back}` : "";
4454
3803
  const data = await callDataAPI(`/tool-failures${queryString}`);
4455
3804
  context.output.writeData(data);
@@ -4467,7 +3816,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4467
3816
  toolFlags["include-window"] = "false";
4468
3817
  }
4469
3818
  const args = flagsToArgs(toolFlags, "tool_name", positional);
4470
- const params = parseCommandFlags(ToolFailureDetailSchema, args, command, { positionalKey: "tool_name" });
3819
+ const params = parseSpecFlags("tool-failure-detail", args, command);
4471
3820
  const dropConversation = params.compact === true || params.include_window === false;
4472
3821
  if (params.compact === true && params.include_window === true) {
4473
3822
  throw new CliInputError("--compact drops the conversation window; drop --include-window, or drop --compact.");
@@ -4547,7 +3896,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4547
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>'.");
4548
3897
  }
4549
3898
  const args = flagsToArgs(flags);
4550
- const params = parseCommandFlags(ProblemsSchema, args, command);
3899
+ const params = parseSpecFlags("problems", args, command);
4551
3900
  const query2 = new URLSearchParams;
4552
3901
  if (params.days_back)
4553
3902
  query2.set("days_back", params.days_back.toString());
@@ -4574,7 +3923,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4574
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]");
4575
3924
  }
4576
3925
  const args = flagsToArgs(flags, "id", positional);
4577
- const params = parseCommandFlags(ProblemSchema, args, command, { positionalKey: "id" });
3926
+ const params = parseSpecFlags("problem", args, command);
4578
3927
  const traceView = params.traces === true || params.conversations === true;
4579
3928
  const views = ["evidence", "reports", "conversations", "feedback"].filter((view2) => view2 === "conversations" ? traceView : params[view2] === true);
4580
3929
  if (views.length > 1) {
@@ -4748,7 +4097,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4748
4097
  }
4749
4098
  const args = flagsToArgs(flags, "id", positional);
4750
4099
  args.id = positional;
4751
- const params = parseCommandFlags(SignalSchema, args, command, { positionalKey: "id" });
4100
+ const params = parseSpecFlags("signal", args, command);
4752
4101
  const id = encodeURIComponent(params.id);
4753
4102
  if (params.detections !== true) {
4754
4103
  const data2 = await callDataAPI(`/custom-signals/${id}`);
@@ -4941,7 +4290,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4941
4290
  }
4942
4291
  case "emotions": {
4943
4292
  const args = withStringIdFlags(flagsToArgs(flags), flags);
4944
- const params = parseCommandFlags(EmotionsSchema, args, command);
4293
+ const params = parseSpecFlags("emotions", args, command);
4945
4294
  const query2 = new URLSearchParams;
4946
4295
  if (params.days_back)
4947
4296
  query2.set("days_back", params.days_back.toString());
@@ -4969,7 +4318,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4969
4318
  if (flags["conversation-id"] !== undefined) {
4970
4319
  args.conversation_id = flags["conversation-id"];
4971
4320
  }
4972
- const params = parseCommandFlags(LazinessSchema, args, command);
4321
+ const params = parseSpecFlags("laziness", args, command);
4973
4322
  const query2 = new URLSearchParams;
4974
4323
  if (params.days_back)
4975
4324
  query2.set("days_back", params.days_back.toString());
@@ -4991,7 +4340,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
4991
4340
  if (flags["conversation-id"] !== undefined) {
4992
4341
  args.conversation_id = flags["conversation-id"];
4993
4342
  }
4994
- const params = parseCommandFlags(HallucinationsSchema, args, command);
4343
+ const params = parseSpecFlags("hallucinations", args, command);
4995
4344
  const query2 = new URLSearchParams;
4996
4345
  if (params.days_back)
4997
4346
  query2.set("days_back", params.days_back.toString());
@@ -5025,7 +4374,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5025
4374
  }
5026
4375
  case "tail": {
5027
4376
  const args = flagsToArgs(flags);
5028
- const params = parseCommandFlags(TailSchema, args, command);
4377
+ const params = parseSpecFlags("tail", args, command);
5029
4378
  await runTailCommand(params, context);
5030
4379
  break;
5031
4380
  }
@@ -5050,7 +4399,7 @@ async function runCommand(command, positional, flags, positionals = positional ?
5050
4399
  break;
5051
4400
  }
5052
4401
  default:
5053
- throw new CliInputError(`Unknown command '${command}'`, 'Run "moda --help" for usage information.');
4402
+ throw unknownCommandError(command);
5054
4403
  }
5055
4404
  return 0;
5056
4405
  }
@@ -5153,6 +4502,30 @@ var commandRegistry = createCommandRegistry([
5153
4502
  name: "init",
5154
4503
  description: "Set up Moda in your project",
5155
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
+ ],
5156
4529
  auth: "none",
5157
4530
  outputModes: ["human", "json", "agent"],
5158
4531
  mutability: "write",
@@ -5160,7 +4533,7 @@ var commandRegistry = createCommandRegistry([
5160
4533
  resetApiRequestCountBeforeRun: true,
5161
4534
  telemetry: "result-and-error",
5162
4535
  handler: async (context) => {
5163
- const { runInit } = await import("./index-7zqa7t5c.js");
4536
+ const { runInit } = await import("./index-6qqmjqb2.js");
5164
4537
  if (context.outputMode === "agent-stream") {
5165
4538
  context.output.writeEvent({
5166
4539
  event: "started",
@@ -5194,6 +4567,12 @@ var commandRegistry = createCommandRegistry([
5194
4567
  "moda provision --tenant-id=<org-id> --label=ci-runner --save",
5195
4568
  "KEY=$(moda provision --tenant-id <org-id> | jq -r .apiKey)"
5196
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
+ ],
5197
4576
  auth: "none",
5198
4577
  outputModes: ["human", "json", "agent"],
5199
4578
  mutability: "write",
@@ -5201,7 +4580,7 @@ var commandRegistry = createCommandRegistry([
5201
4580
  resetApiRequestCountBeforeRun: true,
5202
4581
  telemetry: "result-and-error",
5203
4582
  handler: async (context) => {
5204
- const { runProvision } = await import("./provision-n3r7yway.js");
4583
+ const { runProvision } = await import("./provision-wzttap58.js");
5205
4584
  return runProvision(context, {
5206
4585
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
5207
4586
  });
@@ -5800,6 +5179,9 @@ var commandRegistry = createCommandRegistry([
5800
5179
  legacyCommand({
5801
5180
  name: "false-positive",
5802
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
+ ],
5803
5185
  examples: [
5804
5186
  'moda false-positive problem <problem_id> --reason="two unrelated tools"',
5805
5187
  'moda false-positive problem-detection <problem_id> --conversation-id=<id> --attribution-id=<uuid> --reason="refund was approved"',
@@ -5917,6 +5299,9 @@ var commandRegistry = createCommandRegistry([
5917
5299
  'moda feedback "search finds nothing for a trace I can open" --category=missing_data --conversation-id=<id>',
5918
5300
  'moda feedback "trace is about refunds, not this problem" --category=false_positive_attribution --problem-id=<id> --conversation-id=<id>'
5919
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
+ ],
5920
5305
  ...dataApiDefaults,
5921
5306
  mutability: "write"
5922
5307
  }),
@@ -6116,7 +5501,7 @@ function classifyCliError(error) {
6116
5501
  return "auth_error";
6117
5502
  if (error instanceof ApiError && error.statusCode === 403)
6118
5503
  return "access_error";
6119
- if (error instanceof z2.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError) {
5504
+ if (error instanceof z.ZodError || error instanceof CliInputError || error instanceof CliInputRequiredError) {
6120
5505
  return "validation_error";
6121
5506
  }
6122
5507
  if (error instanceof ApiError || isApiLikeError(error)) {
@@ -6128,7 +5513,7 @@ function classifyCliError(error) {
6128
5513
  return "unknown_error";
6129
5514
  }
6130
5515
  function cliValidationReason(error) {
6131
- if (error instanceof z2.ZodError) {
5516
+ if (error instanceof z.ZodError) {
6132
5517
  const issue = error.issues[0];
6133
5518
  if (!issue)
6134
5519
  return "zod";
@@ -6155,7 +5540,7 @@ function printCliError(error) {
6155
5540
  if (error.guidance)
6156
5541
  safeWriteStderr(`${error.guidance}
6157
5542
  `);
6158
- } else if (error instanceof z2.ZodError) {
5543
+ } else if (error instanceof z.ZodError) {
6159
5544
  const issues = error.errors.map((e) => {
6160
5545
  const field = e.path.length ? e.path.join(".") : "input";
6161
5546
  return ` ${field}: ${e.message}`;
@@ -6199,6 +5584,21 @@ function printFeedbackTip(commandName, context) {
6199
5584
  ${colorOk ? `\x1B[2m${text}\x1B[0m` : text}
6200
5585
  `);
6201
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
+ }
6202
5602
  function printAgentCliError(command, error, mode = "agent") {
6203
5603
  const output = createCliOutput({
6204
5604
  command: command || "unknown",
@@ -6296,9 +5696,8 @@ async function dispatchParsedCommandInner(parsed, startedAt) {
6296
5696
  return 1;
6297
5697
  };
6298
5698
  const definition = commandRegistry.find(command);
6299
- if (!definition) {
6300
- return failEarly(new CliInputError(`Unknown command '${command}'`, 'Run "moda --help" for usage information.'));
6301
- }
5699
+ if (!definition)
5700
+ return failEarly(unknownCommandError(command));
6302
5701
  if (parsed.shortFlags?.length) {
6303
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);
6304
5703
  }
@@ -6485,6 +5884,7 @@ if (isMain) {
6485
5884
  });
6486
5885
  }
6487
5886
  export {
5887
+ unknownCommandError,
6488
5888
  telemetrySubcommandNames,
6489
5889
  telemetryCommandName,
6490
5890
  stripLoneSurrogates,
@@ -6499,6 +5899,7 @@ export {
6499
5899
  parseArgs,
6500
5900
  normalizeBooleanFlags,
6501
5901
  initFlagsForContext,
5902
+ globalFlagHelpLines,
6502
5903
  flagsToArgs,
6503
5904
  dispatchParsedCommand,
6504
5905
  detectCallerAgent,