@moda-ai/cli 1.36.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  runPromptsCommand,
9
9
  runSkillsCommand,
10
10
  runStatusCommand
11
- } from "./cli-7qkhy41j.js";
11
+ } from "./cli-3kcy61fr.js";
12
12
  import {
13
13
  ApiError,
14
14
  HARNESS_REPORT_APPROVAL_PATH,
@@ -29,7 +29,8 @@ import {
29
29
  summarizeHarness,
30
30
  terminalStyles,
31
31
  validateHarnessReport
32
- } from "./cli-0p6n391h.js";
32
+ } from "./cli-07tv75te.js";
33
+ import"./cli-ssfq84k5.js";
33
34
  import {
34
35
  authFetch,
35
36
  clearAuthSession,
@@ -37,7 +38,7 @@ import {
37
38
  loadAuthSession,
38
39
  login,
39
40
  revokeCliSessionToken
40
- } from "./cli-yz99t7n8.js";
41
+ } from "./cli-kegd748v.js";
41
42
  import {
42
43
  AGENT_ERROR_CODES,
43
44
  CliAccessError,
@@ -55,7 +56,6 @@ import {
55
56
  MODA_BASE_URL,
56
57
  PROD_BASE_URL,
57
58
  VERSION,
58
- __require,
59
59
  assertValidProfileName,
60
60
  clearStoredApiKeyCredentials,
61
61
  createCliOutput,
@@ -84,7 +84,10 @@ import {
84
84
  validateConfig,
85
85
  wasOutputCancelled,
86
86
  writeSecretJsonFile
87
- } from "./cli-drabjmaj.js";
87
+ } from "./cli-q79sq80a.js";
88
+ import {
89
+ __require
90
+ } from "./cli-0v6na3yp.js";
88
91
 
89
92
  // src/cli.ts
90
93
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -210,6 +213,13 @@ var ProblemFeedbackSchema = z.object({
210
213
  new_name: z.string().max(255).optional(),
211
214
  actor: z.string().max(255).optional()
212
215
  });
216
+ var ProblemLinearFileSchema = z.object({
217
+ id: z.string().min(1),
218
+ issue: z.string().max(2048).optional(),
219
+ team_id: z.string().max(255).optional(),
220
+ title: z.string().optional(),
221
+ priority: z.preprocess((v) => typeof v === "string" && /^\d+$/.test(v.trim()) ? Number(v) : v, z.number().int().min(0).max(4).optional())
222
+ });
213
223
  var SignalSchema = z.object({
214
224
  id: z.string().min(1).max(255),
215
225
  detections: boolFlag(),
@@ -2901,11 +2911,26 @@ async function runAuthCommand(context) {
2901
2911
  return { exitCode: EXIT_AUTH_REQUIRED };
2902
2912
  }
2903
2913
  process.stdout.write(`${session.access_token}
2914
+ `);
2915
+ return { exitCode: EXIT_OK };
2916
+ }
2917
+ case "api-key": {
2918
+ const credential = resolveApiKeyCredential({ profile: context.profile, env: context.env });
2919
+ if (!credential) {
2920
+ if (context.flags.json === "true") {
2921
+ process.stdout.write(`${JSON.stringify({ error: "no_api_key" })}
2922
+ `);
2923
+ } else {
2924
+ console.error('No API key saved. Run "moda init" (or "moda auth login --api-key-stdin").');
2925
+ }
2926
+ return { exitCode: EXIT_AUTH_REQUIRED };
2927
+ }
2928
+ process.stdout.write(`${credential.key}
2904
2929
  `);
2905
2930
  return { exitCode: EXIT_OK };
2906
2931
  }
2907
2932
  default:
2908
- throw unknownSubcommandError("auth", subcommand(context), ["login", "logout", "status", "token", "whoami"]);
2933
+ throw unknownSubcommandError("auth", subcommand(context), ["api-key", "login", "logout", "status", "token", "whoami"]);
2909
2934
  }
2910
2935
  }
2911
2936
  async function runProfilesCommand(context) {
@@ -5373,6 +5398,19 @@ function parseFlag(args, index, flags, beforeCommand) {
5373
5398
  flags[key] = "true";
5374
5399
  return index;
5375
5400
  }
5401
+ function initFlagsForContext(flags, outputMode, stdinIsTTY) {
5402
+ const args = flagsToArgs(flags);
5403
+ const explicitMode = args.json === true || args.json === "true" || args.agent === true || args.agent === "true";
5404
+ if (explicitMode)
5405
+ return args;
5406
+ if (outputMode === "json")
5407
+ return { ...args, json: true };
5408
+ if (outputMode !== "human")
5409
+ return { ...args, agent: true };
5410
+ if (!stdinIsTTY)
5411
+ return { ...args, non_interactive: true };
5412
+ return args;
5413
+ }
5376
5414
  function flagsToArgs(flags, positionalKey, positionalValue) {
5377
5415
  const result = {};
5378
5416
  if (positionalKey && positionalValue) {
@@ -5405,6 +5443,7 @@ Commands:
5405
5443
  auth login --api-key Non-interactive: validate MODA_API_KEY (or --api-key=<key>) and save it
5406
5444
  auth status Show auth state for both credentials (exit 4 when neither is usable); --online probes the API
5407
5445
  auth token Print the raw bearer token for $(moda auth token)
5446
+ auth api-key Print the saved API key for $(moda auth api-key)
5408
5447
  auth logout Clear cached Moda auth
5409
5448
  auth whoami Show the authenticated Moda identity (session or API key)
5410
5449
  profiles list List local Moda profiles
@@ -5457,6 +5496,8 @@ Commands:
5457
5496
  problem-feedback <problem_id> Mark a Problem fixed, dismiss, rename, or flag a bad attribution
5458
5497
  false-positive <kind> <target> Mark any detection as a false positive, optional --reason (problem, problem-detection, quote, tool, laziness, hallucination, custom-signal)
5459
5498
  false-positives [conv_id] Current false-positive marks: all (--kind, --all, --limit) or one trace
5499
+ problem-linear <problem_id> Show the Linear issue linked to a Problem (key, state, URL)
5500
+ problem-linear-file <problem_id> File a Problem as a Linear issue, or link an existing one (--issue)
5460
5501
  detection-reviews <conv_id> Problem detections on a trace with their review state
5461
5502
  detection-review <problem_id> Mark a problem detection correct, a false positive, or clear the review
5462
5503
  signals List custom signals (name, criteria, status, 7-day stats)
@@ -5485,6 +5526,7 @@ Commands:
5485
5526
  skills gen Kick off tenant-wide skill generation
5486
5527
  skills status [run-id] Show a generation run's status, outcome, and recent events (default: latest run)
5487
5528
  skills pull Pull tenant-generated skills into .claude/skills (and .cursor/rules)
5529
+ skills install <id...> Install bundled integration guides into .claude/skills (--list to browse)
5488
5530
  skills pull --status=proposed Include not-yet-promoted skills (default: approved)
5489
5531
  skills sync Push local .claude/skills/**/SKILL.md up to Moda
5490
5532
  skills sync --dry-run Show what would be pushed without writing
@@ -5599,6 +5641,13 @@ False-positive flags (moda false-positive <kind> <target>):
5599
5641
  hallucination <conversation_id> Hallucinations on that trace; audit only
5600
5642
  custom-signal <signal_id> A hit on that trace (--conversation-id); saved as does_not_fit so the signal learns
5601
5643
 
5644
+ Problem-linear-file flags (needs Linear connected: Integrations -> Linear):
5645
+ --issue=ENG-123|URL Link an existing Linear issue instead of filing a new one
5646
+ --team-id=ID File into this Linear team (default: the integration's default team)
5647
+ --title=TEXT Issue title (default: the Problem's name)
5648
+ --priority=N 0 none, 1 urgent, 2 high, 3 medium, 4 low
5649
+ --issue excludes --team-id/--title/--priority
5650
+
5602
5651
  Detection-review flags (moda detection-review <problem_id>):
5603
5652
  --conversation-id=ID Trace the detection is on (required)
5604
5653
  --attribution-id=UUID Detection id (from problem --evidence or detection-reviews; required)
@@ -5670,6 +5719,10 @@ Init flags:
5670
5719
  --no-tui Show raw external analyst output
5671
5720
  --sdk-integrate Run your coding agent to install the Moda SDK and instrument LLM calls
5672
5721
  --no-sdk-integrate Skip SDK integration (alias: --no-sdk-guide)
5722
+ --verification-id=ID Tag the SDK integration's test trace with this id
5723
+ (the onb_ id from the Moda onboarding page)
5724
+ --connect-code=CODE Sign in with the one-time mcc_ code from the Moda
5725
+ onboarding page instead of the browser (10 min, single use)
5673
5726
  --ci-cd Create GitHub Actions Moda validation workflow
5674
5727
  --no-ci-cd Skip CI/CD workflow creation
5675
5728
  --autosync Create GitHub Actions workflow to sync prompts + skills to Moda on push to main
@@ -5741,6 +5794,8 @@ Examples:
5741
5794
  moda problems --days-back=7
5742
5795
  moda problem <problem_id> --evidence --limit=10
5743
5796
  moda problem-feedback <problem_id> --action=mark_fixed
5797
+ moda problem-linear <problem_id>
5798
+ moda problem-linear-file <problem_id> --priority=2
5744
5799
  moda detection-reviews <conversation_id>
5745
5800
  moda detection-review <problem_id> --conversation-id=<id> --attribution-id=<uuid> --verdict=false_positive --note="expected retry"
5746
5801
  moda signals
@@ -6098,6 +6153,50 @@ function detectCallerAgent(env) {
6098
6153
  return "agent";
6099
6154
  return "human";
6100
6155
  }
6156
+ var LINEAR_CONNECT_GUIDANCE = "Connect Linear in the Moda dashboard (Integrations -> Linear), then retry.";
6157
+ function describeLinearLink(linkValue) {
6158
+ const link = asRecord(linkValue);
6159
+ if (!link)
6160
+ return "No Linear issue linked to this Problem.";
6161
+ const issue = asRecord(link.issue);
6162
+ if (!issue) {
6163
+ return "A Linear issue is still being created for this Problem; re-run shortly.";
6164
+ }
6165
+ return [asString(issue.identifier), asString(issue.stateName), asString(issue.url)].filter((part) => part !== null && part !== "").join(" · ");
6166
+ }
6167
+ function linearApiError(error) {
6168
+ if (!(error instanceof ApiError))
6169
+ return error;
6170
+ let code;
6171
+ let message;
6172
+ try {
6173
+ const body = asRecord(JSON.parse(error.responseBody));
6174
+ code = asString(body?.error) ?? undefined;
6175
+ message = asString(body?.message) ?? undefined;
6176
+ } catch {
6177
+ code = undefined;
6178
+ }
6179
+ if (error.statusCode === 404 && code === "linear_not_enabled") {
6180
+ return new CliAccessError("The Linear integration is not enabled for this tenant.", {
6181
+ guidance: LINEAR_CONNECT_GUIDANCE
6182
+ });
6183
+ }
6184
+ if (error.statusCode === 404 && code === "problem_not_found") {
6185
+ return new CliInputError(`${message ?? "Problem not found"}.`, "Run `moda problems` to list problems with their canonical ids.");
6186
+ }
6187
+ if (error.statusCode === 409 && code === "not_connected") {
6188
+ return new CliAccessError("Linear is not connected, or a disconnect is still in progress.", {
6189
+ guidance: `If Linear was just disconnected, wait for that to finish. ${LINEAR_CONNECT_GUIDANCE}`
6190
+ });
6191
+ }
6192
+ if (error.statusCode === 409 && code === "needs_reauth") {
6193
+ return new CliAccessError("Linear needs to be reconnected.", { guidance: LINEAR_CONNECT_GUIDANCE });
6194
+ }
6195
+ if (error.statusCode === 400 && code === "no_team") {
6196
+ return new CliInputError("No default Linear team is configured.", "Pass --team-id=ID, or set a default team in Integrations -> Linear.");
6197
+ }
6198
+ return error;
6199
+ }
6101
6200
  async function runCommand(command, positional, flags, positionals = positional ? [positional] : [], context = createCommandContext({ command, positional, positionals, flags })) {
6102
6201
  switch (command) {
6103
6202
  case "prompts": {
@@ -6498,6 +6597,72 @@ async function runCommand(command, positional, flags, positionals = positional ?
6498
6597
  context.output.writeData(data);
6499
6598
  break;
6500
6599
  }
6600
+ case "problem-linear": {
6601
+ if (!positional) {
6602
+ throw new CliInputError("<problem_id> is required", "Usage: moda problem-linear <problem_id>");
6603
+ }
6604
+ if (!UUID_RE.test(positional)) {
6605
+ throw new CliInputError(`Problem id must be a canonical UUID; got "${positional}". Run \`moda problems\` to list problems with their canonical ids.`);
6606
+ }
6607
+ const data = await callDataAPI(`/problems/${positional}/linear`).catch((error) => {
6608
+ throw linearApiError(error);
6609
+ });
6610
+ const link = asRecord(data)?.link;
6611
+ const summary = describeLinearLink(link);
6612
+ const nextCommands = link ? [] : [`moda problem-linear-file ${positional}`];
6613
+ if (context.outputMode === "human" && !context.quiet) {
6614
+ safeWriteStderr(link ? `${summary}
6615
+ ` : `${summary} File one with: moda problem-linear-file ${positional}
6616
+ `);
6617
+ }
6618
+ context.output.writeData(data, { summary, nextCommands });
6619
+ break;
6620
+ }
6621
+ case "problem-linear-file": {
6622
+ const usage = "Usage: moda problem-linear-file <problem_id> [--issue=ENG-123|URL] [--team-id=ID] [--title=TEXT] [--priority=0-4]";
6623
+ if (!positional) {
6624
+ throw new CliInputError("<problem_id> is required", usage);
6625
+ }
6626
+ const params = ProblemLinearFileSchema.parse({
6627
+ id: positional,
6628
+ ...flags.issue !== undefined ? { issue: flags.issue } : {},
6629
+ ...flags["team-id"] !== undefined ? { team_id: flags["team-id"] } : {},
6630
+ ...flags.title !== undefined ? { title: flags.title } : {},
6631
+ ...flags.priority !== undefined ? { priority: flags.priority } : {}
6632
+ });
6633
+ if (!UUID_RE.test(params.id)) {
6634
+ throw new CliInputError(`Problem id must be a canonical UUID; got "${params.id}". Run \`moda problems\` to list problems with their canonical ids.`);
6635
+ }
6636
+ const issue = params.issue?.trim() ?? "";
6637
+ if (params.issue !== undefined && issue === "") {
6638
+ throw new CliInputError("--issue must be a Linear issue key (ENG-123) or URL.", usage);
6639
+ }
6640
+ if (issue !== "" && (params.team_id !== undefined || params.title !== undefined || params.priority !== undefined)) {
6641
+ throw new CliInputError("--issue links an existing issue and cannot be combined with --team-id, --title, or --priority.", usage);
6642
+ }
6643
+ const title = params.title?.trim() ?? "";
6644
+ const teamId = params.team_id?.trim() ?? "";
6645
+ const data = await callDataAPI(`/problems/${params.id}/linear`, {
6646
+ method: "POST",
6647
+ body: JSON.stringify(issue !== "" ? { issue } : {
6648
+ ...teamId !== "" ? { team_id: teamId } : {},
6649
+ ...title !== "" ? { title } : {},
6650
+ ...params.priority !== undefined ? { priority: params.priority } : {}
6651
+ }),
6652
+ headers: { "Content-Type": "application/json" }
6653
+ }, { retries: 0 }).catch((error) => {
6654
+ throw linearApiError(error);
6655
+ });
6656
+ const record = asRecord(data);
6657
+ const verb = issue !== "" ? "Linked" : record?.created === true ? "Filed" : "Already linked";
6658
+ const summary = `${verb}: ${describeLinearLink(record?.link)}`;
6659
+ if (context.outputMode === "human" && !context.quiet) {
6660
+ safeWriteStderr(`${summary}
6661
+ `);
6662
+ }
6663
+ context.output.writeData(data, { summary });
6664
+ break;
6665
+ }
6501
6666
  case "signals": {
6502
6667
  const data = await callDataAPI("/custom-signals");
6503
6668
  context.output.writeData(data);
@@ -6921,7 +7086,7 @@ var commandRegistry = createCommandRegistry([
6921
7086
  resetApiRequestCountBeforeRun: true,
6922
7087
  telemetry: "result",
6923
7088
  handler: async (context) => {
6924
- const { runInit } = await import("./index-pf2hvadv.js");
7089
+ const { runInit } = await import("./index-hwfe7gs8.js");
6925
7090
  if (context.outputMode === "agent-stream") {
6926
7091
  context.output.writeEvent({
6927
7092
  event: "started",
@@ -6930,7 +7095,7 @@ var commandRegistry = createCommandRegistry([
6930
7095
  elapsed_ms: Date.now() - context.startedAt
6931
7096
  });
6932
7097
  }
6933
- const result = await runInit(flagsToArgs(context.flags), {
7098
+ const result = await runInit(initFlagsForContext(context.flags, context.outputMode, process.stdin.isTTY === true), {
6934
7099
  onEvent: (event2) => {
6935
7100
  context.output.writeEvent({
6936
7101
  event: event2.status === "warning" ? "warning" : "progress",
@@ -6962,7 +7127,7 @@ var commandRegistry = createCommandRegistry([
6962
7127
  resetApiRequestCountBeforeRun: true,
6963
7128
  telemetry: "result-and-error",
6964
7129
  handler: async (context) => {
6965
- const { runProvision } = await import("./provision-d242y9qd.js");
7130
+ const { runProvision } = await import("./provision-64c2n9aw.js");
6966
7131
  return runProvision(context, {
6967
7132
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
6968
7133
  });
@@ -7001,6 +7166,7 @@ var commandRegistry = createCommandRegistry([
7001
7166
  "moda auth status",
7002
7167
  "moda auth status --online",
7003
7168
  "moda auth token",
7169
+ "moda auth api-key",
7004
7170
  "moda auth whoami",
7005
7171
  "moda auth logout"
7006
7172
  ],
@@ -7062,6 +7228,15 @@ var commandRegistry = createCommandRegistry([
7062
7228
  usage: "moda auth token",
7063
7229
  examples: ["moda auth token", 'curl -H "Authorization: Bearer $(moda auth token)" ...']
7064
7230
  },
7231
+ {
7232
+ name: "api-key",
7233
+ description: "Print the saved API key for $(moda auth api-key); pipe it, never echo it",
7234
+ usage: "moda auth api-key",
7235
+ examples: [
7236
+ 'MODA_API_KEY="$(moda auth api-key)" npm run dev',
7237
+ "moda auth api-key | wrangler secret put MODA_API_KEY"
7238
+ ]
7239
+ },
7065
7240
  {
7066
7241
  name: "logout",
7067
7242
  description: "Revoke and clear the browser session and any stored API key",
@@ -7342,6 +7517,23 @@ var commandRegistry = createCommandRegistry([
7342
7517
  ...dataApiDefaults,
7343
7518
  mutability: "write"
7344
7519
  }),
7520
+ legacyCommand({
7521
+ name: "problem-linear",
7522
+ description: "Show the Linear issue linked to a Problem (key, state, URL); needs Linear connected (Integrations -> Linear)",
7523
+ examples: ["moda problem-linear <problem_id>"],
7524
+ ...dataApiDefaults
7525
+ }),
7526
+ legacyCommand({
7527
+ name: "problem-linear-file",
7528
+ description: "File a Problem as a Linear issue in the team's tracker, or link an existing issue with --issue; needs Linear connected (Integrations -> Linear)",
7529
+ examples: [
7530
+ "moda problem-linear-file <problem_id>",
7531
+ 'moda problem-linear-file <problem_id> --team-id=<team_id> --title="CRM lookups time out" --priority=2',
7532
+ "moda problem-linear-file <problem_id> --issue=ENG-123"
7533
+ ],
7534
+ ...dataApiDefaults,
7535
+ mutability: "write"
7536
+ }),
7345
7537
  legacyCommand({
7346
7538
  name: "detection-reviews",
7347
7539
  description: "List problem detections on a trace with their review state (correct / false_positive / clear)",
@@ -7557,7 +7749,14 @@ var commandRegistry = createCommandRegistry([
7557
7749
  {
7558
7750
  name: "skills",
7559
7751
  description: "Generate, pull, and sync Moda skills",
7560
- examples: ["moda skills gen", "moda skills status", "moda skills pull", "moda skills sync"],
7752
+ examples: [
7753
+ "moda skills gen",
7754
+ "moda skills status",
7755
+ "moda skills pull",
7756
+ "moda skills sync",
7757
+ "moda skills install --list",
7758
+ "moda skills install integration-node-openai"
7759
+ ],
7561
7760
  auth: "none",
7562
7761
  outputModes: ["human", "json", "agent"],
7563
7762
  mutability: "write",
@@ -7878,9 +8077,11 @@ export {
7878
8077
  resolveTailSignal,
7879
8078
  printCliError,
7880
8079
  parseArgs,
8080
+ initFlagsForContext,
7881
8081
  flagsToArgs,
7882
8082
  dispatchParsedCommand,
7883
8083
  detectCallerAgent,
8084
+ describeLinearLink,
7884
8085
  commandRegistry,
7885
8086
  classifyCliError,
7886
8087
  buildResumeCommand,
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  buildSourceSnapshot
3
- } from "./cli-0p6n391h.js";
4
- import"./cli-drabjmaj.js";
3
+ } from "./cli-07tv75te.js";
4
+ import"./cli-q79sq80a.js";
5
+ import"./cli-0v6na3yp.js";
5
6
 
6
7
  // src/harness-github-actions.ts
7
8
  var DEFAULT_MODA_GITHUB_URL = "https://moda-github.modas.workers.dev";
@@ -42,8 +42,9 @@ import {
42
42
  writeHarnessAnalyzeResult,
43
43
  writeHarnessArtifacts,
44
44
  writeHumanProgress
45
- } from "./cli-0p6n391h.js";
46
- import"./cli-drabjmaj.js";
45
+ } from "./cli-07tv75te.js";
46
+ import"./cli-q79sq80a.js";
47
+ import"./cli-0v6na3yp.js";
47
48
  export {
48
49
  writeHumanProgress,
49
50
  writeHarnessArtifacts,