@mushi-mushi/cli 0.34.1 → 0.35.1
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-2RCG7AHP.js +432 -0
- package/dist/{chunk-67WU4UYB.js → chunk-FBCX3OBT.js} +9 -3
- package/dist/chunk-Q4TOO3HX.js +8 -0
- package/dist/chunk-R3S4SF4A.js +2770 -0
- package/dist/{chunk-VBEYT4RS.js → chunk-VI5A6EDG.js} +172 -564
- package/dist/chunk-Z2AFR5AI.js +10 -0
- package/dist/{connect-354QHAUQ.js → connect-45YP7OGH.js} +2 -2
- package/dist/{connect-HZAHHWBI.js → connect-VTUZZHQB.js} +4 -3
- package/dist/daemon-5XONC35D.js +22 -0
- package/dist/index.js +1246 -1233
- package/dist/init.js +80 -9
- package/dist/{version-MD563FA6.js → version-ABB4VJEJ.js} +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-QI7DE6J3.js +0 -8
- package/dist/chunk-XXBGTUGX.js +0 -10
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-FBCX3OBT.js";
|
|
29
29
|
import {
|
|
30
30
|
MUSHI_CLI_VERSION
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-Q4TOO3HX.js";
|
|
32
32
|
import {
|
|
33
33
|
FRAMEWORKS,
|
|
34
34
|
detectFramework,
|
|
@@ -53,6 +53,26 @@ import { randomUUID } from "crypto";
|
|
|
53
53
|
import { appendFileSync, existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync } from "fs";
|
|
54
54
|
import { join as join2 } from "path";
|
|
55
55
|
|
|
56
|
+
// src/hosting-env-hint.ts
|
|
57
|
+
var LOVABLE_BOLT_DOCS = "https://kensaur.us/mushi-mushi/docs/quickstart/lovable-bolt";
|
|
58
|
+
function envVarNames(block) {
|
|
59
|
+
return block.split("\n").map((line) => /^([A-Z_][A-Z0-9_]*)=/.exec(line.trim())?.[1]).filter((name) => Boolean(name));
|
|
60
|
+
}
|
|
61
|
+
function hostingEnvHint(envBlock, envFile) {
|
|
62
|
+
const names = envVarNames(envBlock);
|
|
63
|
+
const first = names[0] ?? "MUSHI_PROJECT_ID";
|
|
64
|
+
const last = names[names.length - 1] ?? first;
|
|
65
|
+
return [
|
|
66
|
+
`Your deployed site needs these too. The values are in ${envFile}; copy them from there:`,
|
|
67
|
+
...names.map((n) => ` ${n}`),
|
|
68
|
+
"",
|
|
69
|
+
`Vercel: Project \u2192 Settings \u2192 Environment Variables, or \`vercel env add ${first} production\` (it asks for the value).`,
|
|
70
|
+
`Netlify: Project configuration \u2192 Environment variables, or \`netlify env:set ${last} "<value>"\`.`,
|
|
71
|
+
"Then redeploy: a NEXT_PUBLIC_ / VITE_ variable only reaches the site on the next build.",
|
|
72
|
+
`Lovable or Bolt: no variables needed; paste the script tag instead: ${LOVABLE_BOLT_DOCS}`
|
|
73
|
+
].join("\n");
|
|
74
|
+
}
|
|
75
|
+
|
|
56
76
|
// src/device-auth.ts
|
|
57
77
|
var DEVICE_FETCH_TIMEOUT_MS = 15e3;
|
|
58
78
|
var DEFAULT_SLOW_DOWN_MS = 5e3;
|
|
@@ -1226,6 +1246,46 @@ async function checkPipelineDoctor(config, doFetch) {
|
|
|
1226
1246
|
}];
|
|
1227
1247
|
}
|
|
1228
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
|
+
}
|
|
1229
1289
|
async function runDoctor(config, options = {}) {
|
|
1230
1290
|
const doFetch = options.fetch ?? globalThis.fetch;
|
|
1231
1291
|
const checks = [];
|
|
@@ -1266,6 +1326,7 @@ async function runDoctor(config, options = {}) {
|
|
|
1266
1326
|
const serverChecks = await checkServerPreflight(config, doFetch);
|
|
1267
1327
|
checks.push(...serverChecks);
|
|
1268
1328
|
checks.push(...await checkPipelineDoctor(config, doFetch));
|
|
1329
|
+
checks.push(...await checkHealthRegistry(config, doFetch));
|
|
1269
1330
|
}
|
|
1270
1331
|
checks.push(...await checkVersionDrift(options.cwd ?? process.cwd(), doFetch));
|
|
1271
1332
|
if (runIngest) {
|
|
@@ -1341,6 +1402,7 @@ ${failed.length} check${failed.length === 1 ? "" : "s"} failed.`);
|
|
|
1341
1402
|
}
|
|
1342
1403
|
|
|
1343
1404
|
// src/init.ts
|
|
1405
|
+
var NATIVE_FRAMEWORK_IDS = /* @__PURE__ */ new Set(["expo", "react-native", "capacitor"]);
|
|
1344
1406
|
var ENV_FILES = [".env.local", ".env"];
|
|
1345
1407
|
function isInteractive() {
|
|
1346
1408
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
@@ -1391,7 +1453,7 @@ async function runInit(options = {}) {
|
|
|
1391
1453
|
} else {
|
|
1392
1454
|
p.log.info(`Skipped install. Run \`${installCommand(pm, packagesToInstall)}\` yourself.`);
|
|
1393
1455
|
}
|
|
1394
|
-
await writeEnvFile(
|
|
1456
|
+
const envFile = await writeEnvFile(
|
|
1395
1457
|
cwd,
|
|
1396
1458
|
credentials.sdkKey,
|
|
1397
1459
|
credentials.projectId,
|
|
@@ -1399,6 +1461,12 @@ async function runInit(options = {}) {
|
|
|
1399
1461
|
endpoint,
|
|
1400
1462
|
Boolean(options.yes)
|
|
1401
1463
|
);
|
|
1464
|
+
if (!NATIVE_FRAMEWORK_IDS.has(framework.id)) {
|
|
1465
|
+
p.note(
|
|
1466
|
+
hostingEnvHint(envVarsToWrite(credentials.sdkKey, credentials.projectId, framework, endpoint), envFile),
|
|
1467
|
+
"Before you deploy:"
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1402
1470
|
persistCliConfig(credentials, endpoint);
|
|
1403
1471
|
emitWizardFunnelEvent(credentials, endpoint, "wizard_env_written", { framework: framework.id });
|
|
1404
1472
|
const enableRewards = await maybeEnableRewards(options);
|
|
@@ -1908,13 +1976,13 @@ async function writeEnvFile(cwd, apiKey, projectId, framework, endpoint, overwri
|
|
|
1908
1976
|
});
|
|
1909
1977
|
if (p.isCancel(answer)) {
|
|
1910
1978
|
p.log.info(`Kept existing env vars in ${target}.`);
|
|
1911
|
-
return;
|
|
1979
|
+
return target;
|
|
1912
1980
|
}
|
|
1913
1981
|
shouldOverwrite = Boolean(answer);
|
|
1914
1982
|
}
|
|
1915
1983
|
if (!shouldOverwrite) {
|
|
1916
1984
|
p.log.info(`Kept existing env vars in ${target}. Re-run and confirm to overwrite.`);
|
|
1917
|
-
return;
|
|
1985
|
+
return target;
|
|
1918
1986
|
}
|
|
1919
1987
|
const MUSHI_LINE_RE = /^(NEXT_PUBLIC_|NUXT_PUBLIC_|VITE_|EXPO_PUBLIC_)?MUSHI_[A-Z_]+=.*/gm;
|
|
1920
1988
|
const stripped = existing.replace(MUSHI_LINE_RE, "").replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
@@ -1925,7 +1993,7 @@ ${newVars}
|
|
|
1925
1993
|
`);
|
|
1926
1994
|
p.log.success(`Updated MUSHI_* env vars in ${target}`);
|
|
1927
1995
|
warnIfMissingFromGitignore(cwd, target);
|
|
1928
|
-
return;
|
|
1996
|
+
return target;
|
|
1929
1997
|
}
|
|
1930
1998
|
const prefix = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
|
|
1931
1999
|
appendFileSync(targetPath, `${prefix}
|
|
@@ -1934,6 +2002,7 @@ ${newVars}
|
|
|
1934
2002
|
`);
|
|
1935
2003
|
p.log.success(`Wrote env vars to ${target}`);
|
|
1936
2004
|
warnIfMissingFromGitignore(cwd, target);
|
|
2005
|
+
return target;
|
|
1937
2006
|
}
|
|
1938
2007
|
function isEnvFileCoveredByGitignore(gitignoreContent, envFile) {
|
|
1939
2008
|
const lines = gitignoreContent.split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#"));
|
|
@@ -2044,7 +2113,7 @@ import { MushiRewardsBadge } from '@mushi-mushi/react';
|
|
|
2044
2113
|
" [ ] 1. Paste the init snippet above into your app entry file",
|
|
2045
2114
|
" [ ] 2. Start your dev server",
|
|
2046
2115
|
" [ ] 3. Wire your editor: npx mushi-mushi setup --ide cursor (or --ide claude)",
|
|
2047
|
-
` [ ] 4. Open the
|
|
2116
|
+
` [ ] 4. Open the Test it tab to send a test report: ${consoleUrl(consoleBase, "/onboarding?tab=verify")}`
|
|
2048
2117
|
].join("\n"),
|
|
2049
2118
|
"Next steps:"
|
|
2050
2119
|
);
|
|
@@ -2058,7 +2127,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
2058
2127
|
if (p.isCancel(answer) || !answer) return;
|
|
2059
2128
|
const endpoint = resolveCloudEndpoint(options.endpoint);
|
|
2060
2129
|
try {
|
|
2061
|
-
const { runConnect } = await import("./connect-
|
|
2130
|
+
const { runConnect } = await import("./connect-45YP7OGH.js");
|
|
2062
2131
|
const saved = loadConfig();
|
|
2063
2132
|
const result = await runConnect(
|
|
2064
2133
|
{
|
|
@@ -2076,7 +2145,9 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
2076
2145
|
for (const line of result.messages) p.log.message(line);
|
|
2077
2146
|
} catch (err) {
|
|
2078
2147
|
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
2079
|
-
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
|
+
);
|
|
2080
2151
|
}
|
|
2081
2152
|
}
|
|
2082
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.
|
|
17
|
+
declare const MUSHI_MCP_PIN_SPEC = "@mushi-mushi/mcp@0.30.1";
|
|
18
18
|
|
|
19
19
|
export { MUSHI_CLI_VERSION, MUSHI_MCP_PIN_SPEC };
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
package/dist/chunk-QI7DE6J3.js
DELETED