@mushi-mushi/cli 0.27.1 → 0.28.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/README.md +6 -1
- package/dist/{chunk-M7CDSRZM.js → chunk-AV3RKAEE.js} +77 -47
- package/dist/{chunk-NNB2NONG.js → chunk-FJETUM25.js} +156 -497
- package/dist/chunk-KOBEOGNF.js +475 -0
- package/dist/chunk-SXSI2W6Z.js +42 -0
- package/dist/chunk-U2VGB63C.js +8 -0
- package/dist/chunk-UVO4A2G6.js +10 -0
- package/dist/connect-63GYZLFM.js +13 -0
- package/dist/{connect-5EQA7G3U.js → connect-C673EKS3.js} +74 -42
- package/dist/detect-4PYRZXVK.js +22 -0
- package/dist/endpoint-NHECZL47.js +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1202 -814
- package/dist/init.d.ts +179 -1
- package/dist/init.js +468 -225
- package/dist/{version-AYMUW3UQ.js → version-VR37VEE4.js} +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wizard-args.d.ts +2 -2
- package/dist/wizard-args.js +5 -3
- package/package.json +10 -15
- package/CODE_OF_CONDUCT.md +0 -51
- package/CONTRIBUTING.md +0 -226
- package/SECURITY.md +0 -359
- package/dist/chunk-DBAEB56N.js +0 -10
- package/dist/chunk-XLGHUOKY.js +0 -8
- package/dist/connect-TWO2ZNFB.js +0 -10
package/README.md
CHANGED
|
@@ -181,10 +181,15 @@ local bumps; use the PR flow when you want review + CI on the dependency change.
|
|
|
181
181
|
```bash
|
|
182
182
|
mushi upgrade # plan + install
|
|
183
183
|
mushi upgrade --dry-run # print the install command without running it
|
|
184
|
+
mushi upgrade --check # plan only: exit 0 current, 1 outdated, 2 registry down
|
|
184
185
|
mushi upgrade --json # machine-readable plan + result
|
|
185
186
|
mushi upgrade --cwd ../app # target another repo
|
|
186
187
|
```
|
|
187
188
|
|
|
189
|
+
`--check` never installs. Use it in a **non-required** CI job so a one-patch
|
|
190
|
+
drift cannot freeze production deploys. Exit `2` (registry unreachable) should
|
|
191
|
+
not fail a required gate — retry or treat as a warning.
|
|
192
|
+
|
|
188
193
|
Pre-release versions are never auto-selected, registry versions are validated
|
|
189
194
|
against strict semver before being interpolated into the install command, and
|
|
190
195
|
non-registry specifiers (`workspace:`, `file:`, git URLs, dist-tags) are left
|
|
@@ -440,4 +445,4 @@ The CLI is also importable for tooling (used by `create-mushi-mushi`):
|
|
|
440
445
|
MIT
|
|
441
446
|
|
|
442
447
|
<!-- mushi-readme-stats-footer -->
|
|
443
|
-
<sub>Monorepo scale (July 2026):
|
|
448
|
+
<sub>Monorepo scale (July 2026): 59 edge functions · 374 SQL migrations · 13 outbound plugins · 11 inbound adapters · 19 pipeline agents. Canonical counts: <a href="https://github.com/kensaurus/mushi-mushi/blob/master/docs/stats.md">docs/stats.md</a> · <code>pnpm docs-stats</code></sub>
|
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
MUSHI_CLI_VERSION
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-U2VGB63C.js";
|
|
4
|
+
import {
|
|
5
|
+
assertEndpoint,
|
|
6
|
+
normalizeEndpoint
|
|
7
|
+
} from "./chunk-SXSI2W6Z.js";
|
|
4
8
|
import {
|
|
5
9
|
__require
|
|
6
10
|
} from "./chunk-3RG5ZIWI.js";
|
|
7
11
|
|
|
8
|
-
// src/config.ts
|
|
9
|
-
import { randomUUID } from "crypto";
|
|
10
|
-
import { spawnSync } from "child_process";
|
|
11
|
-
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
12
|
-
import { homedir } from "os";
|
|
13
|
-
import { dirname, join } from "path";
|
|
14
|
-
|
|
15
12
|
// src/keychain.ts
|
|
16
13
|
var KEYCHAIN_SERVICE = "mushi-cli";
|
|
17
14
|
function accountName(profile = "default") {
|
|
@@ -29,6 +26,18 @@ function getEntryClass() {
|
|
|
29
26
|
}
|
|
30
27
|
return _EntryClass ?? null;
|
|
31
28
|
}
|
|
29
|
+
function trySaveKeyToKeychain(apiKey, profile = "default") {
|
|
30
|
+
if (!apiKey) return false;
|
|
31
|
+
const EntryClass = getEntryClass();
|
|
32
|
+
if (!EntryClass) return false;
|
|
33
|
+
try {
|
|
34
|
+
const entry = new EntryClass(KEYCHAIN_SERVICE, accountName(profile));
|
|
35
|
+
entry.setPassword(apiKey);
|
|
36
|
+
return true;
|
|
37
|
+
} catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
32
41
|
function tryLoadKeyFromKeychain(profile = "default") {
|
|
33
42
|
const EntryClass = getEntryClass();
|
|
34
43
|
if (!EntryClass) return null;
|
|
@@ -42,10 +51,20 @@ function tryLoadKeyFromKeychain(profile = "default") {
|
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
// src/config.ts
|
|
54
|
+
import { randomUUID } from "crypto";
|
|
55
|
+
import { spawnSync } from "child_process";
|
|
56
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
57
|
+
import { homedir } from "os";
|
|
58
|
+
import { dirname, join } from "path";
|
|
45
59
|
var DEFAULT_PROFILE = "default";
|
|
46
60
|
function isMultiProfileFile(value) {
|
|
47
61
|
return typeof value === "object" && value !== null && "profiles" in value && typeof value.profiles === "object" && value.profiles !== null;
|
|
48
62
|
}
|
|
63
|
+
function savedSdkKeyFor(config, projectId) {
|
|
64
|
+
const saved = config.sdkKey;
|
|
65
|
+
if (!projectId || !saved || typeof saved !== "object") return void 0;
|
|
66
|
+
return saved.projectId === projectId && typeof saved.key === "string" && saved.key ? saved.key : void 0;
|
|
67
|
+
}
|
|
49
68
|
function resolveProfileName(explicit, fileActive) {
|
|
50
69
|
const fromEnv = process.env["MUSHI_PROFILE"]?.trim();
|
|
51
70
|
return explicit?.trim() || fromEnv || fileActive || DEFAULT_PROFILE;
|
|
@@ -225,6 +244,47 @@ function tightenWindowsAcl(path, type) {
|
|
|
225
244
|
}
|
|
226
245
|
}
|
|
227
246
|
|
|
247
|
+
// src/key-scopes.ts
|
|
248
|
+
var SDK_KEY_SCOPES = ["report:write"];
|
|
249
|
+
var CLI_KEY_SCOPES = ["report:write", "mcp:read"];
|
|
250
|
+
var SDK_KEY_LABEL = "sdk-ingest";
|
|
251
|
+
var CLI_KEY_LABEL = "cli-login";
|
|
252
|
+
async function probeKeyScope(endpoint, apiKey, projectId, doFetch = globalThis.fetch) {
|
|
253
|
+
let base = endpoint;
|
|
254
|
+
while (base.endsWith("/")) base = base.slice(0, -1);
|
|
255
|
+
let res;
|
|
256
|
+
try {
|
|
257
|
+
res = await doFetch(`${base}/v1/admin/mcp/account-overview`, {
|
|
258
|
+
headers: { "X-Mushi-Api-Key": apiKey, "X-Mushi-Project": projectId },
|
|
259
|
+
signal: AbortSignal.timeout(8e3)
|
|
260
|
+
});
|
|
261
|
+
} catch (err) {
|
|
262
|
+
return { result: "unreachable", message: err instanceof Error ? err.message : String(err) };
|
|
263
|
+
}
|
|
264
|
+
if (res.ok) return { result: "mcp", status: res.status };
|
|
265
|
+
if (res.status === 401) return { result: "invalid", status: res.status };
|
|
266
|
+
if (res.status === 403) {
|
|
267
|
+
const body = await res.json().catch(() => null);
|
|
268
|
+
const code = body?.error?.code ?? body?.code;
|
|
269
|
+
if (code === "INSUFFICIENT_SCOPE") return { result: "ingest-only", status: res.status };
|
|
270
|
+
}
|
|
271
|
+
return { result: "unknown", status: res.status };
|
|
272
|
+
}
|
|
273
|
+
function describeUnsafeSdkKey(probe, endpoint) {
|
|
274
|
+
switch (probe.result) {
|
|
275
|
+
case "mcp":
|
|
276
|
+
return "this key can read your bug reports (mcp scope), and SDK env vars ship inside the app bundle";
|
|
277
|
+
case "invalid":
|
|
278
|
+
return "the backend rejected this key";
|
|
279
|
+
case "unreachable":
|
|
280
|
+
return `could not reach ${endpoint} to confirm the key is ingest-only (${probe.message ?? "network error"})`;
|
|
281
|
+
case "unknown":
|
|
282
|
+
return `could not confirm the key is ingest-only (HTTP ${probe.status ?? "?"})`;
|
|
283
|
+
case "ingest-only":
|
|
284
|
+
return "the key is ingest-only";
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
228
288
|
// src/console-url.ts
|
|
229
289
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
230
290
|
import { dirname as dirname2, join as join2 } from "path";
|
|
@@ -341,41 +401,6 @@ async function openInBrowser(url) {
|
|
|
341
401
|
});
|
|
342
402
|
}
|
|
343
403
|
|
|
344
|
-
// src/endpoint.ts
|
|
345
|
-
var TEST_REPORT_TIMEOUT_MS = 1e4;
|
|
346
|
-
var TEST_REPORT_FETCH_TIMEOUT_MS = TEST_REPORT_TIMEOUT_MS;
|
|
347
|
-
var CLOUD_API_ENDPOINT = "https://dxptnwrhwsqckaftyymj.supabase.co/functions/v1/api";
|
|
348
|
-
function resolveCloudEndpoint(explicit) {
|
|
349
|
-
if (explicit?.trim()) return explicit.trim();
|
|
350
|
-
const fromEnv = process.env.MUSHI_API_ENDPOINT?.trim();
|
|
351
|
-
if (fromEnv) return fromEnv;
|
|
352
|
-
return CLOUD_API_ENDPOINT;
|
|
353
|
-
}
|
|
354
|
-
function assertEndpoint(url) {
|
|
355
|
-
let parsed;
|
|
356
|
-
try {
|
|
357
|
-
parsed = new URL(url);
|
|
358
|
-
} catch {
|
|
359
|
-
throw new Error(`Invalid endpoint URL: ${url}`);
|
|
360
|
-
}
|
|
361
|
-
const host = parsed.hostname;
|
|
362
|
-
const isLocal = host === "localhost" || host === "127.0.0.1" || host === "::1" || host.endsWith(".local");
|
|
363
|
-
if (parsed.protocol !== "https:" && !isLocal) {
|
|
364
|
-
throw new Error(`Endpoint must use https:// (got ${parsed.protocol}//${host}).`);
|
|
365
|
-
}
|
|
366
|
-
return normalizeEndpoint(parsed.origin + parsed.pathname);
|
|
367
|
-
}
|
|
368
|
-
function normalizeEndpoint(url) {
|
|
369
|
-
if (!url) {
|
|
370
|
-
throw new Error(
|
|
371
|
-
"No API endpoint configured. Run `mushi init` or set MUSHI_API_ENDPOINT. Set endpoint to your Supabase edge function URL, e.g. https://xyz.supabase.co/functions/v1/api"
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
let end = url.length;
|
|
375
|
-
while (end > 0 && url.charCodeAt(end - 1) === 47) end--;
|
|
376
|
-
return url.slice(0, end);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
404
|
// src/errors.ts
|
|
380
405
|
var EXIT_CODE_MAP = {
|
|
381
406
|
E_AUTH_MISSING: 2,
|
|
@@ -644,11 +669,20 @@ async function waitForIngestReady(options) {
|
|
|
644
669
|
}
|
|
645
670
|
|
|
646
671
|
export {
|
|
672
|
+
trySaveKeyToKeychain,
|
|
673
|
+
savedSdkKeyFor,
|
|
674
|
+
resolveProfileName,
|
|
647
675
|
CONFIG_PATH,
|
|
648
676
|
loadConfig,
|
|
649
677
|
ensureClientId,
|
|
650
678
|
maybeShowTelemetryNotice,
|
|
651
679
|
saveConfig,
|
|
680
|
+
SDK_KEY_SCOPES,
|
|
681
|
+
CLI_KEY_SCOPES,
|
|
682
|
+
SDK_KEY_LABEL,
|
|
683
|
+
CLI_KEY_LABEL,
|
|
684
|
+
probeKeyScope,
|
|
685
|
+
describeUnsafeSdkKey,
|
|
652
686
|
consoleUrl,
|
|
653
687
|
resolveConsoleUrlSync,
|
|
654
688
|
resolveConsoleUrl,
|
|
@@ -657,10 +691,6 @@ export {
|
|
|
657
691
|
cliSetupDeepLink,
|
|
658
692
|
reportsUrl,
|
|
659
693
|
openInBrowser,
|
|
660
|
-
TEST_REPORT_FETCH_TIMEOUT_MS,
|
|
661
|
-
resolveCloudEndpoint,
|
|
662
|
-
assertEndpoint,
|
|
663
|
-
normalizeEndpoint,
|
|
664
694
|
requireUuid,
|
|
665
695
|
apiCall,
|
|
666
696
|
sanitizeEndpoint,
|