@mushi-mushi/cli 0.23.0 → 0.24.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 +26 -0
- package/dist/{chunk-GSQO35YD.js → chunk-BWASDQI6.js} +15 -1
- package/dist/{chunk-WLLFV26V.js → chunk-GUVGTFVK.js} +15 -1
- package/dist/chunk-X74T7JKC.js +6 -0
- package/dist/{connect-KX4UGY6Z.js → connect-7LTQRBEW.js} +2 -2
- package/dist/{connect-XFVSH4JZ.js → connect-KKN62YK2.js} +1 -1
- package/dist/index.js +492 -133
- package/dist/init.js +182 -60
- package/dist/version.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-BY5SZYRO.js +0 -6
package/dist/init.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
apiKeyHint,
|
|
5
5
|
cliSetupDeepLink,
|
|
6
6
|
consoleUrl,
|
|
7
|
+
ensureClientId,
|
|
7
8
|
loadConfig,
|
|
8
9
|
normalizeEndpoint,
|
|
9
10
|
openInBrowser,
|
|
@@ -13,7 +14,7 @@ import {
|
|
|
13
14
|
resolveConsoleUrl,
|
|
14
15
|
resolveConsoleUrlSync,
|
|
15
16
|
saveConfig
|
|
16
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-GUVGTFVK.js";
|
|
17
18
|
import {
|
|
18
19
|
FRAMEWORKS,
|
|
19
20
|
detectFramework,
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
} from "./chunk-AIZRI665.js";
|
|
25
26
|
import {
|
|
26
27
|
MUSHI_CLI_VERSION
|
|
27
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-X74T7JKC.js";
|
|
28
29
|
|
|
29
30
|
// src/init.ts
|
|
30
31
|
import * as p from "@clack/prompts";
|
|
@@ -35,6 +36,7 @@ import { join as join2 } from "path";
|
|
|
35
36
|
|
|
36
37
|
// src/device-auth.ts
|
|
37
38
|
var DEVICE_FETCH_TIMEOUT_MS = 15e3;
|
|
39
|
+
var DEFAULT_SLOW_DOWN_MS = 5e3;
|
|
38
40
|
function trimTrailingSlash(endpoint) {
|
|
39
41
|
let end = endpoint.length;
|
|
40
42
|
while (end > 0 && endpoint.charCodeAt(end - 1) === 47) end--;
|
|
@@ -49,15 +51,18 @@ async function deviceFetch(url, init = {}) {
|
|
|
49
51
|
clearTimeout(timer);
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
|
-
async function startDeviceAuth(endpoint) {
|
|
54
|
+
async function startDeviceAuth(endpoint, clientId) {
|
|
53
55
|
const base = trimTrailingSlash(endpoint);
|
|
54
56
|
const res = await deviceFetch(`${base}/v1/cli/auth/device/start`, {
|
|
55
57
|
method: "POST",
|
|
56
|
-
headers: { "Content-Type": "application/json" }
|
|
58
|
+
headers: { "Content-Type": "application/json" },
|
|
59
|
+
body: JSON.stringify(clientId ? { client_id: clientId } : {})
|
|
57
60
|
});
|
|
58
61
|
const json = await res.json().catch(() => null);
|
|
59
62
|
if (!res.ok || !json?.ok || !json.data) {
|
|
60
|
-
throw new Error(
|
|
63
|
+
throw new Error(
|
|
64
|
+
json?.error?.message ?? `Could not start browser sign-in (HTTP ${res.status}).`
|
|
65
|
+
);
|
|
61
66
|
}
|
|
62
67
|
return json.data;
|
|
63
68
|
}
|
|
@@ -76,6 +81,12 @@ async function pollDeviceToken(endpoint, deviceCode) {
|
|
|
76
81
|
switch (json.error) {
|
|
77
82
|
case "authorization_pending":
|
|
78
83
|
return { status: "pending" };
|
|
84
|
+
case "slow_down": {
|
|
85
|
+
const retryAfterHeader = res.headers?.get?.("Retry-After");
|
|
86
|
+
const retryAfterSeconds = retryAfterHeader ? Number(retryAfterHeader) : NaN;
|
|
87
|
+
const retryAfterMs = Number.isFinite(retryAfterSeconds) && retryAfterSeconds > 0 ? retryAfterSeconds * 1e3 : DEFAULT_SLOW_DOWN_MS;
|
|
88
|
+
return { status: "slow_down", retryAfterMs };
|
|
89
|
+
}
|
|
79
90
|
case "access_denied":
|
|
80
91
|
return { status: "denied" };
|
|
81
92
|
case "expired_token":
|
|
@@ -84,20 +95,27 @@ async function pollDeviceToken(endpoint, deviceCode) {
|
|
|
84
95
|
return {
|
|
85
96
|
status: "error",
|
|
86
97
|
message: json.error_description ?? json.error ?? `HTTP ${res.status}`,
|
|
87
|
-
// 5xx is a server hiccup the next poll may clear;
|
|
88
|
-
//
|
|
89
|
-
|
|
98
|
+
// 5xx is a server hiccup the next poll may clear; 408 (gateway
|
|
99
|
+
// timeout) is equally transient. Any other 4xx is a definitive
|
|
100
|
+
// rejection (already claimed / invalid_grant) that won't fix
|
|
101
|
+
// itself. (429/slow_down is handled above as its own outcome.)
|
|
102
|
+
retryable: res.status >= 500 || res.status === 408
|
|
90
103
|
};
|
|
91
104
|
}
|
|
92
105
|
} catch (err) {
|
|
93
|
-
return {
|
|
106
|
+
return {
|
|
107
|
+
status: "error",
|
|
108
|
+
message: err instanceof Error ? err.message : String(err),
|
|
109
|
+
retryable: true
|
|
110
|
+
};
|
|
94
111
|
}
|
|
95
112
|
}
|
|
96
113
|
var defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
114
|
+
var deviceAuthRetryDelayMs = 1e3;
|
|
97
115
|
async function waitForCliToken(endpoint, session, opts = {}) {
|
|
98
116
|
const sleep = opts.sleep ?? defaultSleep;
|
|
99
117
|
const now = opts.now ?? Date.now;
|
|
100
|
-
|
|
118
|
+
let intervalMs = (session.interval || 5) * 1e3;
|
|
101
119
|
const deadline = now() + (session.expires_in || 600) * 1e3;
|
|
102
120
|
const maxConsecutiveErrors = opts.maxConsecutiveErrors ?? 5;
|
|
103
121
|
let consecutiveErrors = 0;
|
|
@@ -115,6 +133,11 @@ async function waitForCliToken(endpoint, session, opts = {}) {
|
|
|
115
133
|
consecutiveErrors = 0;
|
|
116
134
|
opts.onPending?.();
|
|
117
135
|
continue;
|
|
136
|
+
case "slow_down":
|
|
137
|
+
consecutiveErrors = 0;
|
|
138
|
+
intervalMs = Math.max(intervalMs, outcome.retryAfterMs);
|
|
139
|
+
opts.onSlowDown?.(outcome.retryAfterMs);
|
|
140
|
+
continue;
|
|
118
141
|
case "denied":
|
|
119
142
|
throw new Error("Login was denied in the browser.");
|
|
120
143
|
case "expired":
|
|
@@ -139,19 +162,51 @@ function cliAuthHeaders(cliToken) {
|
|
|
139
162
|
Authorization: `Bearer ${cliToken}`
|
|
140
163
|
};
|
|
141
164
|
}
|
|
165
|
+
var DeviceAuthRequestError = class extends Error {
|
|
166
|
+
step;
|
|
167
|
+
status;
|
|
168
|
+
retryable;
|
|
169
|
+
constructor(step, message, status) {
|
|
170
|
+
super(message);
|
|
171
|
+
this.name = "DeviceAuthRequestError";
|
|
172
|
+
this.step = step;
|
|
173
|
+
this.status = status;
|
|
174
|
+
this.retryable = status === void 0 || status >= 500 || status === 408;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
async function withOneRetry(run) {
|
|
178
|
+
try {
|
|
179
|
+
return await run();
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (err instanceof DeviceAuthRequestError && err.retryable) {
|
|
182
|
+
if (deviceAuthRetryDelayMs > 0) {
|
|
183
|
+
await defaultSleep(deviceAuthRetryDelayMs);
|
|
184
|
+
}
|
|
185
|
+
return run();
|
|
186
|
+
}
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
142
190
|
async function listProjects(endpoint, cliToken) {
|
|
143
191
|
const base = trimTrailingSlash(endpoint);
|
|
144
|
-
|
|
145
|
-
|
|
192
|
+
return withOneRetry(async () => {
|
|
193
|
+
let res;
|
|
194
|
+
try {
|
|
195
|
+
res = await deviceFetch(`${base}/v1/cli/projects`, { headers: cliAuthHeaders(cliToken) });
|
|
196
|
+
} catch (err) {
|
|
197
|
+
throw new DeviceAuthRequestError(
|
|
198
|
+
"list_projects",
|
|
199
|
+
`Could not reach ${base}/v1/cli/projects: ${err instanceof Error ? err.message : String(err)}`
|
|
200
|
+
);
|
|
201
|
+
}
|
|
146
202
|
const json = await res.json().catch(() => null);
|
|
147
203
|
if (res.ok && json?.ok) return json.data?.projects ?? [];
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
204
|
+
throw new DeviceAuthRequestError(
|
|
205
|
+
"list_projects",
|
|
206
|
+
json?.error?.message ?? `Could not list projects (HTTP ${res.status}).`,
|
|
207
|
+
res.status
|
|
152
208
|
);
|
|
153
|
-
}
|
|
154
|
-
return [];
|
|
209
|
+
});
|
|
155
210
|
}
|
|
156
211
|
async function createProject(endpoint, cliToken, name) {
|
|
157
212
|
const base = trimTrailingSlash(endpoint);
|
|
@@ -169,17 +224,28 @@ async function createProject(endpoint, cliToken, name) {
|
|
|
169
224
|
}
|
|
170
225
|
async function mintProjectKey(endpoint, cliToken, projectId) {
|
|
171
226
|
const base = trimTrailingSlash(endpoint);
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
+
}
|
|
178
241
|
const json = await res.json().catch(() => null);
|
|
179
|
-
if (res.ok && json?.ok
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
242
|
+
if (res.ok && json?.ok && json.data?.key) return json.data.key;
|
|
243
|
+
throw new DeviceAuthRequestError(
|
|
244
|
+
"mint_key",
|
|
245
|
+
json?.error?.message ?? `Could not mint an SDK key (HTTP ${res.status}).`,
|
|
246
|
+
res.ok ? void 0 : res.status
|
|
247
|
+
);
|
|
248
|
+
});
|
|
183
249
|
}
|
|
184
250
|
|
|
185
251
|
// src/freshness.ts
|
|
@@ -390,7 +456,10 @@ async function runInit(options = {}) {
|
|
|
390
456
|
const detected = detectFramework(cwd, pkg);
|
|
391
457
|
const framework = await chooseFramework(detected, options);
|
|
392
458
|
const consoleBase = await resolveConsoleUrl({ cwd });
|
|
393
|
-
const endpoint = resolveCloudEndpoint(
|
|
459
|
+
const endpoint = resolveCloudEndpoint(
|
|
460
|
+
options.endpoint ?? process.env.MUSHI_API_ENDPOINT?.trim() ?? loadConfig().endpoint
|
|
461
|
+
);
|
|
462
|
+
options = { ...options, endpoint };
|
|
394
463
|
const credentials = await acquireCredentials(options, consoleBase, endpoint);
|
|
395
464
|
await verifyCredentials(credentials, options, consoleBase);
|
|
396
465
|
const pm = detectPackageManager(cwd);
|
|
@@ -400,8 +469,16 @@ async function runInit(options = {}) {
|
|
|
400
469
|
} else {
|
|
401
470
|
p.log.info(`Skipped install. Run \`${installCommand(pm, packagesToInstall)}\` yourself.`);
|
|
402
471
|
}
|
|
403
|
-
await writeEnvFile(
|
|
472
|
+
await writeEnvFile(
|
|
473
|
+
cwd,
|
|
474
|
+
credentials.apiKey,
|
|
475
|
+
credentials.projectId,
|
|
476
|
+
framework,
|
|
477
|
+
endpoint,
|
|
478
|
+
Boolean(options.yes)
|
|
479
|
+
);
|
|
404
480
|
persistCliConfig(credentials.apiKey, credentials.projectId, endpoint);
|
|
481
|
+
emitWizardFunnelEvent(credentials, endpoint, "wizard_env_written", { framework: framework.id });
|
|
405
482
|
const enableRewards = await maybeEnableRewards(options);
|
|
406
483
|
printNextSteps(framework, consoleBase, enableRewards);
|
|
407
484
|
await maybeSendTestReport(credentials, { ...options, endpoint, consoleBase });
|
|
@@ -473,7 +550,9 @@ async function acquireCredentials(options, consoleBase, endpoint) {
|
|
|
473
550
|
if (options.yes) {
|
|
474
551
|
const creds = await runBrowserSignIn(options, endpoint, consoleBase);
|
|
475
552
|
if (creds) return creds;
|
|
476
|
-
p.log.warn(
|
|
553
|
+
p.log.warn(
|
|
554
|
+
"Browser sign-in didn't complete \u2014 switching to manual entry. Run `npx mushi-mushi doctor --auth` to diagnose the sign-in path."
|
|
555
|
+
);
|
|
477
556
|
} else {
|
|
478
557
|
const method = await p.select({
|
|
479
558
|
message: "Connect this app to Mushi",
|
|
@@ -498,17 +577,19 @@ async function acquireCredentials(options, consoleBase, endpoint) {
|
|
|
498
577
|
if (method === "browser") {
|
|
499
578
|
const creds = await runBrowserSignIn(options, endpoint, consoleBase);
|
|
500
579
|
if (creds) return creds;
|
|
501
|
-
p.log.warn(
|
|
580
|
+
p.log.warn(
|
|
581
|
+
"Browser sign-in didn't complete \u2014 switching to manual entry. Run `npx mushi-mushi doctor --auth` to diagnose the sign-in path."
|
|
582
|
+
);
|
|
502
583
|
}
|
|
503
584
|
}
|
|
504
|
-
return collectCredentialsManually(options, consoleBase);
|
|
585
|
+
return collectCredentialsManually(options, consoleBase, endpoint);
|
|
505
586
|
}
|
|
506
587
|
async function runBrowserSignIn(options, endpoint, consoleBase) {
|
|
507
588
|
const startSpin = p.spinner();
|
|
508
589
|
startSpin.start("Starting secure browser sign-in\u2026");
|
|
509
590
|
let session;
|
|
510
591
|
try {
|
|
511
|
-
session = await startDeviceAuth(endpoint);
|
|
592
|
+
session = await startDeviceAuth(endpoint, ensureClientId());
|
|
512
593
|
} catch (err) {
|
|
513
594
|
startSpin.stop("Could not start browser sign-in.");
|
|
514
595
|
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
@@ -539,7 +620,9 @@ async function runBrowserSignIn(options, endpoint, consoleBase) {
|
|
|
539
620
|
fetchSpin.start("Loading your projects\u2026");
|
|
540
621
|
try {
|
|
541
622
|
projects = await listProjects(endpoint, cliToken);
|
|
542
|
-
fetchSpin.stop(
|
|
623
|
+
fetchSpin.stop(
|
|
624
|
+
projects.length > 0 ? `Found ${projects.length} project(s).` : "No projects yet."
|
|
625
|
+
);
|
|
543
626
|
} catch (err) {
|
|
544
627
|
fetchSpin.stop("Could not load projects \u2014 you can still create a new one.");
|
|
545
628
|
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
@@ -587,34 +670,50 @@ async function runBrowserSignIn(options, endpoint, consoleBase) {
|
|
|
587
670
|
const keySpin = p.spinner();
|
|
588
671
|
keySpin.start("Minting SDK key\u2026");
|
|
589
672
|
try {
|
|
590
|
-
|
|
591
|
-
apiKey = minted ?? void 0;
|
|
592
|
-
if (!apiKey) {
|
|
593
|
-
keySpin.stop("Could not mint an API key.");
|
|
594
|
-
p.log.warn(
|
|
595
|
-
`Open the console Verify tab to generate a key manually: ${consoleUrl(consoleBase, "/onboarding?tab=verify")}`
|
|
596
|
-
);
|
|
597
|
-
return null;
|
|
598
|
-
}
|
|
673
|
+
apiKey = await mintProjectKey(endpoint, cliToken, projectId);
|
|
599
674
|
keySpin.stop("SDK key ready.");
|
|
600
675
|
} catch (err) {
|
|
601
676
|
keySpin.stop("Could not mint an API key.");
|
|
602
677
|
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
678
|
+
p.log.warn(
|
|
679
|
+
`You're signed in, but key minting failed. Generate one manually in the console Verify tab: ${consoleUrl(consoleBase, "/onboarding?tab=verify")}`
|
|
680
|
+
);
|
|
603
681
|
return null;
|
|
604
682
|
}
|
|
605
683
|
}
|
|
606
684
|
if (!projectId || !apiKey) return null;
|
|
607
685
|
return { apiKey, projectId };
|
|
608
686
|
}
|
|
609
|
-
async function collectCredentialsManually(options, consoleBase) {
|
|
687
|
+
async function collectCredentialsManually(options, consoleBase, endpoint) {
|
|
610
688
|
const existing = loadConfig();
|
|
611
|
-
|
|
689
|
+
let savedProjectId = existing.projectId;
|
|
690
|
+
let savedApiKey = existing.apiKey;
|
|
691
|
+
if (!options.projectId && !options.apiKey && savedProjectId && savedApiKey) {
|
|
692
|
+
p.log.info(
|
|
693
|
+
`Found saved credentials from a previous sign-in (project ${sanitizeSecret(savedProjectId).slice(0, 8)}\u2026).`
|
|
694
|
+
);
|
|
695
|
+
const checkSpin = p.spinner();
|
|
696
|
+
checkSpin.start("Checking saved credentials\u2026");
|
|
697
|
+
const check = await apiCall("/v1/sync/whoami", {
|
|
698
|
+
apiKey: sanitizeSecret(savedApiKey),
|
|
699
|
+
projectId: sanitizeSecret(savedProjectId),
|
|
700
|
+
endpoint
|
|
701
|
+
});
|
|
702
|
+
if (check.ok) {
|
|
703
|
+
checkSpin.stop(`Saved credentials still work (${check.data.project_name}).`);
|
|
704
|
+
} else {
|
|
705
|
+
checkSpin.stop("Saved credentials no longer authenticate \u2014 enter fresh ones below.");
|
|
706
|
+
savedProjectId = void 0;
|
|
707
|
+
savedApiKey = void 0;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
const rawProjectId = options.projectId ?? savedProjectId ?? await promptText({
|
|
612
711
|
message: "Project ID",
|
|
613
712
|
placeholder: "e.g. bdafa28d-b153-482f-bd4f-42981f3fd3a4",
|
|
614
713
|
hint: projectIdHint(consoleBase),
|
|
615
714
|
validate: (v) => PROJECT_ID_PATTERN.test(v.trim()) ? void 0 : "Expected a UUID \u2014 copy it from the Projects page or the panel right after you create a project."
|
|
616
715
|
});
|
|
617
|
-
const rawApiKey = options.apiKey ??
|
|
716
|
+
const rawApiKey = options.apiKey ?? savedApiKey ?? await promptText({
|
|
618
717
|
message: "API key",
|
|
619
718
|
placeholder: "mushi_xxxxxxxxxxxx",
|
|
620
719
|
hint: apiKeyHint(consoleBase),
|
|
@@ -638,17 +737,30 @@ async function verifyCredentials(credentials, options, consoleBase) {
|
|
|
638
737
|
const endpoint = resolveCloudEndpoint(options.endpoint);
|
|
639
738
|
const spinner2 = p.spinner();
|
|
640
739
|
spinner2.start("Verifying credentials\u2026");
|
|
641
|
-
const result = await apiCall(
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
740
|
+
const result = await apiCall("/v1/sync/whoami", {
|
|
741
|
+
apiKey: credentials.apiKey,
|
|
742
|
+
projectId: credentials.projectId,
|
|
743
|
+
endpoint
|
|
744
|
+
});
|
|
645
745
|
if (!result.ok) {
|
|
646
746
|
spinner2.stop("Credentials could not be verified.");
|
|
647
747
|
p.log.error(result.error?.message ?? "Authentication failed.");
|
|
648
|
-
p.log.
|
|
649
|
-
|
|
748
|
+
p.log.warn("Setup did NOT complete: nothing was installed and no env vars were written.");
|
|
749
|
+
p.log.info(
|
|
750
|
+
[
|
|
751
|
+
"To recover:",
|
|
752
|
+
' \u2022 Re-run `npx mushi-mushi` and choose "Sign in with your browser", or',
|
|
753
|
+
` \u2022 Double-check the Project ID / API key in the console: ${cliSetupDeepLink(consoleBase)}`
|
|
754
|
+
].join("\n")
|
|
755
|
+
);
|
|
650
756
|
throw new Error("Credential verification failed \u2014 fix Project ID / API key and re-run.");
|
|
651
757
|
}
|
|
758
|
+
if (result.data.project_id && result.data.project_id !== credentials.projectId) {
|
|
759
|
+
p.log.warn(
|
|
760
|
+
`Project ID ${redact(credentials.projectId)} doesn't match this API key's project \u2014 using the key's actual project (${result.data.project_name}) instead.`
|
|
761
|
+
);
|
|
762
|
+
credentials.projectId = result.data.project_id;
|
|
763
|
+
}
|
|
652
764
|
spinner2.stop(`Connected to ${result.data.project_name}`);
|
|
653
765
|
}
|
|
654
766
|
function sanitizeSecret(raw) {
|
|
@@ -784,6 +896,20 @@ function persistCliConfig(apiKey, projectId, endpoint) {
|
|
|
784
896
|
const existing = loadConfig();
|
|
785
897
|
saveConfig({ ...existing, apiKey, projectId, endpoint });
|
|
786
898
|
}
|
|
899
|
+
function emitWizardFunnelEvent(credentials, endpoint, event, metadata = {}) {
|
|
900
|
+
if (process.env.MUSHI_NO_TELEMETRY) return;
|
|
901
|
+
void fetch(`${endpoint.replace(/\/$/, "")}/v1/cli/funnel`, {
|
|
902
|
+
method: "POST",
|
|
903
|
+
headers: {
|
|
904
|
+
"Content-Type": "application/json",
|
|
905
|
+
"X-Mushi-Api-Key": credentials.apiKey,
|
|
906
|
+
"X-Mushi-Project": credentials.projectId
|
|
907
|
+
},
|
|
908
|
+
body: JSON.stringify({ event, source: "cli", metadata }),
|
|
909
|
+
signal: AbortSignal.timeout(4e3)
|
|
910
|
+
}).catch(() => {
|
|
911
|
+
});
|
|
912
|
+
}
|
|
787
913
|
function printNextSteps(framework, consoleBase, enableRewards = false) {
|
|
788
914
|
p.note(framework.snippet(), "Add this to your app:");
|
|
789
915
|
if (enableRewards) {
|
|
@@ -817,7 +943,7 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
817
943
|
if (p.isCancel(answer) || !answer) return;
|
|
818
944
|
const endpoint = resolveCloudEndpoint(options.endpoint);
|
|
819
945
|
try {
|
|
820
|
-
const { runConnect } = await import("./connect-
|
|
946
|
+
const { runConnect } = await import("./connect-7LTQRBEW.js");
|
|
821
947
|
await runConnect({
|
|
822
948
|
apiKey: credentials.apiKey,
|
|
823
949
|
projectId: credentials.projectId,
|
|
@@ -828,12 +954,8 @@ async function maybeOfferConnect(credentials, options, _consoleBase) {
|
|
|
828
954
|
wait: true
|
|
829
955
|
});
|
|
830
956
|
} catch (err) {
|
|
831
|
-
p.log.warn(
|
|
832
|
-
|
|
833
|
-
);
|
|
834
|
-
p.log.info(
|
|
835
|
-
"You can run manually: mushi connect --write-env --wire-ide --wait"
|
|
836
|
-
);
|
|
957
|
+
p.log.warn(err instanceof Error ? err.message : String(err));
|
|
958
|
+
p.log.info("You can run manually: mushi connect --write-env --wire-ide --wait");
|
|
837
959
|
}
|
|
838
960
|
}
|
|
839
961
|
async function maybeEnableRewards(options) {
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.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": {
|
|
@@ -11,11 +11,11 @@
|
|
|
11
11
|
"commander": "^15.0.0"
|
|
12
12
|
},
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@types/node": "^22.
|
|
15
|
-
"eslint": "^10.
|
|
14
|
+
"@types/node": "^22.20.0",
|
|
15
|
+
"eslint": "^10.6.0",
|
|
16
16
|
"tsup": "^8.5.1",
|
|
17
17
|
"typescript": "^6.0.3",
|
|
18
|
-
"vitest": "^4.1.
|
|
18
|
+
"vitest": "^4.1.9",
|
|
19
19
|
"@mushi-mushi/eslint-config": "0.0.0"
|
|
20
20
|
},
|
|
21
21
|
"author": "Kenji Sakuramoto (https://bsky.app/profile/mushimushi.dev)",
|