@mushi-mushi/cli 0.24.0 → 0.25.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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MUSHI_CLI_VERSION
3
- } from "./chunk-X74T7JKC.js";
3
+ } from "./chunk-SS42XQ57.js";
4
4
 
5
5
  // src/config.ts
6
6
  import { randomUUID } from "crypto";
@@ -116,7 +116,7 @@ function tightenDirPermissions(path) {
116
116
  }
117
117
 
118
118
  // src/version.ts
119
- var MUSHI_CLI_VERSION = true ? "0.24.0" : "0.0.0-dev";
119
+ var MUSHI_CLI_VERSION = true ? "0.25.0" : "0.0.0-dev";
120
120
 
121
121
  // src/errors.ts
122
122
  var EXIT_CODE_MAP = {
@@ -0,0 +1,6 @@
1
+ // src/version.ts
2
+ var MUSHI_CLI_VERSION = true ? "0.25.0" : "0.0.0-dev";
3
+
4
+ export {
5
+ MUSHI_CLI_VERSION
6
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runConnect
4
- } from "./chunk-BWASDQI6.js";
4
+ } from "./chunk-3JRQN6S4.js";
5
5
  import "./chunk-LDPFTQLE.js";
6
6
  export {
7
7
  runConnect
@@ -4,13 +4,13 @@ import {
4
4
  normalizeEndpoint,
5
5
  requireUuid,
6
6
  saveConfig
7
- } from "./chunk-GUVGTFVK.js";
7
+ } from "./chunk-2WHQONHK.js";
8
8
  import {
9
9
  detectFramework,
10
10
  envVarsToWrite,
11
11
  readPackageJson
12
12
  } from "./chunk-AIZRI665.js";
13
- import "./chunk-X74T7JKC.js";
13
+ import "./chunk-SS42XQ57.js";
14
14
 
15
15
  // src/connect.ts
16
16
  import { appendFile, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ import {
37
37
  sanitizeProjectId,
38
38
  saveConfig,
39
39
  writeMcpServerEntry
40
- } from "./chunk-BWASDQI6.js";
40
+ } from "./chunk-3JRQN6S4.js";
41
41
  import {
42
42
  TEST_REPORT_FETCH_TIMEOUT_MS,
43
43
  assertEndpoint,
@@ -245,28 +245,26 @@ async function createProject(endpoint, cliToken, name) {
245
245
  }
246
246
  async function mintProjectKey(endpoint, cliToken, projectId) {
247
247
  const base = trimTrailingSlash(endpoint);
248
- return withOneRetry(async () => {
249
- let res;
250
- try {
251
- res = await deviceFetch(`${base}/v1/cli/projects/${projectId}/keys`, {
252
- method: "POST",
253
- headers: cliAuthHeaders(cliToken),
254
- body: JSON.stringify({})
255
- });
256
- } catch (err) {
257
- throw new DeviceAuthRequestError(
258
- "mint_key",
259
- `Could not reach ${base}/v1/cli/projects/\u2026/keys: ${err instanceof Error ? err.message : String(err)}`
260
- );
261
- }
262
- const json = await res.json().catch(() => null);
263
- if (res.ok && json?.ok && json.data?.key) return json.data.key;
248
+ let res;
249
+ try {
250
+ res = await deviceFetch(`${base}/v1/cli/projects/${projectId}/keys`, {
251
+ method: "POST",
252
+ headers: cliAuthHeaders(cliToken),
253
+ body: JSON.stringify({})
254
+ });
255
+ } catch (err) {
264
256
  throw new DeviceAuthRequestError(
265
257
  "mint_key",
266
- json?.error?.message ?? `Could not mint an SDK key (HTTP ${res.status}).`,
267
- res.ok ? void 0 : res.status
258
+ `Could not reach ${base}/v1/cli/projects/\u2026/keys: ${err instanceof Error ? err.message : String(err)}`
268
259
  );
269
- });
260
+ }
261
+ const json = await res.json().catch(() => null);
262
+ if (res.ok && json?.ok && json.data?.key) return json.data.key;
263
+ throw new DeviceAuthRequestError(
264
+ "mint_key",
265
+ json?.error?.message ?? `Could not mint an SDK key (HTTP ${res.status}).`,
266
+ res.status
267
+ );
270
268
  }
271
269
 
272
270
  // src/freshness.ts
@@ -984,7 +982,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
984
982
  if (p.isCancel(answer) || !answer) return;
985
983
  const endpoint = resolveCloudEndpoint(options.endpoint);
986
984
  try {
987
- const { runConnect: runConnect2 } = await import("./connect-KKN62YK2.js");
985
+ const { runConnect: runConnect2 } = await import("./connect-22IHGT2L.js");
988
986
  await runConnect2({
989
987
  apiKey: credentials.apiKey,
990
988
  projectId: credentials.projectId,
@@ -1273,189 +1271,7 @@ Examples:
1273
1271
  mushi login # browser-guided (recommended)
1274
1272
  mushi login --api-key mushi_xxx # non-interactive / CI
1275
1273
  mushi login --api-key mushi_xxx --project-id <uuid>
1276
- mushi login --upgrade-scope # re-auth to add mcp:read + mcp:write to your key`).action(async (opts) => {
1277
- const { CLOUD_API_ENDPOINT, resolveCloudEndpoint: resolveCloudEndpoint2 } = await import("./endpoint-DGS73AVM.js");
1278
- const endpoint = opts.endpoint ? resolveCloudEndpoint2(opts.endpoint) : CLOUD_API_ENDPOINT;
1279
- const consoleBase = await resolveConsoleUrl();
1280
- let apiKey = opts.apiKey;
1281
- let projectId = opts.projectId;
1282
- if (apiKey) {
1283
- const config2 = loadConfig();
1284
- config2.apiKey = apiKey;
1285
- config2.endpoint = endpoint;
1286
- if (projectId) config2.projectId = projectId;
1287
- config2.consoleUrl = consoleBase;
1288
- saveConfig(config2);
1289
- console.log("");
1290
- console.log(" \u2713 Credentials saved.");
1291
- const verifyResult = await apiCall(
1292
- "/v1/sync/whoami",
1293
- { apiKey, endpoint, projectId }
1294
- );
1295
- if (!verifyResult.ok) {
1296
- console.warn(` \u26A0 Key saved, but verification failed: ${verifyResult.error?.message ?? "unknown error"}`);
1297
- console.warn(` Check your key at: ${cliSetupDeepLink(consoleBase)}`);
1298
- return;
1299
- }
1300
- const d = verifyResult.data;
1301
- if (d.project_name) {
1302
- if (!projectId && d.project_id) {
1303
- config2.projectId = d.project_id;
1304
- saveConfig(config2);
1305
- }
1306
- console.log(` \u2713 Project: ${d.project_name} (${d.project_id})`);
1307
- }
1308
- console.log(` \u2713 Endpoint: ${endpoint}`);
1309
- console.log("");
1310
- console.log(" Run 'mushi whoami' to verify \xB7 'mushi init' to set up the SDK");
1311
- return;
1312
- }
1313
- console.log("");
1314
- if (opts.upgradeScope) {
1315
- console.log(" Mushi login \u2014 scope upgrade");
1316
- console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1317
- console.log(" Re-authenticating to mint a new key with report:write + mcp:read + mcp:write scopes.");
1318
- console.log(" This lets the CLI admin commands (including writes) and MCP server both work with a single key.");
1319
- console.log("");
1320
- } else {
1321
- console.log(" Mushi login");
1322
- console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1323
- }
1324
- let deviceData;
1325
- try {
1326
- deviceData = await startDeviceAuth(endpoint, ensureClientId());
1327
- } catch (err) {
1328
- process.stderr.write(`
1329
- error: Could not start login session: ${err instanceof Error ? err.message : String(err)}
1330
- `);
1331
- process.stderr.write(` Fallback: mushi login --api-key <key> --project-id <uuid>
1332
- `);
1333
- process.exit(1);
1334
- }
1335
- const verifyUrl = deviceData.verification_uri;
1336
- if (opts.browser !== false) {
1337
- try {
1338
- await openInBrowser(verifyUrl);
1339
- } catch {
1340
- }
1341
- }
1342
- printAuthBanner(deviceData.user_code, verifyUrl);
1343
- let cliToken = null;
1344
- const pollIntervalMs = (deviceData.interval ?? 5) * 1e3;
1345
- const deadline = Date.now() + (deviceData.expires_in ?? 600) * 1e3;
1346
- const MAX_CONSECUTIVE_ERRORS = 5;
1347
- let consecutiveErrors = 0;
1348
- let firstPoll = true;
1349
- while (Date.now() < deadline) {
1350
- if (!firstPoll) {
1351
- await new Promise((r) => setTimeout(r, pollIntervalMs));
1352
- }
1353
- firstPoll = false;
1354
- const outcome = await pollDeviceToken(endpoint, deviceData.device_code);
1355
- if (outcome.status === "approved") {
1356
- cliToken = outcome.cliToken;
1357
- break;
1358
- }
1359
- if (outcome.status === "pending") {
1360
- consecutiveErrors = 0;
1361
- continue;
1362
- }
1363
- if (outcome.status === "error") {
1364
- if (outcome.retryable) {
1365
- consecutiveErrors += 1;
1366
- if (consecutiveErrors < MAX_CONSECUTIVE_ERRORS) continue;
1367
- }
1368
- printAuthFailed("error", outcome.message);
1369
- process.exit(1);
1370
- }
1371
- if (outcome.status === "denied") {
1372
- printAuthFailed("denied");
1373
- process.exit(1);
1374
- }
1375
- if (outcome.status === "expired") {
1376
- printAuthFailed("timeout");
1377
- process.exit(1);
1378
- }
1379
- }
1380
- if (!cliToken) {
1381
- printAuthFailed("timeout");
1382
- process.exit(1);
1383
- }
1384
- printAuthApproved();
1385
- const projectsList = await listProjects(endpoint, cliToken);
1386
- let chosenProjectId = projectId;
1387
- let chosenProjectName;
1388
- if (!chosenProjectId) {
1389
- const { createInterface } = await import("readline");
1390
- const rl = createInterface({ input: process.stdin, output: process.stdout });
1391
- const ask = (q) => new Promise((resolve3) => rl.question(q, (a) => resolve3(a.trim())));
1392
- if (projectsList.length > 0) {
1393
- console.log("");
1394
- console.log(" Your projects:");
1395
- projectsList.forEach((p3, i) => {
1396
- console.log(` ${i + 1}. ${p3.name} (${p3.id})`);
1397
- });
1398
- console.log(` ${projectsList.length + 1}. Create a new project`);
1399
- console.log("");
1400
- const choice = await ask(` Pick a project [1-${projectsList.length + 1}]: `);
1401
- const num = parseInt(choice, 10);
1402
- if (num >= 1 && num <= projectsList.length) {
1403
- const picked = projectsList[num - 1];
1404
- chosenProjectId = picked.id;
1405
- chosenProjectName = picked.name;
1406
- }
1407
- }
1408
- if (!chosenProjectId) {
1409
- console.log("");
1410
- const newName = await ask(" Project name: ");
1411
- rl.close();
1412
- if (!newName.trim()) {
1413
- process.stderr.write("\nerror: Project name is required.\n");
1414
- process.exit(2);
1415
- }
1416
- try {
1417
- const created = await createProject(endpoint, cliToken, newName.trim());
1418
- chosenProjectId = created.id;
1419
- chosenProjectName = created.name;
1420
- apiKey = created.apiKey ?? void 0;
1421
- console.log(` \u2713 Created project "${chosenProjectName}"`);
1422
- } catch (err) {
1423
- process.stderr.write(`
1424
- error: Could not create project: ${err instanceof Error ? err.message : String(err)}
1425
- `);
1426
- process.exit(1);
1427
- }
1428
- } else {
1429
- rl.close();
1430
- }
1431
- }
1432
- if (!apiKey && chosenProjectId) {
1433
- try {
1434
- apiKey = await mintProjectKey(endpoint, cliToken, chosenProjectId) ?? void 0;
1435
- } catch {
1436
- }
1437
- }
1438
- const config = loadConfig();
1439
- config.endpoint = endpoint;
1440
- config.consoleUrl = consoleBase;
1441
- if (chosenProjectId) config.projectId = chosenProjectId;
1442
- if (apiKey) config.apiKey = apiKey;
1443
- saveConfig(config);
1444
- console.log("");
1445
- if (chosenProjectName) console.log(` \u2713 Project: ${chosenProjectName}`);
1446
- if (apiKey) {
1447
- console.log(` \u2713 Full-scope CLI key saved (${apiKey.slice(0, 12)}\u2026)`);
1448
- console.log(` Scopes: report:write \xB7 mcp:read \xB7 mcp:write \u2014 SDK + MCP + admin CLI (incl. writes) all work with this key`);
1449
- } else {
1450
- console.log(` \u2139 Get an SDK key at: ${apiKeyHint(consoleBase)}`);
1451
- }
1452
- console.log("");
1453
- if (opts.upgradeScope) {
1454
- console.log(" Key upgraded! Re-run 'mushi setup' to update your .cursor/mcp.json, then restart Cursor.");
1455
- } else {
1456
- console.log(" Run 'mushi init' to set up the SDK in this project.");
1457
- }
1458
- });
1274
+ mushi login --upgrade-scope # re-auth to add mcp:read + mcp:write to your key`).action(runLogin);
1459
1275
  program2.command("whoami").description("Verify API key and display project info").option("--json", "Machine-readable JSON output").addHelpText("after", `
1460
1276
  Verifies that MUSHI_API_KEY is valid and shows which project it belongs to.
1461
1277
  Useful after 'mushi login' to confirm credentials are correct.`).action(async (opts) => {
@@ -1547,6 +1363,189 @@ Examples:
1547
1363
  }
1548
1364
  });
1549
1365
  }
1366
+ async function runLogin(opts) {
1367
+ const { CLOUD_API_ENDPOINT, resolveCloudEndpoint: resolveCloudEndpoint2 } = await import("./endpoint-DGS73AVM.js");
1368
+ const endpoint = opts.endpoint ? resolveCloudEndpoint2(opts.endpoint) : CLOUD_API_ENDPOINT;
1369
+ const consoleBase = await resolveConsoleUrl();
1370
+ let apiKey = opts.apiKey;
1371
+ let projectId = opts.projectId;
1372
+ if (apiKey) {
1373
+ const config2 = loadConfig();
1374
+ config2.apiKey = apiKey;
1375
+ config2.endpoint = endpoint;
1376
+ if (projectId) config2.projectId = projectId;
1377
+ config2.consoleUrl = consoleBase;
1378
+ saveConfig(config2);
1379
+ console.log("");
1380
+ console.log(" \u2713 Credentials saved.");
1381
+ const verifyResult = await apiCall(
1382
+ "/v1/sync/whoami",
1383
+ { apiKey, endpoint, projectId }
1384
+ );
1385
+ if (!verifyResult.ok) {
1386
+ console.warn(` \u26A0 Key saved, but verification failed: ${verifyResult.error?.message ?? "unknown error"}`);
1387
+ console.warn(` Check your key at: ${cliSetupDeepLink(consoleBase)}`);
1388
+ return;
1389
+ }
1390
+ const d = verifyResult.data;
1391
+ if (d.project_name) {
1392
+ if (!projectId && d.project_id) {
1393
+ config2.projectId = d.project_id;
1394
+ saveConfig(config2);
1395
+ }
1396
+ console.log(` \u2713 Project: ${d.project_name} (${d.project_id})`);
1397
+ }
1398
+ console.log(` \u2713 Endpoint: ${endpoint}`);
1399
+ console.log("");
1400
+ console.log(" Run 'mushi whoami' to verify \xB7 'mushi init' to set up the SDK");
1401
+ return;
1402
+ }
1403
+ console.log("");
1404
+ if (opts.upgradeScope) {
1405
+ console.log(" Mushi login \u2014 scope upgrade");
1406
+ console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1407
+ console.log(" Re-authenticating to mint a new key with report:write + mcp:read + mcp:write scopes.");
1408
+ console.log(" This lets the CLI admin commands (including writes) and MCP server both work with a single key.");
1409
+ console.log("");
1410
+ } else {
1411
+ console.log(" Mushi login");
1412
+ console.log(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
1413
+ }
1414
+ let deviceData;
1415
+ try {
1416
+ deviceData = await startDeviceAuth(endpoint, ensureClientId());
1417
+ } catch (err) {
1418
+ process.stderr.write(`
1419
+ error: Could not start login session: ${err instanceof Error ? err.message : String(err)}
1420
+ `);
1421
+ process.stderr.write(` Fallback: mushi login --api-key <key> --project-id <uuid>
1422
+ `);
1423
+ process.exit(1);
1424
+ }
1425
+ const verifyUrl = deviceData.verification_uri;
1426
+ if (opts.browser !== false) {
1427
+ try {
1428
+ await openInBrowser(verifyUrl);
1429
+ } catch {
1430
+ }
1431
+ }
1432
+ printAuthBanner(deviceData.user_code, verifyUrl);
1433
+ let cliToken = null;
1434
+ const pollIntervalMs = (deviceData.interval ?? 5) * 1e3;
1435
+ const deadline = Date.now() + (deviceData.expires_in ?? 600) * 1e3;
1436
+ const MAX_CONSECUTIVE_ERRORS = 5;
1437
+ let consecutiveErrors = 0;
1438
+ let firstPoll = true;
1439
+ while (Date.now() < deadline) {
1440
+ if (!firstPoll) {
1441
+ await new Promise((r) => setTimeout(r, pollIntervalMs));
1442
+ }
1443
+ firstPoll = false;
1444
+ const outcome = await pollDeviceToken(endpoint, deviceData.device_code);
1445
+ if (outcome.status === "approved") {
1446
+ cliToken = outcome.cliToken;
1447
+ break;
1448
+ }
1449
+ if (outcome.status === "pending") {
1450
+ consecutiveErrors = 0;
1451
+ continue;
1452
+ }
1453
+ if (outcome.status === "error") {
1454
+ if (outcome.retryable) {
1455
+ consecutiveErrors += 1;
1456
+ if (consecutiveErrors < MAX_CONSECUTIVE_ERRORS) continue;
1457
+ }
1458
+ printAuthFailed("error", outcome.message);
1459
+ process.exit(1);
1460
+ }
1461
+ if (outcome.status === "denied") {
1462
+ printAuthFailed("denied");
1463
+ process.exit(1);
1464
+ }
1465
+ if (outcome.status === "expired") {
1466
+ printAuthFailed("timeout");
1467
+ process.exit(1);
1468
+ }
1469
+ }
1470
+ if (!cliToken) {
1471
+ printAuthFailed("timeout");
1472
+ process.exit(1);
1473
+ }
1474
+ printAuthApproved();
1475
+ const projectsList = await listProjects(endpoint, cliToken);
1476
+ let chosenProjectId = projectId;
1477
+ let chosenProjectName;
1478
+ if (!chosenProjectId) {
1479
+ const { createInterface } = await import("readline");
1480
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
1481
+ const ask = (q) => new Promise((resolve3) => rl.question(q, (a) => resolve3(a.trim())));
1482
+ if (projectsList.length > 0) {
1483
+ console.log("");
1484
+ console.log(" Your projects:");
1485
+ projectsList.forEach((p3, i) => {
1486
+ console.log(` ${i + 1}. ${p3.name} (${p3.id})`);
1487
+ });
1488
+ console.log(` ${projectsList.length + 1}. Create a new project`);
1489
+ console.log("");
1490
+ const choice = await ask(` Pick a project [1-${projectsList.length + 1}]: `);
1491
+ const num = parseInt(choice, 10);
1492
+ if (num >= 1 && num <= projectsList.length) {
1493
+ const picked = projectsList[num - 1];
1494
+ chosenProjectId = picked.id;
1495
+ chosenProjectName = picked.name;
1496
+ }
1497
+ }
1498
+ if (!chosenProjectId) {
1499
+ console.log("");
1500
+ const newName = await ask(" Project name: ");
1501
+ rl.close();
1502
+ if (!newName.trim()) {
1503
+ process.stderr.write("\nerror: Project name is required.\n");
1504
+ process.exit(2);
1505
+ }
1506
+ try {
1507
+ const created = await createProject(endpoint, cliToken, newName.trim());
1508
+ chosenProjectId = created.id;
1509
+ chosenProjectName = created.name;
1510
+ apiKey = created.apiKey ?? void 0;
1511
+ console.log(` \u2713 Created project "${chosenProjectName}"`);
1512
+ } catch (err) {
1513
+ process.stderr.write(`
1514
+ error: Could not create project: ${err instanceof Error ? err.message : String(err)}
1515
+ `);
1516
+ process.exit(1);
1517
+ }
1518
+ } else {
1519
+ rl.close();
1520
+ }
1521
+ }
1522
+ if (!apiKey && chosenProjectId) {
1523
+ try {
1524
+ apiKey = await mintProjectKey(endpoint, cliToken, chosenProjectId) ?? void 0;
1525
+ } catch {
1526
+ }
1527
+ }
1528
+ const config = loadConfig();
1529
+ config.endpoint = endpoint;
1530
+ config.consoleUrl = consoleBase;
1531
+ if (chosenProjectId) config.projectId = chosenProjectId;
1532
+ if (apiKey) config.apiKey = apiKey;
1533
+ saveConfig(config);
1534
+ console.log("");
1535
+ if (chosenProjectName) console.log(` \u2713 Project: ${chosenProjectName}`);
1536
+ if (apiKey) {
1537
+ console.log(` \u2713 Full-scope CLI key saved (${apiKey.slice(0, 12)}\u2026)`);
1538
+ console.log(` Scopes: report:write \xB7 mcp:read \xB7 mcp:write \u2014 SDK + MCP + admin CLI (incl. writes) all work with this key`);
1539
+ } else {
1540
+ console.log(` \u2139 Get an SDK key at: ${apiKeyHint(consoleBase)}`);
1541
+ }
1542
+ console.log("");
1543
+ if (opts.upgradeScope) {
1544
+ console.log(" Key upgraded! Re-run 'mushi setup' to update your .cursor/mcp.json, then restart Cursor.");
1545
+ } else {
1546
+ console.log(" Run 'mushi init' to set up the SDK in this project.");
1547
+ }
1548
+ }
1550
1549
 
1551
1550
  // src/commands/deploy.ts
1552
1551
  function registerDeployCommands(program2) {
@@ -2431,8 +2430,11 @@ error: Could not create project: ${err instanceof Error ? err.message : String(e
2431
2430
  }
2432
2431
 
2433
2432
  // src/commands/setup.ts
2433
+ function resolveLoginEndpoint(optsEndpoint, existingConfigEndpoint, envEndpoint) {
2434
+ return optsEndpoint ?? existingConfigEndpoint ?? envEndpoint?.trim();
2435
+ }
2434
2436
  function registerSetupCommands(program2) {
2435
- program2.command("setup").description("Wire Cursor MCP into your IDE (reads ~/.config/mushi/config.json \u2014 run `mushi login` first)").option("--ide <ide>", "Target IDE: cursor | claude | continue | zed", "cursor").option("--project-slug <slug>", "Override the project slug in the server name (default: fetched from API or ID prefix)").option("--all-projects", "Write a separate mushi-<name> server entry for every accessible project").option("--with-rules", "Also write the .cursorrules / .claude/rules/mushi.md lesson-library hook").option("--dry-run", "Print what would be written without making changes").option("--verify", "Probe the MCP key after writing to confirm it has mcp:read scope (default: on)").option("--no-verify", "Skip the post-write key probe").addHelpText("after", `
2437
+ program2.command("setup").description("Wire Cursor MCP into your IDE (reads ~/.config/mushi/config.json \u2014 run `mushi login` first)").option("--ide <ide>", "Target IDE: cursor | claude | continue | zed", "cursor").option("--project-slug <slug>", "Override the project slug in the server name (default: fetched from API or ID prefix)").option("--all-projects", "Write a separate mushi-<name> server entry for every accessible project").option("--with-rules", "Also write the .cursorrules / .claude/rules/mushi.md lesson-library hook").option("--dry-run", "Print what would be written without making changes").option("--verify", "Probe the MCP key after writing to confirm it has mcp:read scope (default: on)").option("--no-verify", "Skip the post-write key probe").option("--endpoint <url>", "Override the Mushi API endpoint (self-hosted) \u2014 used for first-run login if not yet configured").addHelpText("after", `
2436
2438
  Examples:
2437
2439
  mushi setup # wire Cursor (default)
2438
2440
  mushi setup --all-projects # one server entry per accessible project
@@ -2450,6 +2452,11 @@ The command reads credentials from ~/.config/mushi/config.json (run \`mushi logi
2450
2452
  const { existsSync: existsSync3 } = await import("fs");
2451
2453
  const nodePath2 = await import("path");
2452
2454
  const os = await import("os");
2455
+ const existingConfig = loadConfig();
2456
+ if (!existingConfig.apiKey) {
2457
+ const endpoint = resolveLoginEndpoint(opts.endpoint, existingConfig.endpoint, process.env.MUSHI_API_ENDPOINT);
2458
+ await runLogin({ endpoint });
2459
+ }
2453
2460
  const config = requireConfig({ needsProject: true });
2454
2461
  const redactKeyForDisplay = (text2) => {
2455
2462
  const key = config.apiKey;
package/dist/init.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  resolveConsoleUrl,
15
15
  resolveConsoleUrlSync,
16
16
  saveConfig
17
- } from "./chunk-GUVGTFVK.js";
17
+ } from "./chunk-2WHQONHK.js";
18
18
  import {
19
19
  FRAMEWORKS,
20
20
  detectFramework,
@@ -25,7 +25,7 @@ import {
25
25
  } from "./chunk-AIZRI665.js";
26
26
  import {
27
27
  MUSHI_CLI_VERSION
28
- } from "./chunk-X74T7JKC.js";
28
+ } from "./chunk-SS42XQ57.js";
29
29
 
30
30
  // src/init.ts
31
31
  import * as p from "@clack/prompts";
@@ -224,28 +224,26 @@ async function createProject(endpoint, cliToken, name) {
224
224
  }
225
225
  async function mintProjectKey(endpoint, cliToken, projectId) {
226
226
  const base = trimTrailingSlash(endpoint);
227
- return withOneRetry(async () => {
228
- let res;
229
- try {
230
- res = await deviceFetch(`${base}/v1/cli/projects/${projectId}/keys`, {
231
- method: "POST",
232
- headers: cliAuthHeaders(cliToken),
233
- body: JSON.stringify({})
234
- });
235
- } catch (err) {
236
- throw new DeviceAuthRequestError(
237
- "mint_key",
238
- `Could not reach ${base}/v1/cli/projects/\u2026/keys: ${err instanceof Error ? err.message : String(err)}`
239
- );
240
- }
241
- const json = await res.json().catch(() => null);
242
- if (res.ok && json?.ok && json.data?.key) return json.data.key;
227
+ let res;
228
+ try {
229
+ res = await deviceFetch(`${base}/v1/cli/projects/${projectId}/keys`, {
230
+ method: "POST",
231
+ headers: cliAuthHeaders(cliToken),
232
+ body: JSON.stringify({})
233
+ });
234
+ } catch (err) {
243
235
  throw new DeviceAuthRequestError(
244
236
  "mint_key",
245
- json?.error?.message ?? `Could not mint an SDK key (HTTP ${res.status}).`,
246
- res.ok ? void 0 : res.status
237
+ `Could not reach ${base}/v1/cli/projects/\u2026/keys: ${err instanceof Error ? err.message : String(err)}`
247
238
  );
248
- });
239
+ }
240
+ const json = await res.json().catch(() => null);
241
+ if (res.ok && json?.ok && json.data?.key) return json.data.key;
242
+ throw new DeviceAuthRequestError(
243
+ "mint_key",
244
+ json?.error?.message ?? `Could not mint an SDK key (HTTP ${res.status}).`,
245
+ res.status
246
+ );
249
247
  }
250
248
 
251
249
  // src/freshness.ts
@@ -943,7 +941,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
943
941
  if (p.isCancel(answer) || !answer) return;
944
942
  const endpoint = resolveCloudEndpoint(options.endpoint);
945
943
  try {
946
- const { runConnect } = await import("./connect-7LTQRBEW.js");
944
+ const { runConnect } = await import("./connect-XFWRSEMW.js");
947
945
  await runConnect({
948
946
  apiKey: credentials.apiKey,
949
947
  projectId: credentials.projectId,
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MUSHI_CLI_VERSION
3
- } from "./chunk-X74T7JKC.js";
3
+ } from "./chunk-SS42XQ57.js";
4
4
  export {
5
5
  MUSHI_CLI_VERSION
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mushi-mushi/cli",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "license": "MIT",
5
5
  "description": "CLI for Mushi Mushi — `mushi init` wizard installs the right SDK for your framework, plus report triage and pipeline health commands",
6
6
  "bin": {
@@ -1,6 +0,0 @@
1
- // src/version.ts
2
- var MUSHI_CLI_VERSION = true ? "0.24.0" : "0.0.0-dev";
3
-
4
- export {
5
- MUSHI_CLI_VERSION
6
- };