@mushi-mushi/cli 0.35.0 → 0.35.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 +12 -7
- package/dist/{chunk-T36WTCFM.js → chunk-DBXL4RLE.js} +1 -1
- package/dist/chunk-OWUJYMV6.js +10 -0
- package/dist/{chunk-RQEWLXGY.js → chunk-VAQTC77F.js} +3 -3
- package/dist/chunk-VNGG2M3O.js +8 -0
- package/dist/{chunk-DSYPYBJT.js → chunk-XUPFPVB2.js} +2 -2
- package/dist/{chunk-BC3Y5C3L.js → chunk-ZA2HNXTH.js} +1 -1
- package/dist/{connect-DCXEXEIG.js → connect-SH7D5RJP.js} +3 -3
- package/dist/{connect-TBE7M2G5.js → connect-YC6MRVZN.js} +2 -2
- package/dist/{daemon-LG3VI5EK.js → daemon-STJJNPRM.js} +3 -3
- package/dist/index.js +70 -15
- package/dist/init.js +48 -5
- package/dist/{version-XGDCADFX.js → version-6ZDAJV77.js} +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-GNTEONTU.js +0 -10
- package/dist/chunk-HXLBH5GE.js +0 -8
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @mushi-mushi/cli
|
|
2
2
|
|
|
3
|
-
> **Your AI wrote it. Mushi tells you why it broke.**
|
|
3
|
+
> **Your AI wrote it. Mushi Mushi tells you why it broke.**
|
|
4
4
|
|
|
5
5
|
The `mushi` command for [Mushi Mushi](https://github.com/kensaurus/mushi-mushi). Install the SDK in your app, connect your editor, then read bugs, dispatch fixes and merge them without leaving the terminal.
|
|
6
6
|
|
|
@@ -29,11 +29,13 @@ For your editor, `mushi setup` writes the hosted MCP entry by default: the edito
|
|
|
29
29
|
|
|
30
30
|
| Group | Commands |
|
|
31
31
|
| --- | --- |
|
|
32
|
-
| Set up | `init`, `login`, `setup`, `connect`, `doctor`, `upgrade`, `nudge`, `completion` |
|
|
33
|
-
| Bugs | `reports list/show/search/triage`, `lessons list/show` |
|
|
32
|
+
| Set up | `init`, `login`, `setup`, `connect`, `doctor`, `test` (send a test report), `upgrade`, `nudge`, `completion`, `profile` |
|
|
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
|
-
|
|
|
36
|
-
|
|
|
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) |
|
|
36
|
+
| Ship | `sourcemaps upload`, `deploy check`, `migrate`, `audit`, `releases` |
|
|
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
|
+
| CI | `runner status/compare/bill`: where your tests run, what they cost, and whether a red check was your code or the machine |
|
|
37
39
|
| Account | `whoami`, `status`, `usage`, `billing`, `keys`, `integrations`, `slack` |
|
|
38
40
|
|
|
39
41
|
`mushi --help` and `mushi <command> --help` list every command and flag.
|
|
@@ -43,7 +45,7 @@ For your editor, `mushi setup` writes the hosted MCP entry by default: the edito
|
|
|
43
45
|
```bash
|
|
44
46
|
mushi doctor --fix # check SDK, ingest and dispatch; fix what's safe locally
|
|
45
47
|
mushi reports list --status new --severity critical # what broke
|
|
46
|
-
mushi fix <reportId> --wait # an agent opens a draft PR for it
|
|
48
|
+
mushi fix <reportId> --wait # an agent opens a draft PR for it (your own AI key)
|
|
47
49
|
mushi fixes merge <fixId> # merge it and mark the report Fixed
|
|
48
50
|
mushi upgrade # bump @mushi-mushi/* to the latest stable
|
|
49
51
|
mushi upgrade --check # CI: exit 0 current, 1 outdated, 2 registry down
|
|
@@ -58,7 +60,9 @@ mushi init --yes --project-id <uuid> --api-key mushi_xxx --skip-test-report
|
|
|
58
60
|
MUSHI_API_KEY=mushi_xxx mushi connect --project-id <uuid> --endpoint <url> --wait # wire a repo, wait for the first SDK heartbeat
|
|
59
61
|
```
|
|
60
62
|
|
|
61
|
-
Other `init` flags: `--framework next`, `--cwd apps/web` (monorepos), `--endpoint <url>` (self-hosted), `--skip-install
|
|
63
|
+
Other `init` flags: `--framework next`, `--cwd apps/web` (monorepos), `--endpoint <url>` (self-hosted), `--skip-install`, `--audit` (check an existing install instead).
|
|
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.
|
|
62
66
|
|
|
63
67
|
## Environment variables
|
|
64
68
|
|
|
@@ -68,6 +72,7 @@ Other `init` flags: `--framework next`, `--cwd apps/web` (monorepos), `--endpoin
|
|
|
68
72
|
| `MUSHI_PROJECT_ID` | Project UUID |
|
|
69
73
|
| `MUSHI_API_ENDPOINT` | API base URL (defaults to Mushi Cloud) |
|
|
70
74
|
| `MUSHI_CONSOLE_URL` | Console base for links and browser opens |
|
|
75
|
+
| `MUSHI_PROFILE` | Named credential profile to use (same as `--profile`) |
|
|
71
76
|
| `MUSHI_BYOK_KEY` | Key for `mushi keys add`, kept out of shell history |
|
|
72
77
|
| `MUSHI_NO_UPDATE_CHECK=1` | Skip the "newer version" hint |
|
|
73
78
|
| `MUSHI_DEBUG=1` | Full stack traces on error |
|
|
@@ -8,10 +8,10 @@ import {
|
|
|
8
8
|
requireConfig,
|
|
9
9
|
requireUuid,
|
|
10
10
|
tryLoadWorkerKey
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DBXL4RLE.js";
|
|
12
12
|
import {
|
|
13
13
|
MUSHI_CLI_VERSION
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-OWUJYMV6.js";
|
|
15
15
|
|
|
16
16
|
// src/worker/daemon.ts
|
|
17
17
|
import { existsSync as existsSync6, readFileSync as readFileSync5 } from "fs";
|
|
@@ -983,7 +983,7 @@ function registerWorkCommands(program) {
|
|
|
983
983
|
if (opts.repoDir || opts.report || opts.followups) {
|
|
984
984
|
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");
|
|
985
985
|
}
|
|
986
|
-
const { runDaemon: runDaemon2 } = await import("./daemon-
|
|
986
|
+
const { runDaemon: runDaemon2 } = await import("./daemon-STJJNPRM.js");
|
|
987
987
|
await runDaemon2({ configPath: opts.workerConfig });
|
|
988
988
|
return;
|
|
989
989
|
}
|
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
requireUuid,
|
|
10
10
|
saveConfig,
|
|
11
11
|
savedSdkKeyFor
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DBXL4RLE.js";
|
|
13
13
|
import {
|
|
14
14
|
MUSHI_MCP_PIN_SPEC
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-OWUJYMV6.js";
|
|
16
16
|
import {
|
|
17
17
|
assertEndpoint,
|
|
18
18
|
normalizeEndpoint
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import {
|
|
3
3
|
resolveSdkEnvKey,
|
|
4
4
|
runConnect
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XUPFPVB2.js";
|
|
6
6
|
import "./chunk-KOBEOGNF.js";
|
|
7
|
-
import "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-DBXL4RLE.js";
|
|
8
|
+
import "./chunk-OWUJYMV6.js";
|
|
9
9
|
import "./chunk-LGGE3LH7.js";
|
|
10
10
|
export {
|
|
11
11
|
resolveSdkEnvKey,
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
saveConfig,
|
|
7
7
|
savedSdkKeyFor,
|
|
8
8
|
waitForIngestReady
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-ZA2HNXTH.js";
|
|
10
10
|
import {
|
|
11
11
|
MUSHI_MCP_PIN_SPEC
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-VNGG2M3O.js";
|
|
13
13
|
import {
|
|
14
14
|
detectFramework,
|
|
15
15
|
envVarsToWrite,
|
|
@@ -7,9 +7,9 @@ import {
|
|
|
7
7
|
readWorkerKey,
|
|
8
8
|
runDaemon,
|
|
9
9
|
workerHostId
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-VAQTC77F.js";
|
|
11
|
+
import "./chunk-DBXL4RLE.js";
|
|
12
|
+
import "./chunk-OWUJYMV6.js";
|
|
13
13
|
import "./chunk-LGGE3LH7.js";
|
|
14
14
|
export {
|
|
15
15
|
assertWorkerKey,
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
sanitizeEndpoint,
|
|
23
23
|
sanitizeProjectId,
|
|
24
24
|
writeMcpServerEntry
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-XUPFPVB2.js";
|
|
26
26
|
import {
|
|
27
27
|
FRAMEWORKS,
|
|
28
28
|
detectFramework,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
registerUxCommands,
|
|
50
50
|
registerWorkCommands,
|
|
51
51
|
validateWorkerConfig
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-VAQTC77F.js";
|
|
53
53
|
import {
|
|
54
54
|
CONFIG_PATH,
|
|
55
55
|
MushiCliError,
|
|
@@ -87,11 +87,11 @@ import {
|
|
|
87
87
|
tryDeleteWorkerKey,
|
|
88
88
|
trySaveKeyToKeychain,
|
|
89
89
|
trySaveWorkerKey
|
|
90
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-DBXL4RLE.js";
|
|
91
91
|
import {
|
|
92
92
|
MUSHI_CLI_VERSION,
|
|
93
93
|
MUSHI_MCP_PIN_SPEC
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-OWUJYMV6.js";
|
|
95
95
|
import {
|
|
96
96
|
CLOUD_API_ENDPOINT,
|
|
97
97
|
CLOUD_MCP_OAUTH_URL,
|
|
@@ -1594,7 +1594,7 @@ async function checkOnboardingStatus(config, _consoleBase, cwd, doFetch = global
|
|
|
1594
1594
|
}
|
|
1595
1595
|
async function checkVersionDrift(cwd, doFetch) {
|
|
1596
1596
|
const checks = [];
|
|
1597
|
-
const { MUSHI_CLI_VERSION: MUSHI_CLI_VERSION2 } = await import("./version-
|
|
1597
|
+
const { MUSHI_CLI_VERSION: MUSHI_CLI_VERSION2 } = await import("./version-6ZDAJV77.js");
|
|
1598
1598
|
if (MUSHI_CLI_VERSION2 === "0.0.0-dev") return checks;
|
|
1599
1599
|
const parse2 = (v) => {
|
|
1600
1600
|
const m = v.replace(/^[~^]/, "").match(/^(\d+)\.(\d+)\.(\d+)/);
|
|
@@ -1686,6 +1686,46 @@ async function checkPipelineDoctor(config, doFetch) {
|
|
|
1686
1686
|
}];
|
|
1687
1687
|
}
|
|
1688
1688
|
}
|
|
1689
|
+
var HEARTBEAT_ROWS = /* @__PURE__ */ new Set(["never_seen", "sdk_stale"]);
|
|
1690
|
+
async function checkHealthRegistry(config, doFetch) {
|
|
1691
|
+
if (!config.endpoint || !config.apiKey || !config.projectId) return [];
|
|
1692
|
+
let creds;
|
|
1693
|
+
try {
|
|
1694
|
+
creds = sanitizeCliCredentials(config);
|
|
1695
|
+
} catch {
|
|
1696
|
+
return [];
|
|
1697
|
+
}
|
|
1698
|
+
try {
|
|
1699
|
+
const { endpoint, apiKey, projectId: projectId2 } = creds;
|
|
1700
|
+
const res = await doFetch(`${endpoint}/v1/admin/health-checks?projectId=${encodeURIComponent(projectId2)}`, {
|
|
1701
|
+
headers: apiKeyHeaders(apiKey, projectId2),
|
|
1702
|
+
signal: AbortSignal.timeout(3e4)
|
|
1703
|
+
});
|
|
1704
|
+
if (res.status === 401 || res.status === 403 || res.status === 404) return [];
|
|
1705
|
+
if (!res.ok) {
|
|
1706
|
+
return [{ name: "[health] Health check", ok: true, warn: true, detail: `GET /v1/admin/health-checks returned HTTP ${res.status}; health unknown.` }];
|
|
1707
|
+
}
|
|
1708
|
+
const body = await res.json();
|
|
1709
|
+
const rows = (body.data?.projects?.[0]?.checks ?? []).filter((r) => r.source !== "doctor" && !HEARTBEAT_ROWS.has(r.id));
|
|
1710
|
+
const out = [];
|
|
1711
|
+
for (const r of rows) {
|
|
1712
|
+
if (r.status === "ok") continue;
|
|
1713
|
+
const waiting = r.affects && r.affects > 0 ? ` ${r.affects} waiting on this.` : "";
|
|
1714
|
+
const fix = r.fix ? ` \u2192 Fix: ${r.fix.label}${r.fix.to ? ` (console ${r.fix.to})` : ""}${r.fix.steps?.length ? `: ${r.fix.steps.join(" ")}` : ""}` : "";
|
|
1715
|
+
out.push({
|
|
1716
|
+
name: `[health] ${r.title}`,
|
|
1717
|
+
ok: true,
|
|
1718
|
+
warn: true,
|
|
1719
|
+
detail: r.status === "unknown" ? `Not checked: ${r.detail}` : `${r.detail}${waiting}${fix}`
|
|
1720
|
+
});
|
|
1721
|
+
}
|
|
1722
|
+
const passing = rows.filter((r) => r.status === "ok").length;
|
|
1723
|
+
if (passing > 0) out.push({ name: "[health] Other checks", ok: true, detail: `${passing} passed.` });
|
|
1724
|
+
return out;
|
|
1725
|
+
} catch {
|
|
1726
|
+
return [{ name: "[health] Health check", ok: true, warn: true, detail: "Could not reach /v1/admin/health-checks (timeout); health unknown." }];
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1689
1729
|
async function runDoctor(config, options = {}) {
|
|
1690
1730
|
const doFetch = options.fetch ?? globalThis.fetch;
|
|
1691
1731
|
const checks = [];
|
|
@@ -1726,6 +1766,7 @@ async function runDoctor(config, options = {}) {
|
|
|
1726
1766
|
const serverChecks = await checkServerPreflight(config, doFetch);
|
|
1727
1767
|
checks.push(...serverChecks);
|
|
1728
1768
|
checks.push(...await checkPipelineDoctor(config, doFetch));
|
|
1769
|
+
checks.push(...await checkHealthRegistry(config, doFetch));
|
|
1729
1770
|
}
|
|
1730
1771
|
checks.push(...await checkVersionDrift(options.cwd ?? process.cwd(), doFetch));
|
|
1731
1772
|
if (runIngest) {
|
|
@@ -2512,7 +2553,7 @@ import { MushiRewardsBadge } from '@mushi-mushi/react';
|
|
|
2512
2553
|
" [ ] 1. Paste the init snippet above into your app entry file",
|
|
2513
2554
|
" [ ] 2. Start your dev server",
|
|
2514
2555
|
" [ ] 3. Wire your editor: npx mushi-mushi setup --ide cursor (or --ide claude)",
|
|
2515
|
-
` [ ] 4. Open the
|
|
2556
|
+
` [ ] 4. Open the Test it tab to send a test report: ${consoleUrl(consoleBase, "/onboarding?tab=verify")}`
|
|
2516
2557
|
].join("\n"),
|
|
2517
2558
|
"Next steps:"
|
|
2518
2559
|
);
|
|
@@ -2526,7 +2567,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
2526
2567
|
if (p.isCancel(answer) || !answer) return;
|
|
2527
2568
|
const endpoint = resolveCloudEndpoint(options.endpoint);
|
|
2528
2569
|
try {
|
|
2529
|
-
const { runConnect: runConnect2 } = await import("./connect-
|
|
2570
|
+
const { runConnect: runConnect2 } = await import("./connect-SH7D5RJP.js");
|
|
2530
2571
|
const saved = loadConfig();
|
|
2531
2572
|
const result = await runConnect2(
|
|
2532
2573
|
{
|
|
@@ -2544,7 +2585,9 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
2544
2585
|
for (const line of result.messages) p.log.message(line);
|
|
2545
2586
|
} catch (err) {
|
|
2546
2587
|
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
2547
|
-
p.log.info(
|
|
2588
|
+
p.log.info(
|
|
2589
|
+
`You can run it yourself: npx mushi-mushi connect --project-id ${credentials.projectId} --endpoint ${endpoint} --write-env --wire-ide --wait`
|
|
2590
|
+
);
|
|
2548
2591
|
}
|
|
2549
2592
|
}
|
|
2550
2593
|
async function maybeEnableRewards(options) {
|
|
@@ -5318,7 +5361,7 @@ Examples:
|
|
|
5318
5361
|
|
|
5319
5362
|
// src/commands/connect-cli.ts
|
|
5320
5363
|
function registerConnectCommand(program2) {
|
|
5321
|
-
program2.command("connect").description("Save credentials, merge env vars, wire Cursor MCP, optionally wait for SDK heartbeat").option("--api-key <key>", "Mushi API key (mushi_\u2026) saved to the CLI config \u2014 or set MUSHI_API_KEY to keep it out of shell history").option(
|
|
5364
|
+
program2.command("connect").description("Save credentials, merge env vars, wire Cursor MCP, optionally wait for SDK heartbeat").option("--api-key <key>", "Mushi API key (mushi_\u2026) saved to the CLI config \u2014 or set MUSHI_API_KEY to keep it out of shell history. Default: the key `npx mushi-mushi` or `mushi login` saved").option(
|
|
5322
5365
|
"--sdk-key <key>",
|
|
5323
5366
|
"Ingest-only (report:write) key for the SDK env vars \u2014 or set MUSHI_SDK_KEY. Default: the key saved for this project, else --api-key if it is ingest-only"
|
|
5324
5367
|
).requiredOption("--project-id <id>", "Project UUID").requiredOption("--endpoint <url>", "Supabase edge function URL").option("--cwd <path>", "Target repo").option("--write-env", "Force-write SDK env vars to .env.local (default; overrides --no-env)").option("--wire-ide", "Force-wire Cursor MCP into .cursor/mcp.json (default; overrides --no-ide)").option("--no-env", "Skip writing .env.local").option("--no-ide", "Skip writing .cursor/mcp.json").option("--wait", "Poll ingest-setup until SDK heartbeat lands").option("--wait-timeout <sec>", "Max seconds for --wait", "120").option("--json", "Machine-readable output").addHelpText("after", `
|
|
@@ -5330,9 +5373,10 @@ Examples:
|
|
|
5330
5373
|
SDK env vars (VITE_ / NEXT_PUBLIC_ / EXPO_PUBLIC_ \u2026) ship inside your app bundle,
|
|
5331
5374
|
so connect only writes a key the backend confirms is ingest-only (report:write).
|
|
5332
5375
|
A key that can read reports is refused for .env.local; it still works for the CLI and MCP.`).action(async (opts) => {
|
|
5333
|
-
const
|
|
5376
|
+
const saved = loadConfig();
|
|
5377
|
+
const apiKey = process.env.MUSHI_API_KEY ?? opts.apiKey ?? saved.apiKey;
|
|
5334
5378
|
if (!apiKey) {
|
|
5335
|
-
console.error("
|
|
5379
|
+
console.error("No API key found. Run `npx mushi-mushi` or `mushi login` first, or set MUSHI_API_KEY (recommended) or pass --api-key <key>.");
|
|
5336
5380
|
process.exit(1);
|
|
5337
5381
|
}
|
|
5338
5382
|
const result = await runConnect({
|
|
@@ -5346,7 +5390,7 @@ A key that can read reports is refused for .env.local; it still works for the CL
|
|
|
5346
5390
|
wait: opts.wait,
|
|
5347
5391
|
waitTimeoutSec: parseInt(opts.waitTimeout, 10) || 120,
|
|
5348
5392
|
json: opts.json
|
|
5349
|
-
},
|
|
5393
|
+
}, saved);
|
|
5350
5394
|
if (opts.json) {
|
|
5351
5395
|
console.log(JSON.stringify(result, null, 2));
|
|
5352
5396
|
} else {
|
|
@@ -12772,12 +12816,23 @@ Uploaded ${p5.rows} day \xD7 repo \xD7 SKU rows for ${p5.month}. The console's C
|
|
|
12772
12816
|
});
|
|
12773
12817
|
const placement = runner.command("placement").description("Where each repo's CI runs, and changing it through one runner variable with approval (ADR 0037)");
|
|
12774
12818
|
const placementBody = (opts, config) => {
|
|
12775
|
-
if (!opts.remove && !opts.value) throw new MushiCliError("E_INVALID_INPUT", "Pass --value <runner label>, or --remove to delete the variable.");
|
|
12819
|
+
if (!opts.remove && !opts.value) throw new MushiCliError("E_INVALID_INPUT", "Pass --value <runner label | economy | thorough>, or --remove to delete the variable.");
|
|
12776
12820
|
if (opts.remove && opts.value) throw new MushiCliError("E_INVALID_INPUT", "Pass either --value or --remove, not both.");
|
|
12777
12821
|
if (!/^[A-Za-z0-9._-]+\/[A-Za-z0-9._-]+$/.test(opts.repo)) throw new MushiCliError("E_INVALID_INPUT", "--repo must be owner/repo.");
|
|
12778
12822
|
const raw = opts.projectId ?? opts.project ?? config.projectId;
|
|
12779
12823
|
if (!raw) throw new MushiCliError("E_INVALID_INPUT", "Pass --project-id (or configure a project).");
|
|
12780
|
-
|
|
12824
|
+
let revertAfterHours;
|
|
12825
|
+
if (opts.revertAfter !== void 0) {
|
|
12826
|
+
revertAfterHours = Number(opts.revertAfter);
|
|
12827
|
+
if (!Number.isInteger(revertAfterHours) || revertAfterHours < 1 || revertAfterHours > 168) throw new MushiCliError("E_INVALID_INPUT", "--revert-after is a whole number of hours from 1 to 168.");
|
|
12828
|
+
}
|
|
12829
|
+
return {
|
|
12830
|
+
projectId: requireUuid(raw, "project id"),
|
|
12831
|
+
repo: opts.repo,
|
|
12832
|
+
variable: opts.variable,
|
|
12833
|
+
value: opts.remove ? null : opts.value,
|
|
12834
|
+
...revertAfterHours !== void 0 ? { revertAfterHours } : {}
|
|
12835
|
+
};
|
|
12781
12836
|
};
|
|
12782
12837
|
placement.command("show").description("Each repo: the runner variables its workflows read and their values, the CI agreement, runner labels, pending requests").option("--project-id <id>", "Project ID (defaults to the configured project)").option("--project <id>", "Same as --project-id").option("--json", "Machine-readable JSON output").action(async (opts) => {
|
|
12783
12838
|
const config = requireConfig();
|
|
@@ -12810,7 +12865,7 @@ Uploaded ${p5.rows} day \xD7 repo \xD7 SKU rows for ${p5.month}. The console's C
|
|
|
12810
12865
|
console.log(`
|
|
12811
12866
|
Requested ${r.id} (${r.status}). ${r.next ?? "An owner or admin approves and runs it in the console."}`);
|
|
12812
12867
|
};
|
|
12813
|
-
const changeOptions = (cmd) => cmd.requiredOption("--repo <owner/repo>", "Repository connected to the project").option("--variable <name>", "LINUX_RUNNER
|
|
12868
|
+
const changeOptions = (cmd) => cmd.requiredOption("--repo <owner/repo>", "Repository connected to the project").option("--variable <name>", "LINUX_RUNNER, RUNNER_<WORKFLOW>, or CI_PROFILE (where a workflow reads it)", "LINUX_RUNNER").option("--value <label>", "The runner label jobs should ask for (CI_PROFILE: economy or thorough)").option("--revert-after <hours>", "A move to GitHub-hosted runners switches back after this many hours (1-168)").option("--remove", "Remove the variable (jobs use the workflow's fallback, usually GitHub-hosted)").option("--project-id <id>", "Project ID (defaults to the configured project)").option("--project <id>", "Same as --project-id").option("--json", "Machine-readable JSON output");
|
|
12814
12869
|
changeOptions(
|
|
12815
12870
|
placement.command("preview").description("Dry run: what would move, what stays and why, the target runners, cost, the CI agreement's verdict. Changes nothing")
|
|
12816
12871
|
).action(placementAction("preview"));
|
package/dist/init.js
CHANGED
|
@@ -25,10 +25,10 @@ import {
|
|
|
25
25
|
saveConfig,
|
|
26
26
|
savedSdkKeyFor,
|
|
27
27
|
trySaveKeyToKeychain
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-ZA2HNXTH.js";
|
|
29
29
|
import {
|
|
30
30
|
MUSHI_CLI_VERSION
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-VNGG2M3O.js";
|
|
32
32
|
import {
|
|
33
33
|
FRAMEWORKS,
|
|
34
34
|
detectFramework,
|
|
@@ -1246,6 +1246,46 @@ async function checkPipelineDoctor(config, doFetch) {
|
|
|
1246
1246
|
}];
|
|
1247
1247
|
}
|
|
1248
1248
|
}
|
|
1249
|
+
var HEARTBEAT_ROWS = /* @__PURE__ */ new Set(["never_seen", "sdk_stale"]);
|
|
1250
|
+
async function checkHealthRegistry(config, doFetch) {
|
|
1251
|
+
if (!config.endpoint || !config.apiKey || !config.projectId) return [];
|
|
1252
|
+
let creds;
|
|
1253
|
+
try {
|
|
1254
|
+
creds = sanitizeCliCredentials(config);
|
|
1255
|
+
} catch {
|
|
1256
|
+
return [];
|
|
1257
|
+
}
|
|
1258
|
+
try {
|
|
1259
|
+
const { endpoint, apiKey, projectId } = creds;
|
|
1260
|
+
const res = await doFetch(`${endpoint}/v1/admin/health-checks?projectId=${encodeURIComponent(projectId)}`, {
|
|
1261
|
+
headers: apiKeyHeaders(apiKey, projectId),
|
|
1262
|
+
signal: AbortSignal.timeout(3e4)
|
|
1263
|
+
});
|
|
1264
|
+
if (res.status === 401 || res.status === 403 || res.status === 404) return [];
|
|
1265
|
+
if (!res.ok) {
|
|
1266
|
+
return [{ name: "[health] Health check", ok: true, warn: true, detail: `GET /v1/admin/health-checks returned HTTP ${res.status}; health unknown.` }];
|
|
1267
|
+
}
|
|
1268
|
+
const body = await res.json();
|
|
1269
|
+
const rows = (body.data?.projects?.[0]?.checks ?? []).filter((r) => r.source !== "doctor" && !HEARTBEAT_ROWS.has(r.id));
|
|
1270
|
+
const out = [];
|
|
1271
|
+
for (const r of rows) {
|
|
1272
|
+
if (r.status === "ok") continue;
|
|
1273
|
+
const waiting = r.affects && r.affects > 0 ? ` ${r.affects} waiting on this.` : "";
|
|
1274
|
+
const fix = r.fix ? ` \u2192 Fix: ${r.fix.label}${r.fix.to ? ` (console ${r.fix.to})` : ""}${r.fix.steps?.length ? `: ${r.fix.steps.join(" ")}` : ""}` : "";
|
|
1275
|
+
out.push({
|
|
1276
|
+
name: `[health] ${r.title}`,
|
|
1277
|
+
ok: true,
|
|
1278
|
+
warn: true,
|
|
1279
|
+
detail: r.status === "unknown" ? `Not checked: ${r.detail}` : `${r.detail}${waiting}${fix}`
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
const passing = rows.filter((r) => r.status === "ok").length;
|
|
1283
|
+
if (passing > 0) out.push({ name: "[health] Other checks", ok: true, detail: `${passing} passed.` });
|
|
1284
|
+
return out;
|
|
1285
|
+
} catch {
|
|
1286
|
+
return [{ name: "[health] Health check", ok: true, warn: true, detail: "Could not reach /v1/admin/health-checks (timeout); health unknown." }];
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1249
1289
|
async function runDoctor(config, options = {}) {
|
|
1250
1290
|
const doFetch = options.fetch ?? globalThis.fetch;
|
|
1251
1291
|
const checks = [];
|
|
@@ -1286,6 +1326,7 @@ async function runDoctor(config, options = {}) {
|
|
|
1286
1326
|
const serverChecks = await checkServerPreflight(config, doFetch);
|
|
1287
1327
|
checks.push(...serverChecks);
|
|
1288
1328
|
checks.push(...await checkPipelineDoctor(config, doFetch));
|
|
1329
|
+
checks.push(...await checkHealthRegistry(config, doFetch));
|
|
1289
1330
|
}
|
|
1290
1331
|
checks.push(...await checkVersionDrift(options.cwd ?? process.cwd(), doFetch));
|
|
1291
1332
|
if (runIngest) {
|
|
@@ -2072,7 +2113,7 @@ import { MushiRewardsBadge } from '@mushi-mushi/react';
|
|
|
2072
2113
|
" [ ] 1. Paste the init snippet above into your app entry file",
|
|
2073
2114
|
" [ ] 2. Start your dev server",
|
|
2074
2115
|
" [ ] 3. Wire your editor: npx mushi-mushi setup --ide cursor (or --ide claude)",
|
|
2075
|
-
` [ ] 4. Open the
|
|
2116
|
+
` [ ] 4. Open the Test it tab to send a test report: ${consoleUrl(consoleBase, "/onboarding?tab=verify")}`
|
|
2076
2117
|
].join("\n"),
|
|
2077
2118
|
"Next steps:"
|
|
2078
2119
|
);
|
|
@@ -2086,7 +2127,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
2086
2127
|
if (p.isCancel(answer) || !answer) return;
|
|
2087
2128
|
const endpoint = resolveCloudEndpoint(options.endpoint);
|
|
2088
2129
|
try {
|
|
2089
|
-
const { runConnect } = await import("./connect-
|
|
2130
|
+
const { runConnect } = await import("./connect-YC6MRVZN.js");
|
|
2090
2131
|
const saved = loadConfig();
|
|
2091
2132
|
const result = await runConnect(
|
|
2092
2133
|
{
|
|
@@ -2104,7 +2145,9 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
2104
2145
|
for (const line of result.messages) p.log.message(line);
|
|
2105
2146
|
} catch (err) {
|
|
2106
2147
|
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
2107
|
-
p.log.info(
|
|
2148
|
+
p.log.info(
|
|
2149
|
+
`You can run it yourself: npx mushi-mushi connect --project-id ${credentials.projectId} --endpoint ${endpoint} --write-env --wire-ide --wait`
|
|
2150
|
+
);
|
|
2108
2151
|
}
|
|
2109
2152
|
}
|
|
2110
2153
|
async function maybeEnableRewards(options) {
|
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.
|
|
17
|
+
declare const MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.2";
|
|
18
18
|
|
|
19
19
|
export { MUSHI_CLI_VERSION, MUSHI_MCP_PIN_SPEC };
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
package/dist/chunk-GNTEONTU.js
DELETED