@mushi-mushi/cli 0.36.0 → 0.36.2

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/README.md CHANGED
@@ -21,7 +21,7 @@ npm install -g @mushi-mushi/cli # optional: a global `mushi` command
21
21
 
22
22
  The wizard detects your framework and package manager, checks your credentials, installs the right SDK, writes framework-prefixed env vars (`NEXT_PUBLIC_`, `VITE_`, `EXPO_PUBLIC_`…) to `.env.local`, prints the snippet to paste, and offers to send a test report. It never overwrites an existing env var or edits your code.
23
23
 
24
- **Credentials** come from the [console](https://kensaur.us/mushi-mushi/admin): the **project ID** is on the Projects page; the **API key** is under **Setup → Verify → Generate API key** (`report:write`), not the AI keys in Settings. No project yet? The wizard can open the console for you.
24
+ **Credentials** come from the [console](https://kensaur.us/mushi-mushi/admin): the **project ID** is on the **Manage apps** page; the **API key** is under **Set up → Test it → Generate API key** (`report:write`), not the AI keys in Settings. No project yet? The wizard can open the console for you.
25
25
 
26
26
  For your editor, `mushi setup` writes the hosted MCP entry by default: the editor opens a browser sign-in on first use and no key is stored on disk. Add `--stdio` for a local server instead.
27
27
 
@@ -32,7 +32,7 @@ For your editor, `mushi setup` writes the hosted MCP entry by default: the edito
32
32
  | Set up | `init`, `login`, `setup`, `connect`, `doctor`, `test` (send a test report), `upgrade`, `nudge`, `completion`, `profile` |
33
33
  | Bugs | `reports list/show/search/triage`, `lessons list/show`, `sentry import` |
34
34
  | Fixes | `fix <reportId>`, `fixes tail/merge/refresh-ci/review/verify`, `verify workflow` |
35
- | Local agent | `work` (a Cursor agent on your own computer fixes a report; you push), `worker install/status/revoke` (keeps it running, steered from the console) |
35
+ | Local agent | `work` (the Cursor CLI or Claude Code on your own computer fixes a report; `mushi work` pushes and opens the draft PR with your `git` and `gh`), `worker install/status/revoke` (keeps it running, steered from the console) |
36
36
  | Ship | `sourcemaps upload`, `deploy check`, `migrate`, `audit`, `releases` |
37
37
  | Test and UX | `qa stories/runs/run`, `tdd gen/pending/approve/improve`, `stories map`, `ux` (including `ux fresh-eyes`, the first-time user test) |
38
38
  | CI | `runner status/compare/bill`: where your tests run, what they cost, and whether a red check was your code or the machine |
@@ -45,7 +45,7 @@ For your editor, `mushi setup` writes the hosted MCP entry by default: the edito
45
45
  ```bash
46
46
  mushi doctor --fix # check SDK, ingest and dispatch; fix what's safe locally
47
47
  mushi reports list --status new --severity critical # what broke
48
- mushi fix <reportId> --wait # an agent opens a draft PR for it (your own AI key)
48
+ mushi fix <reportId> --wait # the built-in fixer opens a draft PR for it
49
49
  mushi fixes merge <fixId> # merge it and mark the report Fixed
50
50
  mushi upgrade # bump @mushi-mushi/* to the latest stable
51
51
  mushi upgrade --check # CI: exit 0 current, 1 outdated, 2 registry down
@@ -62,7 +62,7 @@ MUSHI_API_KEY=mushi_xxx mushi connect --project-id <uuid> --endpoint <url> --wai
62
62
 
63
63
  Other `init` flags: `--framework next`, `--cwd apps/web` (monorepos), `--endpoint <url>` (self-hosted), `--skip-install`, `--audit` (check an existing install instead).
64
64
 
65
- **What needs your own key.** Reading reports, diagnoses and fix prompts does not. `mushi fix` hands the report to an agent that runs on your own key: Anthropic for the built-in fixer (the default), or Cursor with `--agent cursor_cloud`. `mushi work` runs a Cursor agent on your own computer instead.
65
+ **What needs your own key.** Reading reports, diagnoses and fix prompts does not. `mushi fix` hands the report to the built-in fixer by default (`--agent claude_code`): it uses your own Anthropic or OpenAI key when you have added one, and on hosted Mushi Mushi it falls back to Mushi Mushi's key when you have not. `--agent cursor_cloud` needs your own Cursor key. `mushi work` runs the Cursor CLI or Claude Code (`--agent claude`, CLI 0.36.0 or later) on your own computer instead, on the account that tool is signed in to.
66
66
 
67
67
  ## Environment variables
68
68
 
@@ -9,10 +9,10 @@ import {
9
9
  requireUuid,
10
10
  saveConfig,
11
11
  savedSdkKeyFor
12
- } from "./chunk-T2NBO4WL.js";
12
+ } from "./chunk-H6HZNVVT.js";
13
13
  import {
14
14
  MUSHI_MCP_PIN_SPEC
15
- } from "./chunk-MV3SEIJM.js";
15
+ } from "./chunk-YYDQ3IYE.js";
16
16
  import {
17
17
  assertEndpoint,
18
18
  normalizeEndpoint
@@ -0,0 +1,8 @@
1
+ // src/version.ts
2
+ var MUSHI_CLI_VERSION = true ? "0.36.2" : "0.0.0-dev";
3
+ var MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.7";
4
+
5
+ export {
6
+ MUSHI_CLI_VERSION,
7
+ MUSHI_MCP_PIN_SPEC
8
+ };
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  MUSHI_CLI_VERSION
4
- } from "./chunk-MV3SEIJM.js";
4
+ } from "./chunk-YYDQ3IYE.js";
5
5
  import {
6
6
  CLOUD_API_ENDPOINT,
7
7
  normalizeEndpoint
@@ -14,6 +14,7 @@ var EXIT_CODE_MAP = {
14
14
  E_PROJECT_MISSING: 2,
15
15
  E_ENDPOINT_INVALID: 2,
16
16
  E_INVALID_INPUT: 2,
17
+ E_WRONG_REPO: 2,
17
18
  E_NOT_INTERACTIVE: 2,
18
19
  E_NETWORK: 3,
19
20
  E_TIMEOUT: 3,
@@ -771,6 +772,7 @@ export {
771
772
  getAbortSignal,
772
773
  isKeychainEnabled,
773
774
  trySaveKeyToKeychain,
775
+ tryLoadKeyFromKeychain,
774
776
  syncKeychainAfterKeyChange,
775
777
  trySaveWorkerKey,
776
778
  tryLoadWorkerKey,
@@ -8,10 +8,10 @@ import {
8
8
  requireConfig,
9
9
  requireUuid,
10
10
  tryLoadWorkerKey
11
- } from "./chunk-T2NBO4WL.js";
11
+ } from "./chunk-H6HZNVVT.js";
12
12
  import {
13
13
  MUSHI_CLI_VERSION
14
- } from "./chunk-MV3SEIJM.js";
14
+ } from "./chunk-YYDQ3IYE.js";
15
15
 
16
16
  // src/worker/daemon.ts
17
17
  import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
@@ -405,6 +405,43 @@ ${run.stderr}`).trim();
405
405
  ${text.slice(-2e3)}` : text);
406
406
  }
407
407
 
408
+ // src/commands/work-repo.ts
409
+ function redactRemote(url) {
410
+ return url.trim().replace(/^([a-z][a-z0-9+.-]*:\/\/)[^@/]*@/i, "$1");
411
+ }
412
+ function normaliseRepoUrl(url) {
413
+ let s = url.trim();
414
+ if (!s) return null;
415
+ const proto = /^[a-z][a-z0-9+.-]*:\/\//i.exec(s);
416
+ if (proto) {
417
+ s = s.slice(proto[0].length).replace(/^[^@/]*@/, "");
418
+ s = s.replace(/^([^/:]+):\d+(?=\/|$)/, "$1");
419
+ } else {
420
+ s = s.replace(/^[^@/]*@/, "");
421
+ s = s.replace(/^([^/:]+):(?!\/)/, "$1/");
422
+ }
423
+ s = s.replace(/\/+$/, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
424
+ if (!s) return null;
425
+ const parts = s.split("/").filter(Boolean);
426
+ if (parts.length === 2 && !parts[0].includes(".")) parts.unshift("github.com");
427
+ return parts.length ? parts.join("/") : null;
428
+ }
429
+ function originMatchesRepos(origin, repoUrls) {
430
+ if (!repoUrls.length) return true;
431
+ const o = origin ? normaliseRepoUrl(origin) : null;
432
+ if (!o) return false;
433
+ return repoUrls.some((u) => normaliseRepoUrl(u) === o);
434
+ }
435
+ function wrongRepoMessage(o) {
436
+ if (!o.repoUrls?.length || originMatchesRepos(o.origin, o.repoUrls)) return null;
437
+ const project = o.projectName ? `${o.projectName}${o.projectId ? ` (${o.projectId})` : ""}` : o.projectId ?? "this key's project";
438
+ const origin = o.origin ? redactRemote(o.origin) : "(no origin remote)";
439
+ return {
440
+ message: `Wrong repo: your Mushi key belongs to ${project}, which is linked to ${o.repoUrls.join(", ")}, but ${o.repoDir} has origin ${origin}. mushi work would apply that project's reports to this repo, so it stopped before claiming anything.`,
441
+ hint: "In this repo, run `mushi login --upgrade-scope --project-id <the project for this repo>`, or pass --repo-dir with a clone of the linked repo. For a monorepo or a fork, pass --any-repo to skip this check."
442
+ };
443
+ }
444
+
408
445
  // src/commands/work.ts
409
446
  import { spawn } from "child_process";
410
447
  import { createHash as createHash2 } from "crypto";
@@ -452,7 +489,7 @@ function cap(text, max) {
452
489
  return t.length > max ? `${t.slice(0, max)} [cut]` : t;
453
490
  }
454
491
  function failureTail(r, max = 600) {
455
- const t = [r.stdout, r.stderr].map((x) => x.trim()).filter(Boolean).join("\n").replace(/[ \t]+/g, " ");
492
+ const t = stripVTControlCharacters2([r.stdout, r.stderr].map((x) => x.trim()).filter(Boolean).join("\n")).replace(/[ \t]+/g, " ");
456
493
  const lines = t.split("\n").map((l) => l.trim()).filter(Boolean);
457
494
  const kept = [];
458
495
  let size = 0;
@@ -1020,10 +1057,15 @@ async function installDeps(wt, log) {
1020
1057
  const cmd = installCommand((f) => existsSync(join2(wt, f)));
1021
1058
  if (!cmd) return;
1022
1059
  log(` deps: ${cmd[0]} ${cmd[1][0]} (so the agent can run tests and the commit hooks work)`);
1023
- let r = await runProc(cmd[0], cmd[1], { cwd: wt, timeoutMs: 10 * 6e4 });
1024
- if (r.code !== 0) r = await runProc(cmd[0], cmd[1], { cwd: wt, timeoutMs: 10 * 6e4 });
1060
+ const [bin, args] = windowsShim(cmd, process.platform);
1061
+ let r = await runProc(bin, args, { cwd: wt, timeoutMs: 10 * 6e4 });
1062
+ if (r.code !== 0) r = await runProc(bin, args, { cwd: wt, timeoutMs: 10 * 6e4 });
1025
1063
  if (r.code !== 0) log(` deps: install failed twice, the agent works without them (${failureTail(r, 300)})`);
1026
1064
  }
1065
+ function windowsShim(cmd, platform) {
1066
+ if (platform !== "win32") return cmd;
1067
+ return ["cmd.exe", ["/d", "/s", "/c", cmd[0], ...cmd[1]]];
1068
+ }
1027
1069
  function isMissingModuleFailure(message) {
1028
1070
  return /ERR_MODULE_NOT_FOUND|Cannot find (package|module)/.test(message);
1029
1071
  }
@@ -1091,10 +1133,29 @@ function missingWriteScope(scopes, projectId) {
1091
1133
  const have = scopes.length ? scopes.join(", ") : "no scopes";
1092
1134
  return `This CLI key has ${have}; mushi work also needs mcp:write to record the fix and queue its review. Run: mushi login --upgrade-scope${projectId ? ` --project-id ${projectId}` : ""}`;
1093
1135
  }
1094
- async function requireWriteScope(cfg) {
1136
+ async function readWhoami(cfg) {
1095
1137
  const res = await apiCall("/v1/sync/whoami", cfg);
1096
- const scopes = res.ok ? res.data?.scopes : void 0;
1097
- const problem = missingWriteScope(scopes, cfg.projectId);
1138
+ return res.ok ? res.data : void 0;
1139
+ }
1140
+ async function originOf(repoDir) {
1141
+ if (!existsSync(repoDir)) return null;
1142
+ const r = await runProc("git", ["remote", "get-url", "origin"], { cwd: repoDir, timeoutMs: 3e4 });
1143
+ const url = r.code === 0 ? r.stdout.trim() : "";
1144
+ return url || null;
1145
+ }
1146
+ async function requireRightRepo(whoami, repoDir) {
1147
+ if (!whoami?.repo_urls?.length) return;
1148
+ const problem = wrongRepoMessage({
1149
+ projectName: whoami.project_name,
1150
+ projectId: whoami.project_id,
1151
+ repoUrls: whoami.repo_urls,
1152
+ origin: await originOf(repoDir),
1153
+ repoDir
1154
+ });
1155
+ if (problem) throw new MushiCliError("E_WRONG_REPO", problem.message, problem.hint);
1156
+ }
1157
+ function requireWriteScope(cfg, whoami) {
1158
+ const problem = missingWriteScope(whoami?.scopes, cfg.projectId);
1098
1159
  if (problem) throw new MushiCliError("E_AUTH_MISSING", problem, `mushi login --upgrade-scope${cfg.projectId ? ` --project-id ${cfg.projectId}` : ""}`);
1099
1160
  }
1100
1161
  function stopLine(agent, left, what) {
@@ -1102,14 +1163,14 @@ function stopLine(agent, left, what) {
1102
1163
  return `Stopped: the ${spec.label} agent could not run (out of usage or signed out). ${left} ${what}${left === 1 ? "" : "s"} left untouched and can be picked up again; the run was closed without a retry cooldown. Check: ${spec.bin} ${spec.status.join(" ")}`;
1103
1164
  }
1104
1165
  function registerWorkCommands(program) {
1105
- program.command("work").description("Fix reports with a coding agent on this machine (the Cursor CLI or Claude Code); pushes and opens the draft PR with your git and gh").option("--repo-dir <path>", "A clone of the app repo (only worktrees are created in it); not with --daemon").option("--project <id>", "Project id (overrides MUSHI_PROJECT_ID)").option("--agent <name>", "Local agent: cursor (cursor-agent, default) or claude (Claude Code, claude -p); with --daemon, overrides the worker config's agent").option("--model <id>", "Model for the agent (cursor: cursor-agent --list-models; claude: opus, sonnet, haiku or a claude-\u2026 id)").option("--max <n>", "Reports per run", "3").option("--report <id>", "Work on this report only").option("--followups", 'Instead of new reports: fix the Opus "fix first" findings on PRs mushi work opened, and push to them').option("--keep", "Keep the worktree after the run").option("--dry-run", "Show what would run; change nothing").option("--json", "Machine-readable JSON output").option("--daemon", "Run as a local worker: register this machine, send a heartbeat every 60 s, take the console's lane settings and claim reports (set up with `mushi worker install`)").option("--worker-config <path>", "With --daemon: the lanes file (default ~/.config/mushi/worker.json)").action(async (opts) => {
1166
+ program.command("work").description("Fix reports with a coding agent on this machine (the Cursor CLI or Claude Code); pushes and opens the draft PR with your git and gh").option("--repo-dir <path>", "A clone of the app repo (only worktrees are created in it); not with --daemon").option("--project <id>", "Project id (overrides MUSHI_PROJECT_ID)").option("--agent <name>", "Local agent: cursor (cursor-agent, default) or claude (Claude Code, claude -p); with --daemon, overrides the worker config's agent").option("--model <id>", "Model for the agent (cursor: cursor-agent --list-models; claude: opus, sonnet, haiku or a claude-\u2026 id)").option("--max <n>", "Reports per run", "3").option("--report <id>", "Work on this report only").option("--followups", 'Instead of new reports: fix the Opus "fix first" findings on PRs mushi work opened, and push to them').option("--keep", "Keep the worktree after the run").option("--dry-run", "Show what would run; change nothing").option("--any-repo", "Skip the check that the clone is a repo the key's project is linked to (a monorepo or a fork)").option("--json", "Machine-readable JSON output").option("--daemon", "Run as a local worker: register this machine, send a heartbeat every 60 s, take the console's lane settings and claim reports (set up with `mushi worker install`)").option("--worker-config <path>", "With --daemon: the lanes file (default ~/.config/mushi/worker.json)").action(async (opts) => {
1106
1167
  const agent = parseLocalAgent(opts.agent);
1107
1168
  if (opts.daemon) {
1108
1169
  if (opts.repoDir || opts.report || opts.followups) {
1109
1170
  throw new MushiCliError("E_INVALID_INPUT", "--daemon takes its lanes and clones from the worker config, not from --repo-dir, --report or --followups.", "mushi worker install");
1110
1171
  }
1111
- const { runDaemon: runDaemon2 } = await import("./daemon-ZGSTNMAY.js");
1112
- await runDaemon2({ configPath: opts.workerConfig, ...opts.agent !== void 0 ? { agent } : {} });
1172
+ const { runDaemon: runDaemon2 } = await import("./daemon-D3BEJ4ZR.js");
1173
+ await runDaemon2({ configPath: opts.workerConfig, ...opts.agent !== void 0 ? { agent } : {}, ...opts.anyRepo ? { anyRepo: true } : {} });
1113
1174
  return;
1114
1175
  }
1115
1176
  if (!opts.repoDir) throw new MushiCliError("E_INVALID_INPUT", "mushi work needs --repo-dir <clone>.", "mushi work --repo-dir ~/src/my-app");
@@ -1125,6 +1186,8 @@ function registerWorkCommands(program) {
1125
1186
  };
1126
1187
  const warn = (l) => process.stderr.write(`${l}
1127
1188
  `);
1189
+ const whoami = await readWhoami(cfg);
1190
+ if (!opts.anyRepo) await requireRightRepo(whoami, repoDir);
1128
1191
  if (opts.followups) {
1129
1192
  const listed = await api(`/v1/admin/projects/${cfg.projectId}/local-followups`);
1130
1193
  const due = listed.fixes.slice(0, max);
@@ -1136,7 +1199,7 @@ function registerWorkCommands(program) {
1136
1199
  return;
1137
1200
  }
1138
1201
  await preflight(repoDir, warn, agent);
1139
- await requireWriteScope(cfg);
1202
+ requireWriteScope(cfg, whoami);
1140
1203
  const results2 = [];
1141
1204
  for (const f of due) {
1142
1205
  if (interruptedBy()) break;
@@ -1167,7 +1230,7 @@ function registerWorkCommands(program) {
1167
1230
  return;
1168
1231
  }
1169
1232
  await preflight(repoDir, warn, agent);
1170
- await requireWriteScope(cfg);
1233
+ requireWriteScope(cfg, whoami);
1171
1234
  const results = [];
1172
1235
  for (const d of picked) {
1173
1236
  if (interruptedBy()) break;
@@ -2874,6 +2937,7 @@ async function runDaemon(opts = {}) {
2874
2937
  if (gh.code !== 0) process.stdout.write("worker: gh is not signed in on this machine; lanes take nothing until it is (run: gh auth login).\n");
2875
2938
  const repos = /* @__PURE__ */ new Map();
2876
2939
  const notReady = /* @__PURE__ */ new Map();
2940
+ const origins = /* @__PURE__ */ new Map();
2877
2941
  for (const lane of cfg.lanes) {
2878
2942
  const g = await runProc("git", ["rev-parse", "--git-dir"], { cwd: lane.repoDir, timeoutMs: 3e4 });
2879
2943
  if (g.code !== 0) {
@@ -2885,8 +2949,28 @@ async function runDaemon(opts = {}) {
2885
2949
  const origin = await runProc("git", ["remote", "get-url", "origin"], { cwd: lane.repoDir, timeoutMs: 3e4 });
2886
2950
  const repo = origin.code === 0 ? repoOfRemote(origin.stdout) : null;
2887
2951
  if (repo) repos.set(lane.name, repo);
2952
+ if (origin.code === 0 && origin.stdout.trim()) origins.set(lane.name, origin.stdout.trim());
2888
2953
  }
2889
2954
  const conf = { apiKey: key, endpoint };
2955
+ if (!opts.anyRepo) {
2956
+ const who = await apiCall("/v1/sync/whoami", conf, {}, { timeoutMs: 3e4 });
2957
+ if (who.ok) {
2958
+ for (const lane of cfg.lanes) {
2959
+ if (notReady.has(lane.name) || lane.projectId !== who.data.project_id) continue;
2960
+ const problem = wrongRepoMessage({
2961
+ projectName: who.data.project_name,
2962
+ projectId: who.data.project_id,
2963
+ repoUrls: who.data.repo_urls,
2964
+ origin: origins.get(lane.name) ?? null,
2965
+ repoDir: lane.repoDir
2966
+ });
2967
+ if (!problem) continue;
2968
+ process.stdout.write(`worker: lane ${lane.name}: ${problem.message} The lane stays out until it is fixed (or restart with --any-repo).
2969
+ `);
2970
+ notReady.set(lane.name, `Its clone is not a repo ${who.data.project_name || "this project"} is linked to (${who.data.repo_urls.join(", ")}); point the lane at a clone of one, or restart the worker with --any-repo`);
2971
+ }
2972
+ }
2973
+ }
2890
2974
  let wake = () => void 0;
2891
2975
  const readings = createHostReadings({
2892
2976
  ...cursorAccount ? { cursorAccount } : {},
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MUSHI_CLI_VERSION
3
- } from "./chunk-FRVELHB4.js";
3
+ } from "./chunk-76LVDUR5.js";
4
4
  import {
5
5
  assertEndpoint,
6
6
  normalizeEndpoint
@@ -415,6 +415,7 @@ var EXIT_CODE_MAP = {
415
415
  E_PROJECT_MISSING: 2,
416
416
  E_ENDPOINT_INVALID: 2,
417
417
  E_INVALID_INPUT: 2,
418
+ E_WRONG_REPO: 2,
418
419
  E_NOT_INTERACTIVE: 2,
419
420
  E_NETWORK: 3,
420
421
  E_TIMEOUT: 3,
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/version.ts
4
+ var MUSHI_CLI_VERSION = true ? "0.36.2" : "0.0.0-dev";
5
+ var MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.7";
6
+
7
+ export {
8
+ MUSHI_CLI_VERSION,
9
+ MUSHI_MCP_PIN_SPEC
10
+ };
@@ -6,10 +6,10 @@ import {
6
6
  saveConfig,
7
7
  savedSdkKeyFor,
8
8
  waitForIngestReady
9
- } from "./chunk-GHG5XKGP.js";
9
+ } from "./chunk-TN2IZOY7.js";
10
10
  import {
11
11
  MUSHI_MCP_PIN_SPEC
12
- } from "./chunk-FRVELHB4.js";
12
+ } from "./chunk-76LVDUR5.js";
13
13
  import {
14
14
  detectFramework,
15
15
  envVarsToWrite,
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  resolveSdkEnvKey,
4
4
  runConnect
5
- } from "./chunk-NHE5JMLQ.js";
5
+ } from "./chunk-2JOEQQOU.js";
6
6
  import "./chunk-KOBEOGNF.js";
7
- import "./chunk-T2NBO4WL.js";
8
- import "./chunk-MV3SEIJM.js";
7
+ import "./chunk-H6HZNVVT.js";
8
+ import "./chunk-YYDQ3IYE.js";
9
9
  import "./chunk-LGGE3LH7.js";
10
10
  export {
11
11
  resolveSdkEnvKey,
@@ -10,9 +10,9 @@ import {
10
10
  readWorkerKey,
11
11
  runDaemon,
12
12
  workerHostId
13
- } from "./chunk-YJ5Z6ZDX.js";
14
- import "./chunk-T2NBO4WL.js";
15
- import "./chunk-MV3SEIJM.js";
13
+ } from "./chunk-OKT53MJ7.js";
14
+ import "./chunk-H6HZNVVT.js";
15
+ import "./chunk-YYDQ3IYE.js";
16
16
  import "./chunk-LGGE3LH7.js";
17
17
  export {
18
18
  assertWorkerKey,
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import {
22
22
  sanitizeEndpoint,
23
23
  sanitizeProjectId,
24
24
  writeMcpServerEntry
25
- } from "./chunk-NHE5JMLQ.js";
25
+ } from "./chunk-2JOEQQOU.js";
26
26
  import {
27
27
  FRAMEWORKS,
28
28
  detectFramework,
@@ -50,7 +50,7 @@ import {
50
50
  registerUxCommands,
51
51
  registerWorkCommands,
52
52
  validateWorkerConfig
53
- } from "./chunk-YJ5Z6ZDX.js";
53
+ } from "./chunk-OKT53MJ7.js";
54
54
  import {
55
55
  CONFIG_PATH,
56
56
  MushiCliError,
@@ -86,13 +86,14 @@ import {
86
86
  setGlobalOutputFormat,
87
87
  syncKeychainAfterKeyChange,
88
88
  tryDeleteWorkerKey,
89
+ tryLoadKeyFromKeychain,
89
90
  trySaveKeyToKeychain,
90
91
  trySaveWorkerKey
91
- } from "./chunk-T2NBO4WL.js";
92
+ } from "./chunk-H6HZNVVT.js";
92
93
  import {
93
94
  MUSHI_CLI_VERSION,
94
95
  MUSHI_MCP_PIN_SPEC
95
- } from "./chunk-MV3SEIJM.js";
96
+ } from "./chunk-YYDQ3IYE.js";
96
97
  import {
97
98
  CLOUD_API_ENDPOINT,
98
99
  CLOUD_MCP_OAUTH_URL,
@@ -427,6 +428,17 @@ function printAuthFailed(reason, detail) {
427
428
  console.log("");
428
429
  }
429
430
 
431
+ // src/env-key-override.ts
432
+ function envKeyOverrideLines(env, savedKey, platform = process.platform) {
433
+ const envKey = env.MUSHI_API_KEY?.trim();
434
+ if (!envKey || savedKey && envKey === savedKey) return [];
435
+ const where = platform === "win32" ? 'Remove it under Windows Settings \u2192 System \u2192 About \u2192 Advanced system settings \u2192 Environment Variables, or open a new terminal after `[Environment]::SetEnvironmentVariable("MUSHI_API_KEY", $null, "User")` in PowerShell.' : "Remove the `export MUSHI_API_KEY=\u2026` line from your shell profile, or run `unset MUSHI_API_KEY` in this terminal.";
436
+ return [
437
+ `\u26A0 MUSHI_API_KEY is set in your environment (${envKey.slice(0, 12)}\u2026), and it overrides ${savedKey ? `the saved key (${savedKey.slice(0, 12)}\u2026)` : "the saved key"}.`,
438
+ ` Commands in this terminal use the environment key. ${where}`
439
+ ];
440
+ }
441
+
430
442
  // src/login.ts
431
443
  function getPostLoginBannerMessage(opts) {
432
444
  if (opts.suppressPostLoginBanner) return null;
@@ -674,8 +686,10 @@ error: Could not create project: ${err instanceof Error ? err.message : String(e
674
686
  if (opts.upgradeScope) {
675
687
  console.log(` \u2713 Full-scope CLI key saved (${apiKey.slice(0, 12)}\u2026)`);
676
688
  console.log(` Scopes: report:write \xB7 mcp:read \xB7 mcp:write \u2014 SDK + MCP + admin CLI (incl. writes) all work with this key`);
689
+ for (const line of envKeyOverrideLines(process.env, apiKey)) console.log(` ${line}`);
677
690
  } else {
678
691
  console.log(` \u2713 CLI key saved (${apiKey.slice(0, 12)}\u2026)`);
692
+ for (const line of envKeyOverrideLines(process.env, apiKey)) console.log(` ${line}`);
679
693
  console.log(` Scopes: report:write \xB7 mcp:read \u2014 SDK ingest + MCP read tools.`);
680
694
  console.log(` Admin writes (mushi work, fix merge, billing cap, pipeline start) need: mushi login --upgrade-scope${chosenProjectId ? ` --project-id ${chosenProjectId}` : ""}`);
681
695
  }
@@ -1595,7 +1609,7 @@ async function checkOnboardingStatus(config, _consoleBase, cwd, doFetch = global
1595
1609
  }
1596
1610
  async function checkVersionDrift(cwd, doFetch) {
1597
1611
  const checks = [];
1598
- const { MUSHI_CLI_VERSION: MUSHI_CLI_VERSION2 } = await import("./version-673M6J44.js");
1612
+ const { MUSHI_CLI_VERSION: MUSHI_CLI_VERSION2 } = await import("./version-TOLAY73N.js");
1599
1613
  if (MUSHI_CLI_VERSION2 === "0.0.0-dev") return checks;
1600
1614
  const parse2 = (v) => {
1601
1615
  const m = v.replace(/^[~^]/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
@@ -2568,7 +2582,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
2568
2582
  if (p.isCancel(answer) || !answer) return;
2569
2583
  const endpoint = resolveCloudEndpoint(options.endpoint);
2570
2584
  try {
2571
- const { runConnect: runConnect2 } = await import("./connect-GVDAI3RJ.js");
2585
+ const { runConnect: runConnect2 } = await import("./connect-YZMEO7Y5.js");
2572
2586
  const saved = loadConfig();
2573
2587
  const result = await runConnect2(
2574
2588
  {
@@ -2915,6 +2929,7 @@ Useful after 'mushi login' to confirm credentials are correct.`).action(async (o
2915
2929
  console.log(" Mint one on the console MCP page, or run `mushi login`.");
2916
2930
  }
2917
2931
  }
2932
+ for (const line of envKeyOverrideLines(process.env, tryLoadKeyFromKeychain() ?? void 0)) console.log(` ${line}`);
2918
2933
  }
2919
2934
  });
2920
2935
  program2.command("ping").description("Check connectivity to the Mushi backend").option("--json", "Machine-readable JSON output").action(async (opts) => {
package/dist/init.js CHANGED
@@ -25,10 +25,10 @@ import {
25
25
  saveConfig,
26
26
  savedSdkKeyFor,
27
27
  trySaveKeyToKeychain
28
- } from "./chunk-GHG5XKGP.js";
28
+ } from "./chunk-TN2IZOY7.js";
29
29
  import {
30
30
  MUSHI_CLI_VERSION
31
- } from "./chunk-FRVELHB4.js";
31
+ } from "./chunk-76LVDUR5.js";
32
32
  import {
33
33
  FRAMEWORKS,
34
34
  detectFramework,
@@ -2127,7 +2127,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
2127
2127
  if (p.isCancel(answer) || !answer) return;
2128
2128
  const endpoint = resolveCloudEndpoint(options.endpoint);
2129
2129
  try {
2130
- const { runConnect } = await import("./connect-CHLNFDG5.js");
2130
+ const { runConnect } = await import("./connect-W4VHAQIQ.js");
2131
2131
  const saved = loadConfig();
2132
2132
  const result = await runConnect(
2133
2133
  {
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  MUSHI_CLI_VERSION,
4
4
  MUSHI_MCP_PIN_SPEC
5
- } from "./chunk-MV3SEIJM.js";
5
+ } from "./chunk-YYDQ3IYE.js";
6
6
  export {
7
7
  MUSHI_CLI_VERSION,
8
8
  MUSHI_MCP_PIN_SPEC
package/dist/version.d.ts CHANGED
@@ -14,6 +14,6 @@ declare const MUSHI_CLI_VERSION: string;
14
14
  * setup refreshes the pin. Synced to packages/mcp/package.json by
15
15
  * `scripts/sync-mcp-pin.mjs` — never hand-edit the version.
16
16
  */
17
- declare const MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.5";
17
+ declare const MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.7";
18
18
 
19
19
  export { MUSHI_CLI_VERSION, MUSHI_MCP_PIN_SPEC };
package/dist/version.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  MUSHI_CLI_VERSION,
3
3
  MUSHI_MCP_PIN_SPEC
4
- } from "./chunk-FRVELHB4.js";
4
+ } from "./chunk-76LVDUR5.js";
5
5
  export {
6
6
  MUSHI_CLI_VERSION,
7
7
  MUSHI_MCP_PIN_SPEC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mushi-mushi/cli",
3
- "version": "0.36.0",
3
+ "version": "0.36.2",
4
4
  "license": "MIT",
5
5
  "description": "Mushi Mushi CLI: SDK setup, MCP wiring, triage. Bug fixing for AI-built apps: plain-English diagnosis + a ready fix, in your editor.",
6
6
  "bin": {
@@ -1,8 +0,0 @@
1
- // src/version.ts
2
- var MUSHI_CLI_VERSION = true ? "0.36.0" : "0.0.0-dev";
3
- var MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.5";
4
-
5
- export {
6
- MUSHI_CLI_VERSION,
7
- MUSHI_MCP_PIN_SPEC
8
- };
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/version.ts
4
- var MUSHI_CLI_VERSION = true ? "0.36.0" : "0.0.0-dev";
5
- var MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.5";
6
-
7
- export {
8
- MUSHI_CLI_VERSION,
9
- MUSHI_MCP_PIN_SPEC
10
- };