@mushi-mushi/cli 0.22.1 → 0.23.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/index.js CHANGED
@@ -1,16 +1,34 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  FRAMEWORKS,
4
+ MUSHI_CLI_VERSION,
5
+ apiCall,
4
6
  apiKeyHeaders,
7
+ apiKeyHint,
5
8
  buildMcpServerBlock,
6
9
  buildMcpServerName,
10
+ cliSetupDeepLink,
11
+ consoleUrl,
7
12
  detectFramework,
8
13
  detectPackageManager,
14
+ die,
9
15
  envVarsToWrite,
10
16
  fetchIngestSetup,
17
+ fmtDate,
11
18
  installCommand,
19
+ installSignalHandlers,
12
20
  loadConfig,
21
+ openInBrowser,
22
+ pad,
23
+ printAndExit,
24
+ probeEndpointHealth,
25
+ projectIdHint,
13
26
  readPackageJson,
27
+ reportsUrl,
28
+ requireConfig,
29
+ requireUuid,
30
+ resolveConsoleUrl,
31
+ resolveConsoleUrlSync,
14
32
  runConnect,
15
33
  sanitizeApiKey,
16
34
  sanitizeCliCredentials,
@@ -18,9 +36,8 @@ import {
18
36
  sanitizeProjectId,
19
37
  saveConfig,
20
38
  writeMcpServerEntry
21
- } from "./chunk-R2HPR2FV.js";
39
+ } from "./chunk-GSQO35YD.js";
22
40
  import {
23
- CLOUD_API_ENDPOINT,
24
41
  TEST_REPORT_FETCH_TIMEOUT_MS,
25
42
  assertEndpoint,
26
43
  normalizeEndpoint,
@@ -30,369 +47,12 @@ import {
30
47
  // src/index.ts
31
48
  import { Command } from "commander";
32
49
 
33
- // src/errors.ts
34
- var EXIT_CODE_MAP = {
35
- E_AUTH_MISSING: 2,
36
- E_AUTH_INVALID: 2,
37
- E_PROJECT_MISSING: 2,
38
- E_ENDPOINT_INVALID: 2,
39
- E_INVALID_INPUT: 2,
40
- E_NOT_INTERACTIVE: 2,
41
- E_NETWORK: 3,
42
- E_TIMEOUT: 3,
43
- E_API_ERROR: 3,
44
- E_RATE_LIMITED: 3,
45
- E_FILE_NOT_FOUND: 1,
46
- E_FILE_PERMISSION: 1,
47
- E_FRESHNESS_STALE: 1,
48
- E_INTERRUPTED: 130,
49
- // 128 + SIGINT (2). POSIX convention.
50
- E_INTERNAL: 1
51
- };
52
- var MushiCliError = class extends Error {
53
- code;
54
- hint;
55
- cause;
56
- constructor(code, message, hint, cause) {
57
- super(message);
58
- this.name = "MushiCliError";
59
- this.code = code;
60
- if (hint) this.hint = hint;
61
- if (cause !== void 0) this.cause = cause;
62
- }
63
- /** Exit code POSIX-aware shell scripts should branch on. */
64
- get exitCode() {
65
- return EXIT_CODE_MAP[this.code];
66
- }
67
- /**
68
- * Format for `--json` output. Used by the JSON writer when a CLI
69
- * subcommand was invoked with `--json` and an error escapes.
70
- */
71
- toJSON() {
72
- return {
73
- error: {
74
- code: this.code,
75
- message: this.message,
76
- ...this.hint ? { hint: this.hint } : {}
77
- }
78
- };
79
- }
80
- };
81
- function printAndExit(err, asJson = false) {
82
- const cliErr = err instanceof MushiCliError ? err : new MushiCliError(
83
- "E_INTERNAL",
84
- err instanceof Error ? err.message : String(err),
85
- "this is unexpected \u2014 re-run with MUSHI_DEBUG=1 and report at https://github.com/kensaurus/mushi-mushi/issues",
86
- err
87
- );
88
- if (asJson) {
89
- process.stderr.write(JSON.stringify(cliErr.toJSON()) + "\n");
90
- } else {
91
- process.stderr.write(`error [${cliErr.code}]: ${cliErr.message}
92
- `);
93
- if (cliErr.hint) process.stderr.write(` \u2192 fix: ${cliErr.hint}
94
- `);
95
- }
96
- process.exit(cliErr.exitCode);
97
- }
98
-
99
- // src/signals.ts
100
- var installed = false;
101
- var activeController = null;
102
- function installSignalHandlers() {
103
- if (installed) return;
104
- installed = true;
105
- const abortAndExit = (signal) => {
106
- activeController?.abort(
107
- new MushiCliError(
108
- "E_INTERRUPTED",
109
- `aborted by ${signal}`,
110
- "partial state on the server is safe to retry \u2014 re-run the same command"
111
- )
112
- );
113
- const code = signal === "SIGINT" ? 130 : signal === "SIGTERM" ? 143 : 1;
114
- process.nextTick(() => {
115
- process.exit(code);
116
- });
117
- };
118
- process.on("SIGINT", () => abortAndExit("SIGINT"));
119
- process.on("SIGTERM", () => abortAndExit("SIGTERM"));
120
- }
121
- function getAbortSignal(external) {
122
- if (external) return external.signal;
123
- if (!activeController || activeController.signal.aborted) {
124
- activeController = new AbortController();
125
- }
126
- return activeController.signal;
127
- }
128
-
129
- // src/version.ts
130
- var MUSHI_CLI_VERSION = true ? "0.22.1" : "0.0.0-dev";
131
-
132
50
  // src/init.ts
133
51
  import * as p from "@clack/prompts";
134
52
  import { spawn } from "child_process";
135
53
  import { randomUUID } from "crypto";
136
- import { appendFileSync, existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync } from "fs";
137
- import { join as join3 } from "path";
138
-
139
- // src/console-url.ts
140
- import { existsSync, readFileSync } from "fs";
141
- import { dirname, join } from "path";
142
- var HOSTED_CONSOLE_BASE = "https://kensaur.us/mushi-mushi/admin";
143
- var LOCAL_ADMIN_URL = "http://localhost:6464";
144
- var LOCAL_PROBE_MS = 800;
145
- function normalizeConsoleBase(url) {
146
- const trimmed = url.trim();
147
- let end = trimmed.length;
148
- while (end > 0 && trimmed.charCodeAt(end - 1) === 47) end--;
149
- return trimmed.slice(0, end);
150
- }
151
- function consoleUrl(base, route) {
152
- const normalizedRoute = route.startsWith("/") ? route : `/${route}`;
153
- return `${normalizeConsoleBase(base)}${normalizedRoute}`;
154
- }
155
- function resolveConsoleUrlFromEnv() {
156
- const raw = process.env["MUSHI_CONSOLE_URL"]?.trim();
157
- return raw ? normalizeConsoleBase(raw) : void 0;
158
- }
159
- function isInsideMushiMonorepo(cwd) {
160
- let dir = cwd;
161
- for (let depth = 0; depth < 14; depth += 1) {
162
- const pkgPath = join(dir, "package.json");
163
- if (existsSync(pkgPath)) {
164
- try {
165
- const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
166
- if (pkg.name === "mushi-mushi") return true;
167
- } catch {
168
- }
169
- }
170
- const parent = dirname(dir);
171
- if (parent === dir) break;
172
- dir = parent;
173
- }
174
- return false;
175
- }
176
- async function probeLocalAdminConsole() {
177
- try {
178
- const controller = new AbortController();
179
- const timer = setTimeout(() => controller.abort(), LOCAL_PROBE_MS);
180
- const res = await fetch(LOCAL_ADMIN_URL, {
181
- signal: controller.signal,
182
- method: "HEAD"
183
- });
184
- clearTimeout(timer);
185
- if (res.ok || res.status === 404 || res.status === 401) {
186
- return LOCAL_ADMIN_URL;
187
- }
188
- } catch {
189
- }
190
- return null;
191
- }
192
- function resolveConsoleUrlSync(cwd = process.cwd()) {
193
- const fromEnv = resolveConsoleUrlFromEnv();
194
- if (fromEnv) return fromEnv;
195
- const config = loadConfig();
196
- if (config.consoleUrl) return normalizeConsoleBase(config.consoleUrl);
197
- if (isInsideMushiMonorepo(cwd)) return LOCAL_ADMIN_URL;
198
- return HOSTED_CONSOLE_BASE;
199
- }
200
- async function resolveConsoleUrl(options) {
201
- const fromEnv = resolveConsoleUrlFromEnv();
202
- if (fromEnv) return fromEnv;
203
- const config = loadConfig();
204
- if (config.consoleUrl) return normalizeConsoleBase(config.consoleUrl);
205
- const local = await probeLocalAdminConsole();
206
- if (local) return local;
207
- const cwd = options?.cwd ?? process.cwd();
208
- if (isInsideMushiMonorepo(cwd)) return LOCAL_ADMIN_URL;
209
- return HOSTED_CONSOLE_BASE;
210
- }
211
- function projectIdHint(base) {
212
- return `Where to find it: ${consoleUrl(base, "/projects")} \u2192 select your project \u2192 click the UUID chip to copy (or copy it from the panel right after you create the project).`;
213
- }
214
- function apiKeyHint(base) {
215
- return `Where to find it: ${consoleUrl(base, "/onboarding?tab=verify")} \u2192 Generate API key (SDK ingest needs report:write \u2014 not Settings \u2192 BYOK keys). Treat it like a password \u2014 env file only, never commit.`;
216
- }
217
- function cliSetupDeepLink(base) {
218
- return consoleUrl(base, "/onboarding?tab=steps&setup=cli");
219
- }
220
- function reportsUrl(base, reportId) {
221
- return reportId ? consoleUrl(base, `/reports/${reportId}`) : consoleUrl(base, "/reports");
222
- }
223
- async function openInBrowser(url) {
224
- let parsed;
225
- try {
226
- parsed = new URL(url);
227
- } catch {
228
- return;
229
- }
230
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
231
- return;
232
- }
233
- const safeUrl = parsed.toString();
234
- const { spawn: spawn2 } = await import("child_process");
235
- const [command, args] = process.platform === "win32" ? (
236
- // Open via rundll32's FileProtocolHandler rather than `cmd /c start`.
237
- // `start` is a cmd builtin, so the URL would be re-parsed by cmd.exe and
238
- // characters like `&` / `|` / `^` could still break out — exactly the
239
- // injection surface CodeQL flags. rundll32 never invokes a shell: the URL
240
- // is handed to the default browser as one opaque argument.
241
- ["rundll32", ["url.dll,FileProtocolHandler", safeUrl]]
242
- ) : process.platform === "darwin" ? ["open", [safeUrl]] : ["xdg-open", [safeUrl]];
243
- await new Promise((resolve3) => {
244
- try {
245
- const child = spawn2(command, [...args], { stdio: "ignore", shell: false });
246
- child.on("error", () => resolve3());
247
- child.on("exit", () => resolve3());
248
- child.unref();
249
- } catch {
250
- resolve3();
251
- }
252
- });
253
- }
254
-
255
- // src/cli-shared.ts
256
- var API_TIMEOUT_MS = 15e3;
257
- async function probeEndpointHealth(endpoint) {
258
- const t0 = Date.now();
259
- const controller = new AbortController();
260
- const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
261
- try {
262
- const res = await fetch(`${endpoint}/health`, { signal: controller.signal });
263
- clearTimeout(timer);
264
- const body = res.headers.get("content-type")?.includes("json") ? await res.json().catch(() => ({})) : {};
265
- return { ok: res.ok, status: res.status, latencyMs: Date.now() - t0, body };
266
- } catch (err) {
267
- clearTimeout(timer);
268
- throw err;
269
- }
270
- }
271
- async function apiCall(path, config, options = {}) {
272
- const endpoint = config.endpoint;
273
- if (!endpoint) {
274
- return {
275
- ok: false,
276
- error: {
277
- code: "NO_ENDPOINT",
278
- message: "No API endpoint configured.\n Run: mushi login --api-key <key> --endpoint <url> --project-id <id>\n Or: export MUSHI_API_ENDPOINT=https://<project-ref>.supabase.co/functions/v1/api"
279
- }
280
- };
281
- }
282
- const controller = new AbortController();
283
- const timer = setTimeout(() => controller.abort(), API_TIMEOUT_MS);
284
- const signals = [controller.signal, getAbortSignal()];
285
- const compositeSignal = AbortSignal.any ? AbortSignal.any(signals) : controller.signal;
286
- try {
287
- const res = await fetch(`${endpoint}${path}`, {
288
- ...options,
289
- signal: compositeSignal,
290
- headers: {
291
- "Content-Type": "application/json",
292
- // `apiKeyAuth` reads X-Mushi-Api-Key; the Authorization header is a
293
- // fallback accepted by some older middleware. Both are sent.
294
- "Authorization": `Bearer ${config.apiKey ?? ""}`,
295
- "X-Mushi-Api-Key": config.apiKey ?? "",
296
- "X-Mushi-Project": config.projectId ?? "",
297
- "X-Mushi-Cli-Version": MUSHI_CLI_VERSION,
298
- ...options.headers
299
- }
300
- });
301
- clearTimeout(timer);
302
- let body;
303
- const contentType = res.headers.get("content-type") ?? "";
304
- if (contentType.includes("application/json")) {
305
- try {
306
- body = await res.json();
307
- } catch {
308
- body = null;
309
- }
310
- } else {
311
- const text2 = await res.text();
312
- try {
313
- body = JSON.parse(text2);
314
- } catch {
315
- body = {
316
- ok: false,
317
- error: {
318
- code: `HTTP_${res.status}`,
319
- message: text2.trim().slice(0, 300) || `HTTP ${res.status}`
320
- }
321
- };
322
- }
323
- }
324
- if (!res.ok && typeof body === "object" && body !== null && !("ok" in body)) {
325
- const b = body;
326
- const nested = b["error"];
327
- const errCode = nested?.["code"] ?? b["code"] ?? `HTTP_${res.status}`;
328
- const errMsg = nested?.["message"] ?? b["message"] ?? `Request failed (${res.status})`;
329
- return {
330
- ok: false,
331
- httpStatus: res.status,
332
- error: { code: errCode, message: errMsg }
333
- };
334
- }
335
- return body;
336
- } catch (err) {
337
- clearTimeout(timer);
338
- if (err instanceof Error && err.name === "AbortError") {
339
- return {
340
- ok: false,
341
- error: {
342
- code: "TIMEOUT",
343
- message: `Request timed out after ${API_TIMEOUT_MS / 1e3}s. Check your network or endpoint.`
344
- }
345
- };
346
- }
347
- return {
348
- ok: false,
349
- error: {
350
- code: "NETWORK_ERROR",
351
- message: err instanceof Error ? err.message : String(err)
352
- }
353
- };
354
- }
355
- }
356
- function die(result, exitCode = 1) {
357
- const { code, message } = result.error;
358
- const status = result.httpStatus ? ` [${result.httpStatus}]` : "";
359
- process.stderr.write(`error${status}: ${code} \u2014 ${message}
360
- `);
361
- if (code === "INSUFFICIENT_SCOPE") {
362
- process.stderr.write(
363
- "\n Your current API key does not have the required scope for this command.\n New keys minted by the wizard already include both scopes. Existing keys\n can be upgraded with:\n\n mushi login --upgrade-scope\n\n Or visit your console \u2192 Projects \u2192 API Keys to mint a new key.\n"
364
- );
365
- }
366
- process.exit(exitCode);
367
- }
368
- function requireConfig(opts = {}) {
369
- const config = loadConfig();
370
- if (!config.apiKey) {
371
- printAndExit(new MushiCliError(
372
- "E_AUTH_MISSING",
373
- "API key not configured.",
374
- "Run: mushi login --api-key <key> Or: export MUSHI_API_KEY=<key>"
375
- ));
376
- }
377
- if (!config.endpoint) {
378
- config.endpoint = process.env.MUSHI_API_ENDPOINT?.trim() || CLOUD_API_ENDPOINT;
379
- }
380
- if (opts.needsProject && !config.projectId) {
381
- printAndExit(new MushiCliError(
382
- "E_PROJECT_MISSING",
383
- "Project ID not configured.",
384
- `Run: mushi login --project-id <uuid> Or find your project ID at ${consoleUrl(resolveConsoleUrlSync(), "/projects")}`
385
- ));
386
- }
387
- return config;
388
- }
389
- function fmtDate(iso) {
390
- if (!iso) return "\u2014";
391
- return new Date(iso).toLocaleString(void 0, { dateStyle: "short", timeStyle: "short" });
392
- }
393
- function pad(s, width) {
394
- return s.length >= width ? s : s + " ".repeat(width - s.length);
395
- }
54
+ import { appendFileSync, existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
55
+ import { join as join2 } from "path";
396
56
 
397
57
  // src/device-auth.ts
398
58
  var DEVICE_FETCH_TIMEOUT_MS = 15e3;
@@ -506,7 +166,11 @@ async function listProjects(endpoint, cliToken) {
506
166
  const res = await deviceFetch(`${base}/v1/cli/projects`, { headers: cliAuthHeaders(cliToken) });
507
167
  const json = await res.json().catch(() => null);
508
168
  if (res.ok && json?.ok) return json.data?.projects ?? [];
509
- } catch {
169
+ } catch (err) {
170
+ console.error(
171
+ "[mushi] Failed to list projects:",
172
+ err instanceof Error ? err.message : err
173
+ );
510
174
  }
511
175
  return [];
512
176
  }
@@ -599,8 +263,8 @@ function parse(version) {
599
263
  }
600
264
 
601
265
  // src/monorepo.ts
602
- import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync } from "fs";
603
- import { dirname as dirname2, join as join2, resolve } from "path";
266
+ import { existsSync, readFileSync, readdirSync, statSync } from "fs";
267
+ import { dirname, join, resolve } from "path";
604
268
  var WORKSPACE_GLOB_CANDIDATES = ["apps/*", "packages/*", "examples/*"];
605
269
  var FRAMEWORK_DEPS = {
606
270
  next: "Next.js",
@@ -617,9 +281,9 @@ var FRAMEWORK_DEPS = {
617
281
  function detectWorkspaceHint(cwd) {
618
282
  const root = findWorkspaceRoot(cwd);
619
283
  if (!root) return null;
620
- const rootPkg = readPackageJsonSafely(join2(root, "package.json"));
284
+ const rootPkg = readPackageJsonSafely(join(root, "package.json"));
621
285
  if (rootPkg && getFrameworkFromPkg(rootPkg)) return null;
622
- const source = existsSync2(join2(root, "pnpm-workspace.yaml")) ? "pnpm-workspace" : root === cwd ? "package-json" : "parent";
286
+ const source = existsSync(join(root, "pnpm-workspace.yaml")) ? "pnpm-workspace" : root === cwd ? "package-json" : "parent";
623
287
  const apps = collectAppsFromGlobs(root);
624
288
  if (apps.length === 0) return null;
625
289
  return { root, apps, source };
@@ -628,15 +292,15 @@ function findWorkspaceRoot(start) {
628
292
  let dir = resolve(start);
629
293
  for (let i = 0; i < 8; i++) {
630
294
  if (isWorkspaceRoot(dir)) return dir;
631
- const parent = dirname2(dir);
295
+ const parent = dirname(dir);
632
296
  if (parent === dir) break;
633
297
  dir = parent;
634
298
  }
635
299
  return null;
636
300
  }
637
301
  function isWorkspaceRoot(dir) {
638
- if (existsSync2(join2(dir, "pnpm-workspace.yaml"))) return true;
639
- const pkg = readPackageJsonSafely(join2(dir, "package.json"));
302
+ if (existsSync(join(dir, "pnpm-workspace.yaml"))) return true;
303
+ const pkg = readPackageJsonSafely(join(dir, "package.json"));
640
304
  if (!pkg) return false;
641
305
  return Boolean(pkg.workspaces);
642
306
  }
@@ -644,8 +308,8 @@ function collectAppsFromGlobs(root) {
644
308
  const results = [];
645
309
  for (const glob of WORKSPACE_GLOB_CANDIDATES) {
646
310
  const prefix = glob.replace("/*", "");
647
- const parentDir = join2(root, prefix);
648
- if (!existsSync2(parentDir)) continue;
311
+ const parentDir = join(root, prefix);
312
+ if (!existsSync(parentDir)) continue;
649
313
  let entries;
650
314
  try {
651
315
  entries = readdirSync(parentDir);
@@ -653,7 +317,7 @@ function collectAppsFromGlobs(root) {
653
317
  continue;
654
318
  }
655
319
  for (const entry of entries) {
656
- const pkgPath = join2(parentDir, entry, "package.json");
320
+ const pkgPath = join(parentDir, entry, "package.json");
657
321
  if (!isFileSafe(pkgPath)) continue;
658
322
  const pkg = readPackageJsonSafely(pkgPath);
659
323
  if (!pkg) continue;
@@ -671,14 +335,14 @@ function collectAppsFromGlobs(root) {
671
335
  function readPackageJsonSafely(path) {
672
336
  if (!isFileSafe(path)) return null;
673
337
  try {
674
- return JSON.parse(readFileSync2(path, "utf-8"));
338
+ return JSON.parse(readFileSync(path, "utf-8"));
675
339
  } catch {
676
340
  return null;
677
341
  }
678
342
  }
679
343
  function isFileSafe(path) {
680
344
  try {
681
- return existsSync2(path) && statSync(path).isFile();
345
+ return existsSync(path) && statSync(path).isFile();
682
346
  } catch {
683
347
  return false;
684
348
  }
@@ -1085,10 +749,10 @@ function runCommand(pm, packages, cwd) {
1085
749
  });
1086
750
  }
1087
751
  async function writeEnvFile(cwd, apiKey, projectId, framework, endpoint, overwrite) {
1088
- const target = ENV_FILES.find((f) => existsSync3(join3(cwd, f))) ?? ENV_FILES[0];
1089
- const targetPath = join3(cwd, target);
752
+ const target = ENV_FILES.find((f) => existsSync2(join2(cwd, f))) ?? ENV_FILES[0];
753
+ const targetPath = join2(cwd, target);
1090
754
  const newVars = envVarsToWrite(apiKey, projectId, framework, endpoint);
1091
- const existing = existsSync3(targetPath) ? readFileSync3(targetPath, "utf-8") : "";
755
+ const existing = existsSync2(targetPath) ? readFileSync2(targetPath, "utf-8") : "";
1092
756
  if (existing.includes("MUSHI_PROJECT_ID")) {
1093
757
  let shouldOverwrite = overwrite;
1094
758
  if (!shouldOverwrite) {
@@ -1147,12 +811,12 @@ function escapeRegexChar(ch) {
1147
811
  return /[-/\\^$+?.()|[\]{}]/.test(ch) ? `\\${ch}` : ch;
1148
812
  }
1149
813
  function warnIfMissingFromGitignore(cwd, envFile) {
1150
- const gitignorePath = join3(cwd, ".gitignore");
1151
- if (!existsSync3(gitignorePath)) {
814
+ const gitignorePath = join2(cwd, ".gitignore");
815
+ if (!existsSync2(gitignorePath)) {
1152
816
  p.log.warn(`No .gitignore found \u2014 make sure ${envFile} is not committed.`);
1153
817
  return;
1154
818
  }
1155
- const content = readFileSync3(gitignorePath, "utf-8");
819
+ const content = readFileSync2(gitignorePath, "utf-8");
1156
820
  if (!isEnvFileCoveredByGitignore(content, envFile)) {
1157
821
  p.log.warn(`${envFile} is not in .gitignore \u2014 add it before committing.`);
1158
822
  }
@@ -1194,7 +858,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
1194
858
  if (p.isCancel(answer) || !answer) return;
1195
859
  const endpoint = resolveCloudEndpoint(options.endpoint);
1196
860
  try {
1197
- const { runConnect: runConnect2 } = await import("./connect-JIEIWTF3.js");
861
+ const { runConnect: runConnect2 } = await import("./connect-XFVSH4JZ.js");
1198
862
  await runConnect2({
1199
863
  apiKey: credentials.apiKey,
1200
864
  projectId: credentials.projectId,
@@ -1326,7 +990,7 @@ function isSameDirectory(a, b) {
1326
990
  }
1327
991
 
1328
992
  // src/migrate.ts
1329
- var DOCS_BASE = "https://docs.mushimushi.dev";
993
+ var DOCS_BASE = "https://kensaur.us/mushi-mushi/docs";
1330
994
  var COMPETITOR_PACKAGES = {
1331
995
  "instabug-to-mushi": [
1332
996
  "instabug-reactnative",
@@ -1488,8 +1152,8 @@ Examples:
1488
1152
  mushi login --api-key mushi_xxx # non-interactive / CI
1489
1153
  mushi login --api-key mushi_xxx --project-id <uuid>
1490
1154
  mushi login --upgrade-scope # re-auth to add mcp:read + mcp:write to your key`).action(async (opts) => {
1491
- const { CLOUD_API_ENDPOINT: CLOUD_API_ENDPOINT2, resolveCloudEndpoint: resolveCloudEndpoint2 } = await import("./endpoint-DGS73AVM.js");
1492
- const endpoint = opts.endpoint ? resolveCloudEndpoint2(opts.endpoint) : CLOUD_API_ENDPOINT2;
1155
+ const { CLOUD_API_ENDPOINT, resolveCloudEndpoint: resolveCloudEndpoint2 } = await import("./endpoint-DGS73AVM.js");
1156
+ const endpoint = opts.endpoint ? resolveCloudEndpoint2(opts.endpoint) : CLOUD_API_ENDPOINT;
1493
1157
  const consoleBase = await resolveConsoleUrl();
1494
1158
  let apiKey = opts.apiKey;
1495
1159
  let projectId = opts.projectId;
@@ -2221,14 +1885,14 @@ Typical CI usage:
2221
1885
  import { createReadStream } from "fs";
2222
1886
  import { readFile, readdir } from "fs/promises";
2223
1887
  import { createHash } from "crypto";
2224
- import { join as join4, relative, basename } from "path";
1888
+ import { join as join3, relative, basename } from "path";
2225
1889
  import * as p2 from "@clack/prompts";
2226
1890
  async function findMapFiles(dir) {
2227
1891
  const results = [];
2228
1892
  async function walk(current) {
2229
1893
  const entries = await readdir(current, { withFileTypes: true });
2230
1894
  for (const e of entries) {
2231
- const full = join4(current, e.name);
1895
+ const full = join3(current, e.name);
2232
1896
  if (e.isDirectory()) {
2233
1897
  await walk(full);
2234
1898
  } else if (e.isFile() && (e.name.endsWith(".js.map") || e.name.endsWith(".css.map"))) {
@@ -2661,7 +2325,7 @@ Supported IDEs:
2661
2325
 
2662
2326
  The command reads credentials from ~/.config/mushi/config.json (run \`mushi login\` first).`).action(async (opts) => {
2663
2327
  const { writeFile: writeFile2, mkdir, readFile: readFile3 } = await import("fs/promises");
2664
- const { existsSync: existsSync4 } = await import("fs");
2328
+ const { existsSync: existsSync3 } = await import("fs");
2665
2329
  const nodePath2 = await import("path");
2666
2330
  const os = await import("os");
2667
2331
  const config = requireConfig({ needsProject: true });
@@ -2773,7 +2437,7 @@ The command reads credentials from ~/.config/mushi/config.json (run \`mushi logi
2773
2437
  }
2774
2438
  } else if (ideEntry.format === "zed") {
2775
2439
  let settings = {};
2776
- if (existsSync4(configPath)) {
2440
+ if (existsSync3(configPath)) {
2777
2441
  try {
2778
2442
  const raw = await readFile3(configPath, "utf8");
2779
2443
  settings = JSON.parse(raw);
@@ -2895,7 +2559,11 @@ The command reads credentials from ~/.config/mushi/config.json (run \`mushi logi
2895
2559
  console.log(`\u26A0 Key probe returned HTTP ${probeRes.status} \u2014 check your credentials.`);
2896
2560
  }
2897
2561
  }
2898
- } catch {
2562
+ } catch (probeErr) {
2563
+ console.warn(
2564
+ "[mushi setup] API key probe failed \u2014 verify credentials manually.",
2565
+ probeErr instanceof Error ? probeErr.message : probeErr
2566
+ );
2899
2567
  }
2900
2568
  }
2901
2569
  console.log("");
@@ -2934,6 +2602,7 @@ Examples:
2934
2602
 
2935
2603
  # CI: fail the pipeline if the fix errors
2936
2604
  mushi fix $REPORT_ID --agent cursor_cloud --wait && echo "Fix PR opened"`).action(async (reportId, opts) => {
2605
+ requireUuid(reportId, "reportId");
2937
2606
  const cfg = loadConfig();
2938
2607
  if (opts.endpoint) cfg.endpoint = opts.endpoint;
2939
2608
  if (opts.apiKey) cfg.apiKey = opts.apiKey;
@@ -3308,9 +2977,9 @@ async function planUpgrade(cwd) {
3308
2977
  ...pkg?.dependencies ?? {},
3309
2978
  ...pkg?.devDependencies ?? {}
3310
2979
  };
3311
- const installed2 = MUSHI_PACKAGES.filter((name) => deps[name]);
2980
+ const installed = MUSHI_PACKAGES.filter((name) => deps[name]);
3312
2981
  const entries = await Promise.all(
3313
- installed2.map(async (name) => {
2982
+ installed.map(async (name) => {
3314
2983
  const current = deps[name] ?? "";
3315
2984
  const currentCore = current.replace(/^[\^~>=<]*/, "");
3316
2985
  if (!/^\d/.test(currentCore)) {
@@ -3475,9 +3144,9 @@ async function checkEndpointReachability(endpoint, doFetch = globalThis.fetch) {
3475
3144
  async function checkSdkInstall(cwd) {
3476
3145
  try {
3477
3146
  const { readFile: readFile3 } = await import("fs/promises");
3478
- const { join: join5, resolve: resolve3 } = await import("path");
3147
+ const { join: join4, resolve: resolve3 } = await import("path");
3479
3148
  const root = resolve3(cwd);
3480
- const pkgPath = join5(root, "package.json");
3149
+ const pkgPath = join4(root, "package.json");
3481
3150
  const pkg = JSON.parse(await readFile3(pkgPath, "utf8"));
3482
3151
  const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
3483
3152
  const sdks = [
@@ -3486,11 +3155,11 @@ async function checkSdkInstall(cwd) {
3486
3155
  "@mushi-mushi/core",
3487
3156
  "@mushi-mushi/react-native"
3488
3157
  ];
3489
- const installed2 = sdks.filter((s) => deps[s]);
3158
+ const installed = sdks.filter((s) => deps[s]);
3490
3159
  return {
3491
3160
  name: "SDK installed in this repo",
3492
- ok: installed2.length > 0,
3493
- detail: installed2.length > 0 ? installed2.map((s) => `${s}@${deps[s]}`).join(", ") : "No @mushi-mushi/* package in package.json \u2014 run `mushi init` to install"
3161
+ ok: installed.length > 0,
3162
+ detail: installed.length > 0 ? installed.map((s) => `${s}@${deps[s]}`).join(", ") : "No @mushi-mushi/* package in package.json \u2014 run `mushi init` to install"
3494
3163
  };
3495
3164
  } catch {
3496
3165
  return null;
@@ -3674,9 +3343,9 @@ async function checkHostAppWiring(cwd) {
3674
3343
  const checks = [];
3675
3344
  try {
3676
3345
  const { readFile: readFile3, access } = await import("fs/promises");
3677
- const { join: join5, resolve: resolve3 } = await import("path");
3346
+ const { join: join4, resolve: resolve3 } = await import("path");
3678
3347
  const root = resolve3(cwd);
3679
- const pkgPath = join5(root, "package.json");
3348
+ const pkgPath = join4(root, "package.json");
3680
3349
  const pkg = JSON.parse(await readFile3(pkgPath, "utf8"));
3681
3350
  const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
3682
3351
  const isCapHybrid = Boolean(deps["@capacitor/core"] && deps["react"]);
@@ -3684,7 +3353,7 @@ async function checkHostAppWiring(cwd) {
3684
3353
  let envContent = "";
3685
3354
  for (const f of envCandidates) {
3686
3355
  try {
3687
- envContent = await readFile3(join5(root, f), "utf8");
3356
+ envContent = await readFile3(join4(root, f), "utf8");
3688
3357
  break;
3689
3358
  } catch {
3690
3359
  }
@@ -3698,7 +3367,7 @@ async function checkHostAppWiring(cwd) {
3698
3367
  });
3699
3368
  let mcpPresent = false;
3700
3369
  try {
3701
- await access(join5(root, ".cursor", "mcp.json"));
3370
+ await access(join4(root, ".cursor", "mcp.json"));
3702
3371
  mcpPresent = true;
3703
3372
  } catch {
3704
3373
  }
@@ -3732,12 +3401,12 @@ async function checkHostAppWiring(cwd) {
3732
3401
  async function checkMcpConfig(config, cwd, doFetch = globalThis.fetch) {
3733
3402
  const checks = [];
3734
3403
  const { readFile: readFile3 } = await import("fs/promises");
3735
- const { join: join5, resolve: resolve3 } = await import("path");
3404
+ const { join: join4, resolve: resolve3 } = await import("path");
3736
3405
  const { homedir } = await import("os");
3737
3406
  const root = resolve3(cwd);
3738
3407
  const candidates = [
3739
- join5(root, ".cursor", "mcp.json"),
3740
- join5(homedir(), ".cursor", "mcp.json")
3408
+ join4(root, ".cursor", "mcp.json"),
3409
+ join4(homedir(), ".cursor", "mcp.json")
3741
3410
  ];
3742
3411
  let mcpPath = null;
3743
3412
  let mcpRaw = null;
@@ -3890,12 +3559,12 @@ async function checkOnboardingStatus(config, _consoleBase, cwd, doFetch = global
3890
3559
  }
3891
3560
  try {
3892
3561
  const { readFile: readFile3 } = await import("fs/promises");
3893
- const { join: join5, resolve: resolve3 } = await import("path");
3562
+ const { join: join4, resolve: resolve3 } = await import("path");
3894
3563
  const root = resolve3(cwd);
3895
3564
  let envContent = "";
3896
3565
  for (const f of [".env.local", ".env"]) {
3897
3566
  try {
3898
- envContent = await readFile3(join5(root, f), "utf8");
3567
+ envContent = await readFile3(join4(root, f), "utf8");
3899
3568
  break;
3900
3569
  } catch {
3901
3570
  }
@@ -5159,6 +4828,5 @@ registerAuditCommands(program);
5159
4828
  registerSkillsCommands(program);
5160
4829
  registerBillingCommands(program);
5161
4830
  program.parseAsync().catch((err) => {
5162
- console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
5163
- process.exit(1);
4831
+ printAndExit(err);
5164
4832
  });