@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/dist/init.js CHANGED
@@ -5,10 +5,10 @@ import {
5
5
  envVarsToWrite,
6
6
  installCommand,
7
7
  readPackageJson
8
- } from "./chunk-XHD3H54W.js";
8
+ } from "./chunk-NYPX5KXR.js";
9
9
  import {
10
10
  MUSHI_CLI_VERSION
11
- } from "./chunk-KUQZQFOL.js";
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, writeFileSync, existsSync } from "fs";
22
- import { join } from "path";
21
+ import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
23
22
  import { homedir } from "os";
24
- var CONFIG_PATH = join(homedir(), ".mushirc");
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 = dirname(dir);
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 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx --api-key mushi_xxx\nYour project ID is the UUID shown in the Projects page of the Mushi admin console.\n"
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: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
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 (xxxxxxxx-xxxx-...) \u2014 copy it from the Mushi admin console Projects page."
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
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  MUSHI_CLI_VERSION
3
- } from "./chunk-KUQZQFOL.js";
3
+ } from "./chunk-LXO45AYO.js";
4
4
  export {
5
5
  MUSHI_CLI_VERSION
6
6
  };
package/package.json CHANGED
@@ -1,22 +1,28 @@
1
1
  {
2
2
  "name": "@mushi-mushi/cli",
3
- "version": "0.8.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
+ }
@@ -1,6 +0,0 @@
1
- // src/version.ts
2
- var MUSHI_CLI_VERSION = true ? "0.8.0" : "0.0.0-dev";
3
-
4
- export {
5
- MUSHI_CLI_VERSION
6
- };