@moda-ai/cli 1.36.0 → 1.37.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-ert1sbbt.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-strngwn3.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,8 @@ 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)
5673
5724
  --ci-cd Create GitHub Actions Moda validation workflow
5674
5725
  --no-ci-cd Skip CI/CD workflow creation
5675
5726
  --autosync Create GitHub Actions workflow to sync prompts + skills to Moda on push to main
@@ -5741,6 +5792,8 @@ Examples:
5741
5792
  moda problems --days-back=7
5742
5793
  moda problem <problem_id> --evidence --limit=10
5743
5794
  moda problem-feedback <problem_id> --action=mark_fixed
5795
+ moda problem-linear <problem_id>
5796
+ moda problem-linear-file <problem_id> --priority=2
5744
5797
  moda detection-reviews <conversation_id>
5745
5798
  moda detection-review <problem_id> --conversation-id=<id> --attribution-id=<uuid> --verdict=false_positive --note="expected retry"
5746
5799
  moda signals
@@ -6098,6 +6151,50 @@ function detectCallerAgent(env) {
6098
6151
  return "agent";
6099
6152
  return "human";
6100
6153
  }
6154
+ var LINEAR_CONNECT_GUIDANCE = "Connect Linear in the Moda dashboard (Integrations -> Linear), then retry.";
6155
+ function describeLinearLink(linkValue) {
6156
+ const link = asRecord(linkValue);
6157
+ if (!link)
6158
+ return "No Linear issue linked to this Problem.";
6159
+ const issue = asRecord(link.issue);
6160
+ if (!issue) {
6161
+ return "A Linear issue is still being created for this Problem; re-run shortly.";
6162
+ }
6163
+ return [asString(issue.identifier), asString(issue.stateName), asString(issue.url)].filter((part) => part !== null && part !== "").join(" · ");
6164
+ }
6165
+ function linearApiError(error) {
6166
+ if (!(error instanceof ApiError))
6167
+ return error;
6168
+ let code;
6169
+ let message;
6170
+ try {
6171
+ const body = asRecord(JSON.parse(error.responseBody));
6172
+ code = asString(body?.error) ?? undefined;
6173
+ message = asString(body?.message) ?? undefined;
6174
+ } catch {
6175
+ code = undefined;
6176
+ }
6177
+ if (error.statusCode === 404 && code === "linear_not_enabled") {
6178
+ return new CliAccessError("The Linear integration is not enabled for this tenant.", {
6179
+ guidance: LINEAR_CONNECT_GUIDANCE
6180
+ });
6181
+ }
6182
+ if (error.statusCode === 404 && code === "problem_not_found") {
6183
+ return new CliInputError(`${message ?? "Problem not found"}.`, "Run `moda problems` to list problems with their canonical ids.");
6184
+ }
6185
+ if (error.statusCode === 409 && code === "not_connected") {
6186
+ return new CliAccessError("Linear is not connected, or a disconnect is still in progress.", {
6187
+ guidance: `If Linear was just disconnected, wait for that to finish. ${LINEAR_CONNECT_GUIDANCE}`
6188
+ });
6189
+ }
6190
+ if (error.statusCode === 409 && code === "needs_reauth") {
6191
+ return new CliAccessError("Linear needs to be reconnected.", { guidance: LINEAR_CONNECT_GUIDANCE });
6192
+ }
6193
+ if (error.statusCode === 400 && code === "no_team") {
6194
+ return new CliInputError("No default Linear team is configured.", "Pass --team-id=ID, or set a default team in Integrations -> Linear.");
6195
+ }
6196
+ return error;
6197
+ }
6101
6198
  async function runCommand(command, positional, flags, positionals = positional ? [positional] : [], context = createCommandContext({ command, positional, positionals, flags })) {
6102
6199
  switch (command) {
6103
6200
  case "prompts": {
@@ -6498,6 +6595,72 @@ async function runCommand(command, positional, flags, positionals = positional ?
6498
6595
  context.output.writeData(data);
6499
6596
  break;
6500
6597
  }
6598
+ case "problem-linear": {
6599
+ if (!positional) {
6600
+ throw new CliInputError("<problem_id> is required", "Usage: moda problem-linear <problem_id>");
6601
+ }
6602
+ if (!UUID_RE.test(positional)) {
6603
+ throw new CliInputError(`Problem id must be a canonical UUID; got "${positional}". Run \`moda problems\` to list problems with their canonical ids.`);
6604
+ }
6605
+ const data = await callDataAPI(`/problems/${positional}/linear`).catch((error) => {
6606
+ throw linearApiError(error);
6607
+ });
6608
+ const link = asRecord(data)?.link;
6609
+ const summary = describeLinearLink(link);
6610
+ const nextCommands = link ? [] : [`moda problem-linear-file ${positional}`];
6611
+ if (context.outputMode === "human" && !context.quiet) {
6612
+ safeWriteStderr(link ? `${summary}
6613
+ ` : `${summary} File one with: moda problem-linear-file ${positional}
6614
+ `);
6615
+ }
6616
+ context.output.writeData(data, { summary, nextCommands });
6617
+ break;
6618
+ }
6619
+ case "problem-linear-file": {
6620
+ const usage = "Usage: moda problem-linear-file <problem_id> [--issue=ENG-123|URL] [--team-id=ID] [--title=TEXT] [--priority=0-4]";
6621
+ if (!positional) {
6622
+ throw new CliInputError("<problem_id> is required", usage);
6623
+ }
6624
+ const params = ProblemLinearFileSchema.parse({
6625
+ id: positional,
6626
+ ...flags.issue !== undefined ? { issue: flags.issue } : {},
6627
+ ...flags["team-id"] !== undefined ? { team_id: flags["team-id"] } : {},
6628
+ ...flags.title !== undefined ? { title: flags.title } : {},
6629
+ ...flags.priority !== undefined ? { priority: flags.priority } : {}
6630
+ });
6631
+ if (!UUID_RE.test(params.id)) {
6632
+ throw new CliInputError(`Problem id must be a canonical UUID; got "${params.id}". Run \`moda problems\` to list problems with their canonical ids.`);
6633
+ }
6634
+ const issue = params.issue?.trim() ?? "";
6635
+ if (params.issue !== undefined && issue === "") {
6636
+ throw new CliInputError("--issue must be a Linear issue key (ENG-123) or URL.", usage);
6637
+ }
6638
+ if (issue !== "" && (params.team_id !== undefined || params.title !== undefined || params.priority !== undefined)) {
6639
+ throw new CliInputError("--issue links an existing issue and cannot be combined with --team-id, --title, or --priority.", usage);
6640
+ }
6641
+ const title = params.title?.trim() ?? "";
6642
+ const teamId = params.team_id?.trim() ?? "";
6643
+ const data = await callDataAPI(`/problems/${params.id}/linear`, {
6644
+ method: "POST",
6645
+ body: JSON.stringify(issue !== "" ? { issue } : {
6646
+ ...teamId !== "" ? { team_id: teamId } : {},
6647
+ ...title !== "" ? { title } : {},
6648
+ ...params.priority !== undefined ? { priority: params.priority } : {}
6649
+ }),
6650
+ headers: { "Content-Type": "application/json" }
6651
+ }, { retries: 0 }).catch((error) => {
6652
+ throw linearApiError(error);
6653
+ });
6654
+ const record = asRecord(data);
6655
+ const verb = issue !== "" ? "Linked" : record?.created === true ? "Filed" : "Already linked";
6656
+ const summary = `${verb}: ${describeLinearLink(record?.link)}`;
6657
+ if (context.outputMode === "human" && !context.quiet) {
6658
+ safeWriteStderr(`${summary}
6659
+ `);
6660
+ }
6661
+ context.output.writeData(data, { summary });
6662
+ break;
6663
+ }
6501
6664
  case "signals": {
6502
6665
  const data = await callDataAPI("/custom-signals");
6503
6666
  context.output.writeData(data);
@@ -6921,7 +7084,7 @@ var commandRegistry = createCommandRegistry([
6921
7084
  resetApiRequestCountBeforeRun: true,
6922
7085
  telemetry: "result",
6923
7086
  handler: async (context) => {
6924
- const { runInit } = await import("./index-pf2hvadv.js");
7087
+ const { runInit } = await import("./index-vmmfya6b.js");
6925
7088
  if (context.outputMode === "agent-stream") {
6926
7089
  context.output.writeEvent({
6927
7090
  event: "started",
@@ -6930,7 +7093,7 @@ var commandRegistry = createCommandRegistry([
6930
7093
  elapsed_ms: Date.now() - context.startedAt
6931
7094
  });
6932
7095
  }
6933
- const result = await runInit(flagsToArgs(context.flags), {
7096
+ const result = await runInit(initFlagsForContext(context.flags, context.outputMode, process.stdin.isTTY === true), {
6934
7097
  onEvent: (event2) => {
6935
7098
  context.output.writeEvent({
6936
7099
  event: event2.status === "warning" ? "warning" : "progress",
@@ -6962,7 +7125,7 @@ var commandRegistry = createCommandRegistry([
6962
7125
  resetApiRequestCountBeforeRun: true,
6963
7126
  telemetry: "result-and-error",
6964
7127
  handler: async (context) => {
6965
- const { runProvision } = await import("./provision-d242y9qd.js");
7128
+ const { runProvision } = await import("./provision-spwn5t41.js");
6966
7129
  return runProvision(context, {
6967
7130
  resumeCommand: buildResumeCommand("provision", context.rawFlags)
6968
7131
  });
@@ -7001,6 +7164,7 @@ var commandRegistry = createCommandRegistry([
7001
7164
  "moda auth status",
7002
7165
  "moda auth status --online",
7003
7166
  "moda auth token",
7167
+ "moda auth api-key",
7004
7168
  "moda auth whoami",
7005
7169
  "moda auth logout"
7006
7170
  ],
@@ -7062,6 +7226,15 @@ var commandRegistry = createCommandRegistry([
7062
7226
  usage: "moda auth token",
7063
7227
  examples: ["moda auth token", 'curl -H "Authorization: Bearer $(moda auth token)" ...']
7064
7228
  },
7229
+ {
7230
+ name: "api-key",
7231
+ description: "Print the saved API key for $(moda auth api-key); pipe it, never echo it",
7232
+ usage: "moda auth api-key",
7233
+ examples: [
7234
+ 'MODA_API_KEY="$(moda auth api-key)" npm run dev',
7235
+ "moda auth api-key | wrangler secret put MODA_API_KEY"
7236
+ ]
7237
+ },
7065
7238
  {
7066
7239
  name: "logout",
7067
7240
  description: "Revoke and clear the browser session and any stored API key",
@@ -7342,6 +7515,23 @@ var commandRegistry = createCommandRegistry([
7342
7515
  ...dataApiDefaults,
7343
7516
  mutability: "write"
7344
7517
  }),
7518
+ legacyCommand({
7519
+ name: "problem-linear",
7520
+ description: "Show the Linear issue linked to a Problem (key, state, URL); needs Linear connected (Integrations -> Linear)",
7521
+ examples: ["moda problem-linear <problem_id>"],
7522
+ ...dataApiDefaults
7523
+ }),
7524
+ legacyCommand({
7525
+ name: "problem-linear-file",
7526
+ 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)",
7527
+ examples: [
7528
+ "moda problem-linear-file <problem_id>",
7529
+ 'moda problem-linear-file <problem_id> --team-id=<team_id> --title="CRM lookups time out" --priority=2',
7530
+ "moda problem-linear-file <problem_id> --issue=ENG-123"
7531
+ ],
7532
+ ...dataApiDefaults,
7533
+ mutability: "write"
7534
+ }),
7345
7535
  legacyCommand({
7346
7536
  name: "detection-reviews",
7347
7537
  description: "List problem detections on a trace with their review state (correct / false_positive / clear)",
@@ -7557,7 +7747,14 @@ var commandRegistry = createCommandRegistry([
7557
7747
  {
7558
7748
  name: "skills",
7559
7749
  description: "Generate, pull, and sync Moda skills",
7560
- examples: ["moda skills gen", "moda skills status", "moda skills pull", "moda skills sync"],
7750
+ examples: [
7751
+ "moda skills gen",
7752
+ "moda skills status",
7753
+ "moda skills pull",
7754
+ "moda skills sync",
7755
+ "moda skills install --list",
7756
+ "moda skills install integration-node-openai"
7757
+ ],
7561
7758
  auth: "none",
7562
7759
  outputModes: ["human", "json", "agent"],
7563
7760
  mutability: "write",
@@ -7878,9 +8075,11 @@ export {
7878
8075
  resolveTailSignal,
7879
8076
  printCliError,
7880
8077
  parseArgs,
8078
+ initFlagsForContext,
7881
8079
  flagsToArgs,
7882
8080
  dispatchParsedCommand,
7883
8081
  detectCallerAgent,
8082
+ describeLinearLink,
7884
8083
  commandRegistry,
7885
8084
  classifyCliError,
7886
8085
  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,