@moda-ai/cli 1.55.43 → 1.55.45

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 (40) hide show
  1. package/README.md +1 -1
  2. package/dist/{agent-x1gwrrvd.js → agent-5ax7fqhe.js} +8 -8
  3. package/dist/{cli-5y9tj6cb.js → cli-4m0rgkx4.js} +7 -2
  4. package/dist/{cli-daqkdnm1.js → cli-4pc0a18x.js} +1 -1
  5. package/dist/{cli-1z1sx8dg.js → cli-5aa48ry5.js} +5 -4
  6. package/dist/{cli-5fhqfx04.js → cli-8pcq2et6.js} +1 -1
  7. package/dist/{cli-fpd1pfvt.js → cli-8pksf2x7.js} +5 -5
  8. package/dist/{cli-s1w5phms.js → cli-d4cdczhe.js} +5 -5
  9. package/dist/{cli-0xc5htv7.js → cli-dmm9jm9m.js} +1 -1
  10. package/dist/{cli-t0pb7qbs.js → cli-e24fjyrb.js} +118 -10
  11. package/dist/{cli-pmzh2qjy.js → cli-sejqvvhv.js} +14 -6
  12. package/dist/{cli-h62j4jn7.js → cli-t4xfvrry.js} +34 -15
  13. package/dist/{cli-9a0a3v13.js → cli-tztzrh6b.js} +2 -2
  14. package/dist/{cli-k5drmy8r.js → cli-wwbr5caw.js} +8 -8
  15. package/dist/{cli-77ekrx7d.js → cli-xcpwp0gb.js} +14 -7
  16. package/dist/{cli-stfpr2ct.js → cli-xx0pjzkh.js} +4 -4
  17. package/dist/cli.js +33 -29
  18. package/dist/{doctor-wrgajgev.js → doctor-k4tdgvgv.js} +7 -7
  19. package/dist/{fix-7aajsdbf.js → fix-nk5xffz8.js} +4 -4
  20. package/dist/{harness-1rn1hqzz.js → harness-avynbq4f.js} +5 -5
  21. package/dist/{harness-github-actions-m95qvgbs.js → harness-github-actions-gd6vyxb0.js} +5 -5
  22. package/dist/{index-svfzq5rb.js → index-63k2a6gb.js} +11 -11
  23. package/dist/{production-intelligence-7jvfdz6b.js → production-intelligence-0z6v6tpp.js} +5 -3
  24. package/dist/{profile-commands-se9947c1.js → profile-commands-mh3kfqkn.js} +98 -20
  25. package/dist/{prompt-attribution-hc6mcvee.js → prompt-attribution-wvvnzw4m.js} +5 -5
  26. package/dist/prompt-source-mcp.js +5 -5
  27. package/dist/{prompts-ab-ws66335h.js → prompts-ab-y7egdzg4.js} +7 -7
  28. package/dist/{prompts-propose-a9m0p9nr.js → prompts-propose-5nw25v9a.js} +7 -7
  29. package/dist/{prompts-xe5bgbx8.js → prompts-snnbyxmz.js} +5 -5
  30. package/dist/{provision-a9kkfvp7.js → provision-t1dpzcjp.js} +5 -5
  31. package/dist/{registry-j2dsfh6v.js → registry-8zkxefjs.js} +3 -3
  32. package/dist/{skills-vveagdwe.js → skills-d4215fa9.js} +5 -5
  33. package/dist/{sync-yy3fgnxe.js → sync-17f9yxb1.js} +7 -7
  34. package/package.json +1 -1
  35. package/skills/integration/index.json +2 -2
  36. package/skills/moda-cli/SKILL.md +4 -3
  37. package/skills/moda-cli/references/auth.md +16 -7
  38. package/skills/moda-cli/references/output-protocol.md +1 -1
  39. package/skills/moda-cli/references/search-and-traces.md +3 -1
  40. package/skills/moda-cli/references/troubleshooting.md +14 -0
package/README.md CHANGED
@@ -416,7 +416,7 @@ Both commands accept two flags to inline a message window per row:
416
416
  | Variable | Required | Default | Description |
417
417
  |----------|----------|---------|-------------|
418
418
  | `MODA_API_KEY` | Yes | -- | Your Moda API key (`moda_sk_...`) |
419
- | `MODA_BASE_URL` | No | `https://moda.dev` | Base URL for the Data API |
419
+ | `MODA_BASE_URL` | No | `https://moda.dev` | Base URL for the Data API. A loopback URL needs a non-prod profile (`MODA_PROFILE=local`); on a prod profile commands exit 5 before sending anything |
420
420
 
421
421
  ## Documentation
422
422
 
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  buildDoctorReport
3
- } from "./cli-h62j4jn7.js";
4
- import"./cli-pmzh2qjy.js";
5
- import"./cli-k5drmy8r.js";
3
+ } from "./cli-t4xfvrry.js";
4
+ import"./cli-sejqvvhv.js";
5
+ import"./cli-wwbr5caw.js";
6
6
  import"./cli-mm48br00.js";
7
7
  import {
8
8
  readHarnessSyncState
@@ -15,16 +15,16 @@ import {
15
15
  readHarnessReport,
16
16
  validateHarnessReport
17
17
  } from "./cli-cesds766.js";
18
- import"./cli-5fhqfx04.js";
18
+ import"./cli-8pcq2et6.js";
19
19
  import"./cli-e0kbye4s.js";
20
- import"./cli-9a0a3v13.js";
21
- import"./cli-0xc5htv7.js";
20
+ import"./cli-tztzrh6b.js";
21
+ import"./cli-dmm9jm9m.js";
22
22
  import {
23
23
  resolveApiKey,
24
24
  resolveIngestUrl,
25
25
  resolveModaBaseUrl,
26
26
  resolveTenantId
27
- } from "./cli-t0pb7qbs.js";
27
+ } from "./cli-e24fjyrb.js";
28
28
  import {
29
29
  CliInputError
30
30
  } from "./cli-k4tqwah4.js";
@@ -95,7 +95,7 @@ async function buildAgentContext(context) {
95
95
  const graph = readHarnessGraphIfPresent(context.cwd);
96
96
  const reportState = readHarnessReportState(context.cwd);
97
97
  const syncState = readHarnessSyncState(context.cwd);
98
- const harness = graph ? await import("./harness-1rn1hqzz.js") : undefined;
98
+ const harness = graph ? await import("./harness-avynbq4f.js") : undefined;
99
99
  const topFindings = doctor.checks.filter((check) => check.status === "fail" || check.status === "warning").slice(0, 12).map(checkToFinding);
100
100
  const evidenceRefs = [
101
101
  ...doctor.checks.map(checkToEvidenceRef),
@@ -3,10 +3,10 @@ import {
3
3
  } from "./cli-e0kbye4s.js";
4
4
  import {
5
5
  callDataAPI
6
- } from "./cli-0xc5htv7.js";
6
+ } from "./cli-dmm9jm9m.js";
7
7
  import {
8
8
  shellArg
9
- } from "./cli-t0pb7qbs.js";
9
+ } from "./cli-e24fjyrb.js";
10
10
  import {
11
11
  CliInputError
12
12
  } from "./cli-k4tqwah4.js";
@@ -854,6 +854,11 @@ var MODA_INTELLIGENCE_V1_JSON_SCHEMA = {
854
854
  }
855
855
  },
856
856
  warnings: { type: "array", items: { type: "string" } },
857
+ caveats: {
858
+ type: "object",
859
+ required: ["version"],
860
+ properties: { version: { const: "moda.caveats.v1" } }
861
+ },
857
862
  meta: { type: "object" }
858
863
  }
859
864
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  callControlAPI
3
- } from "./cli-0xc5htv7.js";
3
+ } from "./cli-dmm9jm9m.js";
4
4
 
5
5
  // src/replay-runs.ts
6
6
  var DEFAULT_POLL_INTERVAL_MS = 15000;
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  fetchApiKeyProbe
3
- } from "./cli-77ekrx7d.js";
3
+ } from "./cli-xcpwp0gb.js";
4
4
  import {
5
5
  authFetch,
6
6
  getCachedLoginContext
7
- } from "./cli-pmzh2qjy.js";
7
+ } from "./cli-sejqvvhv.js";
8
8
  import {
9
9
  embeddedTenantIdFromApiKey,
10
10
  getModaDir,
@@ -15,7 +15,7 @@ import {
15
15
  resolveTenantIdFromActiveProfile,
16
16
  saveCliConfig,
17
17
  writeSecretJsonFile
18
- } from "./cli-t0pb7qbs.js";
18
+ } from "./cli-e24fjyrb.js";
19
19
  import {
20
20
  CliAccessError,
21
21
  CliInputError,
@@ -118,8 +118,9 @@ function bootstrapLabel(custom) {
118
118
  }
119
119
  var embeddedTenantId = embeddedTenantIdFromApiKey;
120
120
  async function isStoredKeyLive(key, options = {}) {
121
+ const baseUrl = resolveModaBaseUrl(options);
121
122
  try {
122
- const response = await fetchApiKeyProbe(resolveModaBaseUrl(options), { "x-api-key": key }, VALIDATE_TIMEOUT_MS);
123
+ const response = await fetchApiKeyProbe(baseUrl, { "x-api-key": key }, VALIDATE_TIMEOUT_MS);
123
124
  if (response.status !== 200)
124
125
  return false;
125
126
  await response.json();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  createCliOutput,
3
3
  outputModeFromFlags
4
- } from "./cli-t0pb7qbs.js";
4
+ } from "./cli-e24fjyrb.js";
5
5
 
6
6
  // src/command-context.ts
7
7
  function flagEnabled(flags, key) {
@@ -4,19 +4,19 @@ import {
4
4
  parsePromptFileForAb,
5
5
  readPromptLock,
6
6
  runPromptSync
7
- } from "./cli-k5drmy8r.js";
7
+ } from "./cli-wwbr5caw.js";
8
8
  import {
9
9
  DEFAULT_POLL_INTERVAL_MS,
10
10
  DEFAULT_WAIT_TIMEOUT_MS,
11
11
  fetchLatestRun
12
- } from "./cli-daqkdnm1.js";
12
+ } from "./cli-4pc0a18x.js";
13
13
  import {
14
14
  UUID_RE
15
- } from "./cli-9a0a3v13.js";
15
+ } from "./cli-tztzrh6b.js";
16
16
  import {
17
17
  callControlAPI,
18
18
  callDataAPI
19
- } from "./cli-0xc5htv7.js";
19
+ } from "./cli-dmm9jm9m.js";
20
20
  import {
21
21
  EXIT_ERROR,
22
22
  EXIT_OK,
@@ -24,7 +24,7 @@ import {
24
24
  setPlatformTenantOverride,
25
25
  shellArg,
26
26
  validateConfig
27
- } from "./cli-t0pb7qbs.js";
27
+ } from "./cli-e24fjyrb.js";
28
28
  import {
29
29
  CliInputError
30
30
  } from "./cli-k4tqwah4.js";
@@ -44,16 +44,16 @@ import {
44
44
  import {
45
45
  createCommandContext,
46
46
  stringOption
47
- } from "./cli-5fhqfx04.js";
47
+ } from "./cli-8pcq2et6.js";
48
48
  import {
49
49
  assertFlags,
50
50
  assertPositionals,
51
51
  requireTenant
52
- } from "./cli-9a0a3v13.js";
52
+ } from "./cli-tztzrh6b.js";
53
53
  import {
54
54
  ApiError,
55
55
  callControlAPI
56
- } from "./cli-0xc5htv7.js";
56
+ } from "./cli-dmm9jm9m.js";
57
57
  import {
58
58
  embeddedTenantIdFromApiKey,
59
59
  getActiveProfile,
@@ -63,7 +63,7 @@ import {
63
63
  resolveModaBaseUrl,
64
64
  resolveTenantId,
65
65
  shellArg
66
- } from "./cli-t0pb7qbs.js";
66
+ } from "./cli-e24fjyrb.js";
67
67
  import {
68
68
  CliInputError,
69
69
  CliInputRequiredError
@@ -14048,7 +14048,7 @@ async function runHarnessCommand(context) {
14048
14048
  throw new CliInputError("Focused remote prompt analysis is not supported yet.", "Use local --analyst=claude|codex|cursor|local-scan, or drop --concern for a full remote report.");
14049
14049
  }
14050
14050
  if (context.flags["github-actions"] === "true") {
14051
- const { runGithubActionsAnalyze } = await import("./harness-github-actions-m95qvgbs.js");
14051
+ const { runGithubActionsAnalyze } = await import("./harness-github-actions-gd6vyxb0.js");
14052
14052
  const result = await runGithubActionsAnalyze(rootDir, {
14053
14053
  writeReport: (report2) => {
14054
14054
  const normalized = normalizeHarnessReport(report2);
@@ -3,7 +3,7 @@ import {
3
3
  recordApiRequest,
4
4
  resolveApiKey,
5
5
  resolveModaBaseUrl
6
- } from "./cli-t0pb7qbs.js";
6
+ } from "./cli-e24fjyrb.js";
7
7
 
8
8
  // src/api-client.ts
9
9
  var REQUEST_TIMEOUT_MS = 30000;
@@ -111,8 +111,14 @@ function createDefaultProfiles(options = {}) {
111
111
  };
112
112
  }
113
113
  function isLoopbackHostname(hostname) {
114
- const host = hostname.toLowerCase();
115
- return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
114
+ const host = hostname.toLowerCase().replace(/^\[|\]$/g, "").replace(/\.$/, "");
115
+ if (host === "localhost" || host.endsWith(".localhost"))
116
+ return true;
117
+ if (/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host) || host === "0.0.0.0")
118
+ return true;
119
+ if (host === "::1" || host === "::")
120
+ return true;
121
+ return /^::ffff:(7f[0-9a-f]{2}:[0-9a-f]{1,4}|127\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.test(host);
116
122
  }
117
123
  function isLoopbackBaseUrl(url) {
118
124
  try {
@@ -287,16 +293,33 @@ function profileBaseUrlOrigin(name, options = {}) {
287
293
  return sanitizeProfileBaseUrl(url, environment) === normalizeModaBaseUrl(url) ? "profile" : "default";
288
294
  }
289
295
  function describeBaseUrlSource(options) {
290
- const envBase = optionalString(getEnv(options).MODA_BASE_URL);
291
- if (envBase) {
292
- const environment = activeProfileEnvironment(options);
293
- if (!environmentAllowsLoopback(environment) && isLoopbackBaseUrl(normalizeModaBaseUrl(envBase))) {
294
- return `default (env:MODA_BASE_URL loopback ignored for ${environment} profile)`;
295
- }
296
- return "env:MODA_BASE_URL";
296
+ const refused = refusedLoopbackBaseUrl(options);
297
+ if (refused) {
298
+ return `refused (env:MODA_BASE_URL is loopback and the active profile '${refused.profile}' is ${refused.environment})`;
297
299
  }
300
+ if (optionalString(getEnv(options).MODA_BASE_URL))
301
+ return "env:MODA_BASE_URL";
298
302
  return profileBaseUrlOrigin(options.profile, options);
299
303
  }
304
+ function refusedLoopbackBaseUrl(options = {}) {
305
+ const envBase = optionalString(getEnv(options).MODA_BASE_URL);
306
+ if (!envBase)
307
+ return;
308
+ const url = normalizeModaBaseUrl(envBase);
309
+ if (!isLoopbackBaseUrl(url))
310
+ return;
311
+ let profile;
312
+ let environment;
313
+ try {
314
+ const active = getActiveProfile(options);
315
+ profile = active.name;
316
+ environment = active.environment;
317
+ } catch {
318
+ profile = optionalString(options.profile) ?? optionalString(getEnv(options).MODA_PROFILE) ?? DEFAULT_PROFILE_NAME;
319
+ environment = "prod";
320
+ }
321
+ return environmentAllowsLoopback(environment) ? undefined : { url, profile, environment };
322
+ }
300
323
  function loadProfileConfig(options = {}) {
301
324
  const path = getModaPaths(options).profileConfigPath;
302
325
  const parsed = safeReadRecord(path);
@@ -471,6 +494,8 @@ function resolveBaseUrlStrict(options = {}) {
471
494
  } catch {
472
495
  return;
473
496
  }
497
+ if (refusedLoopbackBaseUrl(options))
498
+ return;
474
499
  return resolveBaseUrl(options);
475
500
  }
476
501
  function resolveIngestUrl(options = {}) {
@@ -600,8 +625,29 @@ function resolveApiTenantId(options = {}) {
600
625
  return (apiKey ? embeddedTenantIdFromApiKey(apiKey) : undefined) || resolveTenantId(options);
601
626
  }
602
627
  function resolveModaBaseUrl(options = {}) {
628
+ const refused = refusedLoopbackBaseUrl(options);
629
+ if (refused)
630
+ throw refusedBaseUrlError(refused);
603
631
  return resolveBaseUrl(options) || PROD_BASE_URL;
604
632
  }
633
+ function describeModaBaseUrl(options = {}) {
634
+ const refused = refusedLoopbackBaseUrl(options);
635
+ return refused ? { url: refused.url, refused } : { url: resolveBaseUrl(options) || PROD_BASE_URL };
636
+ }
637
+ function refusedBaseUrlMessage(refused) {
638
+ return `MODA_BASE_URL=${refused.url} is a loopback URL, and the active profile '${refused.profile}' is a ${refused.environment} profile. ` + "The CLI does not send a prod profile's credentials to a loopback server, and does not send requests meant for it to production instead.";
639
+ }
640
+ function refusedBaseUrlError(refused) {
641
+ return new CliInputRequiredError(`${refusedBaseUrlMessage(refused)} Nothing was sent.`, {
642
+ id: "moda_base_url_refused",
643
+ question: `Target the local stack at ${refused.url} with the local profile, or production with MODA_BASE_URL unset?`,
644
+ kind: "select",
645
+ choices: [
646
+ { value: "local", label: `Use the local profile for ${refused.url}`, resume_flags: ["--profile=local"] },
647
+ { value: "production", label: "Use production: unset MODA_BASE_URL and re-run unchanged", resume_flags: [] }
648
+ ]
649
+ }, "Re-run with --profile=local (or MODA_PROFILE=local) to use the local stack, or unset MODA_BASE_URL to use production.");
650
+ }
605
651
  function resolveModaBaseUrlStrict(options = {}) {
606
652
  return resolveBaseUrlStrict(options);
607
653
  }
@@ -660,6 +706,64 @@ function shellArg(value) {
660
706
  return `'${value.replace(/'/g, `'\\''`)}'`;
661
707
  }
662
708
 
709
+ // src/api-access-errors.ts
710
+ var MESSAGE_PATTERNS = [
711
+ [/unknown or deleted tenant|does not exist or is not accessible/i, "tenant_not_found"],
712
+ [/pinned to another tenant|cannot select another/i, "tenant_not_accessible"],
713
+ [/does not match the tenant in the url/i, "tenant_mismatch"],
714
+ [/api key is read-only/i, "read_only_key"]
715
+ ];
716
+ var REASONS = new Set(MESSAGE_PATTERNS.map(([, reason]) => reason));
717
+ function apiForbiddenReason(code, message) {
718
+ if (code && REASONS.has(code))
719
+ return code;
720
+ if (!message)
721
+ return;
722
+ return MESSAGE_PATTERNS.find(([pattern]) => pattern.test(message))?.[1];
723
+ }
724
+ function errorBodyFields(body) {
725
+ if (typeof body !== "string" || !body.trimStart().startsWith("{"))
726
+ return {};
727
+ try {
728
+ const parsed = JSON.parse(body);
729
+ return {
730
+ ...typeof parsed.code === "string" ? { code: parsed.code } : {},
731
+ ...typeof parsed.message === "string" ? { message: parsed.message } : {}
732
+ };
733
+ } catch {
734
+ return {};
735
+ }
736
+ }
737
+ function apiForbiddenError(reason, serverMessage) {
738
+ const server = serverMessage?.trim().replace(/\.$/, "");
739
+ switch (reason) {
740
+ case "tenant_not_found":
741
+ return {
742
+ code: "not_found",
743
+ message: server && /does not exist/i.test(server) ? `${server} (HTTP 403).` : "The tenant this request names does not exist or is not accessible to this API key (HTTP 403).",
744
+ cause: "The tenant id comes from MODA_TENANT_ID (or --tenant-id). No tenant has that id, or it was deleted. " + "Set it to a tenant id from the dashboard URL or from `moda auth whoami` with a browser session, then retry."
745
+ };
746
+ case "tenant_not_accessible":
747
+ return {
748
+ code: "access_denied",
749
+ message: `The Moda API refused this request (HTTP 403): ${server ?? "this API key cannot act on the tenant requested"}.`,
750
+ cause: "This key acts on one tenant only. Unset MODA_TENANT_ID (and drop --tenant-id) so it acts on its own tenant, " + "or use a key for the tenant you want. With MODA_TENANT_ID unset, `moda auth whoami` shows the key's tenant."
751
+ };
752
+ case "tenant_mismatch":
753
+ return {
754
+ code: "access_denied",
755
+ message: `The Moda API refused this request (HTTP 403): ${server ?? "the tenant header does not match the tenant in the URL"}.`,
756
+ cause: "MODA_TENANT_ID names a different tenant than this command. Make them the same tenant, or unset MODA_TENANT_ID."
757
+ };
758
+ case "read_only_key":
759
+ return {
760
+ code: "access_denied",
761
+ message: `The Moda API refused this request (HTTP 403): ${server ?? "this API key is read-only"}.`,
762
+ cause: "This key is read-only: it can run reads but not writes. Run this command with a full-access key."
763
+ };
764
+ }
765
+ }
766
+
663
767
  // src/legacy-names.ts
664
768
  var LEGACY_NAMES = [
665
769
  { legacy: "conversations", use: "moda traces list", canonical: { command: "traces", subcommand: "list" }, silent: true },
@@ -1613,6 +1717,10 @@ function errorToAgentError(error) {
1613
1717
  };
1614
1718
  }
1615
1719
  if (apiErrorStatus(error) === 403) {
1720
+ const body = errorBodyFields(error.responseBody);
1721
+ const reason = apiForbiddenReason(body.code, body.message);
1722
+ if (reason)
1723
+ return { ...apiForbiddenError(reason, body.message), blocking: true };
1616
1724
  return {
1617
1725
  code: "access_denied",
1618
1726
  message: `The Moda API refused this request (HTTP 403): ${serverErrorMessage(error) ?? "the API key does not allow it"}.`,
@@ -2187,4 +2295,4 @@ function extractSuggestedCommands(text) {
2187
2295
  return commands.length > 0 ? commands : undefined;
2188
2296
  }
2189
2297
 
2190
- export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, resolveModaBaseUrlStrict, validateConfig, isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, recordApiRequest, getApiRequestCount, resetApiRequestCount, shellArg, LEGACY_NAMES, canonicalCommandText, setAgentUpdateNotice, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, outputModeFromFlags, resolveOutputMode, createCliOutput, agentEnvelopeFits, errorToAgentError, agentMaxOutputBytes, continuationCommand };
2298
+ export { PROD_BASE_URL, DEFAULT_INGEST_URL, getModaPaths, getModaDir, isLoopbackBaseUrl, describeBaseUrlSource, loadProfileConfig, saveProfileConfig, getActiveProfile, setActiveProfile, upsertProfile, clearStoredApiKeyCredentials, secretFilePathFromRef, resolveSecretReference, resolveApiKeyFromActiveProfile, resolveTenantIdFromActiveProfile, ensureSecretFilePermissions, writeSecretJsonFile, VERSION, MODA_BASE_URL, loadCliConfig, saveCliConfig, resolveApiKey, embeddedTenantIdFromApiKey, resolveIngestUrl2 as resolveIngestUrl, resolveTenantId, resolveApiTenantId, resolveModaBaseUrl, describeModaBaseUrl, refusedBaseUrlMessage, resolveModaBaseUrlStrict, validateConfig, isPlatformApiKey, setPlatformTenantOverride, apiKeyHeaders, recordApiRequest, getApiRequestCount, resetApiRequestCount, shellArg, apiForbiddenReason, errorBodyFields, apiForbiddenError, LEGACY_NAMES, canonicalCommandText, setAgentUpdateNotice, EXIT_OK, EXIT_ERROR, EXIT_DEGRADED, EXIT_AUTH_REQUIRED, EXIT_INPUT_REQUIRED, EXIT_CANCELLED, AGENT_ERROR_CODES, wasOutputCancelled, safeWriteStdout, safeWriteStderr, explicitOutputMode, outputModeFromFlags, resolveOutputMode, createCliOutput, agentEnvelopeFits, errorToAgentError, agentMaxOutputBytes, continuationCommand };
@@ -6,7 +6,7 @@ import {
6
6
  saveProfileConfig,
7
7
  secretFilePathFromRef,
8
8
  writeSecretJsonFile
9
- } from "./cli-t0pb7qbs.js";
9
+ } from "./cli-e24fjyrb.js";
10
10
  import {
11
11
  CliAuthError,
12
12
  CliInputError
@@ -345,10 +345,11 @@ async function connectWithCode(code, options = {}) {
345
345
  if (!CONNECT_CODE_RE.test(code)) {
346
346
  throw new ConnectCodeError("That is not a Moda sign-in code. Copy the command from the Moda onboarding page again.", "rejected");
347
347
  }
348
+ const baseUrl = resolveModaBaseUrl(options);
348
349
  let response;
349
350
  try {
350
351
  recordApiRequest();
351
- response = await fetch(`${resolveModaBaseUrl(options)}/api/cli/auth/connect`, {
352
+ response = await fetch(`${baseUrl}/api/cli/auth/connect`, {
352
353
  method: "POST",
353
354
  headers: { "Content-Type": "application/json" },
354
355
  body: JSON.stringify({ code, label: hostname(), ...options.tenantId ? { tenant_id: options.tenantId } : {} }),
@@ -452,6 +453,13 @@ async function login(screen = "login", options = {}) {
452
453
  reject(new CliInputError(`Moda profile '${targetProfile}' does not exist.`, 'Create it with "moda profiles create <name>" or check "moda profiles list".'));
453
454
  return;
454
455
  }
456
+ let baseUrl;
457
+ try {
458
+ baseUrl = resolveModaBaseUrl(storageOptions);
459
+ } catch (err) {
460
+ reject(err);
461
+ return;
462
+ }
455
463
  const server = createServer(async (req, res) => {
456
464
  if (settled) {
457
465
  res.writeHead(410, { Connection: "close" });
@@ -480,7 +488,7 @@ async function login(screen = "login", options = {}) {
480
488
  try {
481
489
  const cliToken = await exchangeCodeForSession(code);
482
490
  res.writeHead(302, {
483
- Location: `${resolveModaBaseUrl(storageOptions)}/auth/cli/done?status=success`,
491
+ Location: `${baseUrl}/auth/cli/done?status=success`,
484
492
  Connection: "close"
485
493
  });
486
494
  res.end(() => {
@@ -490,7 +498,7 @@ async function login(screen = "login", options = {}) {
490
498
  exchangeInFlight = false;
491
499
  const error2 = err instanceof Error ? err : new Error(String(err));
492
500
  res.writeHead(302, {
493
- Location: `${resolveModaBaseUrl(storageOptions)}/auth/cli/done?status=error&reason=${exchangeFailureReason(err)}`,
501
+ Location: `${baseUrl}/auth/cli/done?status=error&reason=${exchangeFailureReason(err)}`,
494
502
  Connection: "close"
495
503
  });
496
504
  res.end(() => {
@@ -598,7 +606,7 @@ async function login(screen = "login", options = {}) {
598
606
  let response;
599
607
  try {
600
608
  recordApiRequest();
601
- response = await fetch(`${resolveModaBaseUrl(storageOptions)}/api/cli/auth/exchange`, {
609
+ response = await fetch(`${baseUrl}/api/cli/auth/exchange`, {
602
610
  method: "POST",
603
611
  headers: { "Content-Type": "application/json" },
604
612
  body: JSON.stringify({
@@ -762,7 +770,7 @@ async function login(screen = "login", options = {}) {
762
770
  if (address && typeof address === "object") {
763
771
  localPort = address.port;
764
772
  }
765
- const authUrl = `${resolveModaBaseUrl(storageOptions)}/auth/cli?port=${localPort}&screen=${screen}&state=${state}&code_challenge=${codeChallenge}&challenge_method=S256`;
773
+ const authUrl = `${baseUrl}/auth/cli?port=${localPort}&screen=${screen}&state=${state}&code_challenge=${codeChallenge}&challenge_method=S256`;
766
774
  attachPromptInput();
767
775
  try {
768
776
  await (options.openUrl ?? openAuthUrl)(authUrl);
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isAuthSessionValid,
3
3
  loadAuthSession
4
- } from "./cli-pmzh2qjy.js";
4
+ } from "./cli-sejqvvhv.js";
5
5
  import {
6
6
  inspectPromptManifest
7
- } from "./cli-k5drmy8r.js";
7
+ } from "./cli-wwbr5caw.js";
8
8
  import {
9
9
  readHarnessSyncState,
10
10
  renderDoctorHuman,
@@ -12,21 +12,22 @@ import {
12
12
  } from "./cli-xq45etg1.js";
13
13
  import {
14
14
  callDataAPI
15
- } from "./cli-0xc5htv7.js";
15
+ } from "./cli-dmm9jm9m.js";
16
16
  import {
17
+ describeModaBaseUrl,
17
18
  ensureSecretFilePermissions,
18
19
  getActiveProfile,
19
20
  getModaPaths,
20
21
  isLoopbackBaseUrl,
21
22
  loadProfileConfig,
22
23
  recordApiRequest,
24
+ refusedBaseUrlMessage,
23
25
  resolveApiKey,
24
26
  resolveIngestUrl,
25
- resolveModaBaseUrl,
26
27
  resolveSecretReference,
27
28
  resolveTenantId,
28
29
  secretFilePathFromRef
29
- } from "./cli-t0pb7qbs.js";
30
+ } from "./cli-e24fjyrb.js";
30
31
  import {
31
32
  __require
32
33
  } from "./cli-0v6na3yp.js";
@@ -65,7 +66,7 @@ async function runStatusCommand(context) {
65
66
  },
66
67
  workspace: {
67
68
  tenantId: resolveTenantId() ?? null,
68
- baseUrl: resolveModaBaseUrl(),
69
+ baseUrl: describeModaBaseUrl().url,
69
70
  ingestUrl: resolveIngestUrl()
70
71
  },
71
72
  dataFlow: checkStatus(report.checks, "cloud_data_flow"),
@@ -102,7 +103,8 @@ async function buildDoctorReport(context, options) {
102
103
  const profileOptions = { profile: context.profile, env: context.env };
103
104
  const apiKey = resolveApiKey(profileOptions);
104
105
  const tenantId = resolveTenantId(profileOptions);
105
- const baseUrl = resolveModaBaseUrl(profileOptions);
106
+ const base = describeModaBaseUrl(profileOptions);
107
+ const baseUrl = base.url;
106
108
  const ingestUrl = resolveIngestUrl(profileOptions);
107
109
  checks.push({
108
110
  id: "active_profile_resolves",
@@ -157,6 +159,8 @@ async function buildDoctorReport(context, options) {
157
159
  checks.push(urlCheck("base_url_valid", "config", "Base URL is valid", baseUrl));
158
160
  checks.push(urlCheck("ingest_url_valid", "config", "Ingest URL is valid", ingestUrl));
159
161
  checks.push(localBaseUrlCheck(activeProfile.environment, baseUrl));
162
+ if (base.refused)
163
+ checks.push(refusedBaseUrlCheck(base.refused));
160
164
  const manifestPath = join(context.cwd, ".moda", "harness.json");
161
165
  const manifestExists = existsSync(manifestPath);
162
166
  checks.push({
@@ -183,8 +187,8 @@ async function buildDoctorReport(context, options) {
183
187
  "__tests__"
184
188
  ]));
185
189
  checks.push(validationEventPathCheck(ingestUrl));
186
- if (options.offline || !apiKey) {
187
- checks.push(...offlineCloudChecks(options.offline));
190
+ if (options.offline || !apiKey || base.refused) {
191
+ checks.push(...offlineCloudChecks(options.offline, Boolean(base.refused)));
188
192
  } else {
189
193
  checks.push(...await cloudDataFlowChecks(ingestUrl, apiKey));
190
194
  }
@@ -278,6 +282,21 @@ function secretPermissionCheck(path) {
278
282
  remediation: permission.secure ? undefined : "Restrict secret file permissions to the current user."
279
283
  };
280
284
  }
285
+ function refusedBaseUrlCheck(refused) {
286
+ return {
287
+ id: "base_url_not_refused",
288
+ group: "config",
289
+ title: "Base URL is usable with the active profile",
290
+ status: "fail",
291
+ severity: "critical",
292
+ evidence: [
293
+ { label: "MODA_BASE_URL", value: refused.url },
294
+ { label: "profile", value: `${refused.profile} (${refused.environment})` }
295
+ ],
296
+ remediation: `${refusedBaseUrlMessage(refused)} Re-run with --profile=local (or MODA_PROFILE=local) for the local stack, or unset MODA_BASE_URL for production.`,
297
+ nextCommand: "moda status --profile=local"
298
+ };
299
+ }
281
300
  function urlCheck(id, group, title, value) {
282
301
  let valid = false;
283
302
  try {
@@ -376,7 +395,7 @@ async function harnessCurrentCheck(cwd, manifestPath, manifestExists, tenantId)
376
395
  };
377
396
  }
378
397
  try {
379
- const { scanHarness } = await import("./harness-1rn1hqzz.js");
398
+ const { scanHarness } = await import("./harness-avynbq4f.js");
380
399
  const current = scanHarness({
381
400
  rootDir: cwd,
382
401
  scannerVersion: "doctor",
@@ -515,11 +534,11 @@ function validationEventPathCheck(ingestUrl) {
515
534
  evidence: [{ label: "path", value: `${ingestUrl.replace(/\/+$/, "")}/v1/otel/validation` }]
516
535
  };
517
536
  }
518
- function offlineCloudChecks(isOffline) {
519
- const status = isOffline ? "skipped" : "warning";
520
- const evidence = [{ label: "mode", value: isOffline ? "offline" : "missing api key" }];
521
- const remediation = isOffline ? "Rerun without --offline to check Moda Cloud." : "Configure an API key before checking cloud data flow.";
522
- const nextCommand = isOffline ? "moda doctor --online" : "moda init";
537
+ function offlineCloudChecks(isOffline, refused = false) {
538
+ const status = isOffline || refused ? "skipped" : "warning";
539
+ const evidence = [{ label: "mode", value: refused ? "base url refused" : isOffline ? "offline" : "missing api key" }];
540
+ const remediation = refused ? "Fix the refused MODA_BASE_URL (see base_url_not_refused) before checking Moda Cloud." : isOffline ? "Rerun without --offline to check Moda Cloud." : "Configure an API key before checking cloud data flow.";
541
+ const nextCommand = refused ? "moda doctor --online --profile=local" : isOffline ? "moda doctor --online" : "moda init";
523
542
  return [
524
543
  {
525
544
  id: "cloud_api_reachable",
@@ -2,7 +2,7 @@ import {
2
2
  ApiError,
3
3
  callControlAPI,
4
4
  callDataAPI
5
- } from "./cli-0xc5htv7.js";
5
+ } from "./cli-dmm9jm9m.js";
6
6
  import {
7
7
  continuationCommand,
8
8
  embeddedTenantIdFromApiKey,
@@ -11,7 +11,7 @@ import {
11
11
  resolveApiTenantId,
12
12
  setPlatformTenantOverride,
13
13
  shellArg
14
- } from "./cli-t0pb7qbs.js";
14
+ } from "./cli-e24fjyrb.js";
15
15
  import {
16
16
  CliAccessError,
17
17
  CliInputError
@@ -4,14 +4,14 @@ import {
4
4
  } from "./cli-mm48br00.js";
5
5
  import {
6
6
  createCommandContext
7
- } from "./cli-5fhqfx04.js";
7
+ } from "./cli-8pcq2et6.js";
8
8
  import {
9
9
  assertFlags,
10
10
  assertPositionals
11
- } from "./cli-9a0a3v13.js";
11
+ } from "./cli-tztzrh6b.js";
12
12
  import {
13
13
  callControlAPI
14
- } from "./cli-0xc5htv7.js";
14
+ } from "./cli-dmm9jm9m.js";
15
15
  import {
16
16
  CliInputError
17
17
  } from "./cli-k4tqwah4.js";
@@ -5725,9 +5725,9 @@ async function runPromptsCommand(input, legacyFlags, legacyProfileOptions) {
5725
5725
  await promotePrompt(positionals, flags, profileOptions, context);
5726
5726
  break;
5727
5727
  case "ab":
5728
- return (await import("./prompts-ab-ws66335h.js")).runPromptAb(flags, profileOptions, context);
5728
+ return (await import("./prompts-ab-y7egdzg4.js")).runPromptAb(flags, profileOptions, context);
5729
5729
  case "propose":
5730
- await (await import("./prompts-propose-a9m0p9nr.js")).runPromptPropose(positionals, flags, profileOptions, context);
5730
+ await (await import("./prompts-propose-5nw25v9a.js")).runPromptPropose(positionals, flags, profileOptions, context);
5731
5731
  break;
5732
5732
  case "list":
5733
5733
  case "show":
@@ -5830,7 +5830,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
5830
5830
  const analyzedDefinitions = new Map;
5831
5831
  if (flags["no-analyze"] !== "true") {
5832
5832
  options.onProgress?.("Analyzing prompt sources before sync.");
5833
- const { analyzeHarnessPrompts } = await import("./harness-1rn1hqzz.js");
5833
+ const { analyzeHarnessPrompts } = await import("./harness-avynbq4f.js");
5834
5834
  const result = await analyzeHarnessPrompts({
5835
5835
  rootDir: process.cwd(),
5836
5836
  existing: established.flatMap((prompt) => prompt.sourceDefinition ? [prompt.sourceDefinition.source] : []),
@@ -5858,7 +5858,7 @@ async function runPromptSyncExclusive(flags, profileOptions, options) {
5858
5858
  const mergedSources = mergePromptSources(manifest.sources, extraSources);
5859
5859
  const manifestUpdate = stableJson(mergedSources) === stableJson(mergePromptSources(manifest.sources, [])) ? undefined : $stringify({ version: 2, prompt_paths: manifest.promptPaths, sources: mergedSources });
5860
5860
  const prompts = await discoverPrompts(extraSources);
5861
- const { checkPromptAttribution } = await import("./prompt-attribution-hc6mcvee.js");
5861
+ const { checkPromptAttribution } = await import("./prompt-attribution-wvvnzw4m.js");
5862
5862
  const attribution = checkPromptAttribution(process.cwd(), prompts.map((prompt) => prompt.key));
5863
5863
  const brokenAttribution = attribution.references.filter((reference) => reference.status === "missing");
5864
5864
  if (brokenAttribution.length) {
@@ -6164,7 +6164,7 @@ async function migratePromptManifest(options = {}) {
6164
6164
  let addedSources = [];
6165
6165
  let pendingSources = [];
6166
6166
  if (options.discover) {
6167
- const { analyzeHarnessPrompts } = await import("./harness-1rn1hqzz.js");
6167
+ const { analyzeHarnessPrompts } = await import("./harness-avynbq4f.js");
6168
6168
  const result = await analyzeHarnessPrompts({
6169
6169
  rootDir: root,
6170
6170
  existing: manifest.sources,