@mushi-mushi/cli 0.8.0 → 0.11.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 +106 -382
- package/dist/chunk-LXO45AYO.js +6 -0
- package/dist/{chunk-XHD3H54W.js → chunk-NYPX5KXR.js} +78 -0
- package/dist/detect.d.ts +1 -1
- package/dist/detect.js +1 -1
- package/dist/index.js +952 -12
- package/dist/init.js +67 -12
- package/dist/version.js +1 -1
- package/package.json +10 -10
- package/dist/chunk-KUQZQFOL.js +0 -6
package/dist/init.js
CHANGED
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
envVarsToWrite,
|
|
6
6
|
installCommand,
|
|
7
7
|
readPackageJson
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NYPX5KXR.js";
|
|
9
9
|
import {
|
|
10
10
|
MUSHI_CLI_VERSION
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-LXO45AYO.js";
|
|
12
12
|
|
|
13
13
|
// src/init.ts
|
|
14
14
|
import * as p from "@clack/prompts";
|
|
@@ -18,11 +18,26 @@ import { appendFileSync, existsSync as existsSync3, readFileSync as readFileSync
|
|
|
18
18
|
import { join as join3 } from "path";
|
|
19
19
|
|
|
20
20
|
// src/config.ts
|
|
21
|
-
import { chmodSync, readFileSync, statSync,
|
|
22
|
-
import { join } from "path";
|
|
21
|
+
import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
23
22
|
import { homedir } from "os";
|
|
24
|
-
|
|
23
|
+
import { dirname, join } from "path";
|
|
25
24
|
var SECURE_FILE_MODE = 384;
|
|
25
|
+
var SECURE_DIR_MODE = 448;
|
|
26
|
+
function resolveXdgConfigPath() {
|
|
27
|
+
const xdg = process.env["XDG_CONFIG_HOME"];
|
|
28
|
+
if (xdg && xdg.length > 0) {
|
|
29
|
+
return join(xdg, "mushi", "config.json");
|
|
30
|
+
}
|
|
31
|
+
if (process.platform === "win32") {
|
|
32
|
+
const appData = process.env["APPDATA"];
|
|
33
|
+
if (appData && appData.length > 0) {
|
|
34
|
+
return join(appData, "mushi", "config.json");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return join(homedir(), ".config", "mushi", "config.json");
|
|
38
|
+
}
|
|
39
|
+
var LEGACY_CONFIG_PATH = join(homedir(), ".mushirc");
|
|
40
|
+
var CONFIG_PATH = resolveXdgConfigPath();
|
|
26
41
|
function loadConfig(path = CONFIG_PATH) {
|
|
27
42
|
let file = {};
|
|
28
43
|
if (existsSync(path)) {
|
|
@@ -31,6 +46,8 @@ function loadConfig(path = CONFIG_PATH) {
|
|
|
31
46
|
file = JSON.parse(readFileSync(path, "utf-8"));
|
|
32
47
|
} catch {
|
|
33
48
|
}
|
|
49
|
+
} else if (path === CONFIG_PATH && existsSync(LEGACY_CONFIG_PATH)) {
|
|
50
|
+
file = migrateLegacyConfig() ?? {};
|
|
34
51
|
}
|
|
35
52
|
const fromEnv = {
|
|
36
53
|
...process.env["MUSHI_API_KEY"] ? { apiKey: process.env["MUSHI_API_KEY"] } : {},
|
|
@@ -40,9 +57,40 @@ function loadConfig(path = CONFIG_PATH) {
|
|
|
40
57
|
return { ...file, ...fromEnv };
|
|
41
58
|
}
|
|
42
59
|
function saveConfig(config, path = CONFIG_PATH) {
|
|
60
|
+
const dir = dirname(path);
|
|
61
|
+
if (!existsSync(dir)) {
|
|
62
|
+
mkdirSync(dir, { recursive: true, mode: SECURE_DIR_MODE });
|
|
63
|
+
} else {
|
|
64
|
+
tightenDirPermissions(dir);
|
|
65
|
+
}
|
|
43
66
|
writeFileSync(path, JSON.stringify(config, null, 2), { mode: SECURE_FILE_MODE });
|
|
44
67
|
tightenPermissions(path);
|
|
45
68
|
}
|
|
69
|
+
function migrateLegacyConfig(legacyPath = LEGACY_CONFIG_PATH, destPath = CONFIG_PATH) {
|
|
70
|
+
if (!existsSync(legacyPath)) return null;
|
|
71
|
+
let parsed;
|
|
72
|
+
try {
|
|
73
|
+
parsed = JSON.parse(readFileSync(legacyPath, "utf-8"));
|
|
74
|
+
} catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
const dir = dirname(destPath);
|
|
78
|
+
if (!existsSync(dir)) {
|
|
79
|
+
mkdirSync(dir, { recursive: true, mode: SECURE_DIR_MODE });
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
renameSync(legacyPath, destPath);
|
|
83
|
+
} catch {
|
|
84
|
+
writeFileSync(destPath, JSON.stringify(parsed, null, 2), { mode: SECURE_FILE_MODE });
|
|
85
|
+
try {
|
|
86
|
+
unlinkSync(legacyPath);
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
tightenPermissions(destPath);
|
|
91
|
+
tightenDirPermissions(dir);
|
|
92
|
+
return parsed;
|
|
93
|
+
}
|
|
46
94
|
function tightenPermissions(path) {
|
|
47
95
|
if (process.platform === "win32") return;
|
|
48
96
|
try {
|
|
@@ -51,6 +99,14 @@ function tightenPermissions(path) {
|
|
|
51
99
|
} catch {
|
|
52
100
|
}
|
|
53
101
|
}
|
|
102
|
+
function tightenDirPermissions(path) {
|
|
103
|
+
if (process.platform === "win32") return;
|
|
104
|
+
try {
|
|
105
|
+
const current = statSync(path).mode & 511;
|
|
106
|
+
if (current !== SECURE_DIR_MODE) chmodSync(path, SECURE_DIR_MODE);
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
}
|
|
54
110
|
|
|
55
111
|
// src/endpoint.ts
|
|
56
112
|
var TEST_REPORT_TIMEOUT_MS = 1e4;
|
|
@@ -125,7 +181,7 @@ function parse(version) {
|
|
|
125
181
|
|
|
126
182
|
// src/monorepo.ts
|
|
127
183
|
import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, statSync as statSync2 } from "fs";
|
|
128
|
-
import { dirname, join as join2, resolve } from "path";
|
|
184
|
+
import { dirname as dirname2, join as join2, resolve } from "path";
|
|
129
185
|
var WORKSPACE_GLOB_CANDIDATES = ["apps/*", "packages/*", "examples/*"];
|
|
130
186
|
var FRAMEWORK_DEPS = {
|
|
131
187
|
next: "Next.js",
|
|
@@ -153,7 +209,7 @@ function findWorkspaceRoot(start) {
|
|
|
153
209
|
let dir = resolve(start);
|
|
154
210
|
for (let i = 0; i < 8; i++) {
|
|
155
211
|
if (isWorkspaceRoot(dir)) return dir;
|
|
156
|
-
const parent =
|
|
212
|
+
const parent = dirname2(dir);
|
|
157
213
|
if (parent === dir) break;
|
|
158
214
|
dir = parent;
|
|
159
215
|
}
|
|
@@ -267,7 +323,7 @@ function ensureInteractiveOrBailOut(options) {
|
|
|
267
323
|
);
|
|
268
324
|
if (hasAllFlags) return;
|
|
269
325
|
process.stderr.write(
|
|
270
|
-
"mushi-mushi: non-interactive terminal detected.\nPass all of --yes (or --framework), --project-id, and --api-key to run unattended.\nExample: npx mushi-mushi --yes --project-id
|
|
326
|
+
"mushi-mushi: non-interactive terminal detected.\nPass all of --yes (or --framework), --project-id, and --api-key to run unattended.\nExample: npx mushi-mushi --yes --project-id <uuid-from-console> --api-key mushi_xxx\nYour project ID is the UUID shown in the Projects page of the Mushi admin console.\n"
|
|
271
327
|
);
|
|
272
328
|
process.exit(1);
|
|
273
329
|
}
|
|
@@ -301,9 +357,9 @@ async function collectCredentials(options) {
|
|
|
301
357
|
const existing = loadConfig();
|
|
302
358
|
const rawProjectId = options.projectId ?? existing.projectId ?? await promptText({
|
|
303
359
|
message: "Project ID",
|
|
304
|
-
placeholder: "
|
|
360
|
+
placeholder: "e.g. bdafa28d-b153-482f-bd4f-42981f3fd3a4",
|
|
305
361
|
hint: "Where to find it: https://kensaur.us/mushi-mushi/projects \u2192 click your project \u2192 copy the UUID below the project name.",
|
|
306
|
-
validate: (v) => PROJECT_ID_PATTERN.test(v) ? void 0 : "Expected a UUID (
|
|
362
|
+
validate: (v) => PROJECT_ID_PATTERN.test(v.trim()) ? void 0 : "Expected a UUID (e.g. bdafa28d-b153-482f-bd4f-42981f3fd3a4) \u2014 copy it from the Mushi admin console Projects page."
|
|
307
363
|
});
|
|
308
364
|
const rawApiKey = options.apiKey ?? existing.apiKey ?? await promptText({
|
|
309
365
|
message: "API key",
|
|
@@ -315,8 +371,7 @@ async function collectCredentials(options) {
|
|
|
315
371
|
const apiKey = sanitizeSecret(rawApiKey);
|
|
316
372
|
if (!PROJECT_ID_PATTERN.test(projectId)) {
|
|
317
373
|
throw new Error(
|
|
318
|
-
`Invalid project ID. Got: ${redact(projectId)}
|
|
319
|
-
Expected a UUID (e.g. 542b34e0-019e-41fe-b900-7b637717bb86) \u2014 copy it from the Projects page in the Mushi console at https://kensaur.us/mushi-mushi/projects`
|
|
374
|
+
`Invalid project ID. Expected a UUID (e.g. bdafa28d-b153-482f-bd4f-42981f3fd3a4) or the proj_* prefixed form. Got: ${redact(projectId)} \u2014 copy it from the Projects page in the Mushi console at https://kensaur.us/mushi-mushi/projects`
|
|
320
375
|
);
|
|
321
376
|
}
|
|
322
377
|
if (!API_KEY_PATTERN.test(apiKey)) {
|
package/dist/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mushi-mushi/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.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": {
|
|
7
7
|
"mushi": "./dist/index.js"
|
|
8
8
|
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsup",
|
|
11
|
+
"lint": "eslint src/",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"typecheck": "tsc --noEmit"
|
|
14
|
+
},
|
|
9
15
|
"dependencies": {
|
|
10
16
|
"@clack/prompts": "^1.3.0",
|
|
11
17
|
"commander": "^14.0.3"
|
|
12
18
|
},
|
|
13
19
|
"devDependencies": {
|
|
20
|
+
"@mushi-mushi/eslint-config": "workspace:*",
|
|
14
21
|
"@types/node": "^22.19.17",
|
|
15
22
|
"eslint": "^10.3.0",
|
|
16
23
|
"tsup": "^8.5.1",
|
|
17
24
|
"typescript": "^6.0.3",
|
|
18
|
-
"vitest": "^4.1.5"
|
|
19
|
-
"@mushi-mushi/eslint-config": "0.0.0"
|
|
25
|
+
"vitest": "^4.1.5"
|
|
20
26
|
},
|
|
21
27
|
"author": "Kenji Sakuramoto",
|
|
22
28
|
"repository": {
|
|
@@ -103,11 +109,5 @@
|
|
|
103
109
|
"type": "module",
|
|
104
110
|
"engines": {
|
|
105
111
|
"node": ">=20"
|
|
106
|
-
},
|
|
107
|
-
"scripts": {
|
|
108
|
-
"build": "tsup",
|
|
109
|
-
"lint": "eslint src/",
|
|
110
|
-
"test": "vitest run",
|
|
111
|
-
"typecheck": "tsc --noEmit"
|
|
112
112
|
}
|
|
113
|
-
}
|
|
113
|
+
}
|