@nebulord/sickbay 0.1.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 +231 -0
- package/dist/DiffApp-YF2PYQZK.js +187 -0
- package/dist/DoctorApp-U465IMK7.js +447 -0
- package/dist/FixApp-RJPCWNXJ.js +344 -0
- package/dist/StatsApp-BI6COY7S.js +375 -0
- package/dist/TrendApp-XL77HKDR.js +118 -0
- package/dist/TuiApp-VJNV4FD3.js +982 -0
- package/dist/ai-7DGOLNJX.js +64 -0
- package/dist/badge-KQ73KEIN.js +41 -0
- package/dist/chunk-5KJOYSVJ.js +95 -0
- package/dist/chunk-BIK4EL4H.js +19 -0
- package/dist/chunk-BUD5BE6U.js +61 -0
- package/dist/chunk-D24FSOW4.js +22 -0
- package/dist/chunk-POUHUMJN.js +21 -0
- package/dist/chunk-SSUXSMGH.js +25 -0
- package/dist/history-DYFJ65XH.js +14 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +535 -0
- package/dist/init-J2NPRPDO.js +54 -0
- package/dist/resolve-package-PHPJWOLY.js +8 -0
- package/dist/web-EE2VYPEX.js +198 -0
- package/package.json +58 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Header
|
|
3
|
+
} from "./chunk-BIK4EL4H.js";
|
|
4
|
+
import {
|
|
5
|
+
shortName
|
|
6
|
+
} from "./chunk-BUD5BE6U.js";
|
|
7
|
+
|
|
8
|
+
// src/components/DoctorApp.tsx
|
|
9
|
+
import React, { useState, useEffect } from "react";
|
|
10
|
+
import { Box, Text, useApp } from "ink";
|
|
11
|
+
import Spinner from "ink-spinner";
|
|
12
|
+
|
|
13
|
+
// src/commands/doctor.ts
|
|
14
|
+
import { existsSync, readFileSync } from "fs";
|
|
15
|
+
import { join } from "path";
|
|
16
|
+
import { detectProject, detectPackageManager } from "@nebulord/sickbay-core";
|
|
17
|
+
async function checkGitignore(projectPath) {
|
|
18
|
+
const gitignorePath = join(projectPath, ".gitignore");
|
|
19
|
+
if (!existsSync(gitignorePath)) {
|
|
20
|
+
return {
|
|
21
|
+
id: "gitignore",
|
|
22
|
+
label: ".gitignore exists",
|
|
23
|
+
status: "fail",
|
|
24
|
+
message: "No .gitignore found",
|
|
25
|
+
fixDescription: "Create .gitignore with standard entries"
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
const content = readFileSync(gitignorePath, "utf-8");
|
|
29
|
+
const lines = content.split("\n").map((l) => l.trim());
|
|
30
|
+
const required = ["node_modules", ".env", "dist", ".DS_Store"];
|
|
31
|
+
const missing = required.filter((entry) => !lines.includes(entry));
|
|
32
|
+
if (missing.length > 0) {
|
|
33
|
+
return {
|
|
34
|
+
id: "gitignore",
|
|
35
|
+
label: ".gitignore entries",
|
|
36
|
+
status: "warn",
|
|
37
|
+
message: `Missing entries: ${missing.join(", ")}`,
|
|
38
|
+
fixDescription: `Add ${missing.join(", ")} to .gitignore`
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
id: "gitignore",
|
|
43
|
+
label: ".gitignore entries",
|
|
44
|
+
status: "pass",
|
|
45
|
+
message: "All standard entries present"
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function checkEnginesField(projectPath) {
|
|
49
|
+
const pkg = JSON.parse(
|
|
50
|
+
readFileSync(join(projectPath, "package.json"), "utf-8")
|
|
51
|
+
);
|
|
52
|
+
if (!pkg.engines) {
|
|
53
|
+
return {
|
|
54
|
+
id: "engines",
|
|
55
|
+
label: "package.json engines field",
|
|
56
|
+
status: "warn",
|
|
57
|
+
message: "No engines field \u2014 Node.js version not specified",
|
|
58
|
+
fixDescription: 'Add "engines": { "node": ">=18.0.0" } to package.json'
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
id: "engines",
|
|
63
|
+
label: "package.json engines field",
|
|
64
|
+
status: "pass",
|
|
65
|
+
message: `node ${pkg.engines.node ?? "unspecified"}`
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function checkBrowserslist(projectPath) {
|
|
69
|
+
const pkg = JSON.parse(
|
|
70
|
+
readFileSync(join(projectPath, "package.json"), "utf-8")
|
|
71
|
+
);
|
|
72
|
+
const hasFile = existsSync(join(projectPath, ".browserslistrc")) || existsSync(join(projectPath, "browserslist"));
|
|
73
|
+
const hasField = !!pkg.browserslist;
|
|
74
|
+
if (!hasFile && !hasField) {
|
|
75
|
+
return {
|
|
76
|
+
id: "browserslist",
|
|
77
|
+
label: "Browserslist config",
|
|
78
|
+
status: "warn",
|
|
79
|
+
message: "No browserslist config \u2014 browser targets not defined",
|
|
80
|
+
fixDescription: "Create .browserslistrc with default targets"
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
id: "browserslist",
|
|
85
|
+
label: "Browserslist config",
|
|
86
|
+
status: "pass",
|
|
87
|
+
message: "Browserslist configured"
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
async function checkNodeVersion(projectPath) {
|
|
91
|
+
const hasNvmrc = existsSync(join(projectPath, ".nvmrc"));
|
|
92
|
+
const hasNodeVersion = existsSync(join(projectPath, ".node-version"));
|
|
93
|
+
const hasToolVersions = existsSync(join(projectPath, ".tool-versions"));
|
|
94
|
+
if (!hasNvmrc && !hasNodeVersion && !hasToolVersions) {
|
|
95
|
+
return {
|
|
96
|
+
id: "node-version",
|
|
97
|
+
label: "Node version pinning",
|
|
98
|
+
status: "warn",
|
|
99
|
+
message: "No .nvmrc or .node-version \u2014 Node version not pinned",
|
|
100
|
+
fixDescription: "Create .nvmrc with current Node version"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
id: "node-version",
|
|
105
|
+
label: "Node version pinning",
|
|
106
|
+
status: "pass",
|
|
107
|
+
message: hasNvmrc ? ".nvmrc found" : hasNodeVersion ? ".node-version found" : ".tool-versions found"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
async function checkNpmScripts(projectPath) {
|
|
111
|
+
const pkg = JSON.parse(
|
|
112
|
+
readFileSync(join(projectPath, "package.json"), "utf-8")
|
|
113
|
+
);
|
|
114
|
+
const scripts = pkg.scripts ?? {};
|
|
115
|
+
const expected = ["lint", "test", "build"];
|
|
116
|
+
const missing = expected.filter((s) => !scripts[s]);
|
|
117
|
+
if (missing.length > 0) {
|
|
118
|
+
return {
|
|
119
|
+
id: "npm-scripts",
|
|
120
|
+
label: "Essential npm scripts",
|
|
121
|
+
status: missing.includes("build") || missing.includes("test") ? "fail" : "warn",
|
|
122
|
+
message: `Missing scripts: ${missing.join(", ")}`,
|
|
123
|
+
fixDescription: `Add ${missing.join(", ")} scripts to package.json`
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
id: "npm-scripts",
|
|
128
|
+
label: "Essential npm scripts",
|
|
129
|
+
status: "pass",
|
|
130
|
+
message: "lint, test, build all defined"
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
async function checkLockfile(projectPath) {
|
|
134
|
+
const hasNpmLock = existsSync(join(projectPath, "package-lock.json"));
|
|
135
|
+
const hasPnpmLock = existsSync(join(projectPath, "pnpm-lock.yaml"));
|
|
136
|
+
const hasYarnLock = existsSync(join(projectPath, "yarn.lock"));
|
|
137
|
+
const hasBunLock = existsSync(join(projectPath, "bun.lockb")) || existsSync(join(projectPath, "bun.lock"));
|
|
138
|
+
if (!hasNpmLock && !hasPnpmLock && !hasYarnLock && !hasBunLock) {
|
|
139
|
+
return {
|
|
140
|
+
id: "lockfile",
|
|
141
|
+
label: "Lockfile present",
|
|
142
|
+
status: "fail",
|
|
143
|
+
message: "No lockfile found \u2014 dependencies not pinned",
|
|
144
|
+
fixCommand: "npm install",
|
|
145
|
+
fixDescription: "Generate lockfile with npm install"
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
const lockfileNames = {
|
|
149
|
+
pnpm: "pnpm-lock.yaml",
|
|
150
|
+
yarn: "yarn.lock",
|
|
151
|
+
bun: "bun.lockb",
|
|
152
|
+
npm: "package-lock.json"
|
|
153
|
+
};
|
|
154
|
+
return {
|
|
155
|
+
id: "lockfile",
|
|
156
|
+
label: "Lockfile present",
|
|
157
|
+
status: "pass",
|
|
158
|
+
message: lockfileNames[detectPackageManager(projectPath)]
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
async function checkEditorconfig(projectPath) {
|
|
162
|
+
if (!existsSync(join(projectPath, ".editorconfig"))) {
|
|
163
|
+
return {
|
|
164
|
+
id: "editorconfig",
|
|
165
|
+
label: ".editorconfig",
|
|
166
|
+
status: "warn",
|
|
167
|
+
message: "No .editorconfig \u2014 editor settings not standardized",
|
|
168
|
+
fixDescription: "Create .editorconfig with standard settings"
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
id: "editorconfig",
|
|
173
|
+
label: ".editorconfig",
|
|
174
|
+
status: "pass",
|
|
175
|
+
message: ".editorconfig found"
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
async function checkPrettier(projectPath) {
|
|
179
|
+
const info = await detectProject(projectPath);
|
|
180
|
+
if (!info.hasPrettier) {
|
|
181
|
+
return {
|
|
182
|
+
id: "prettier",
|
|
183
|
+
label: "Prettier config",
|
|
184
|
+
status: "warn",
|
|
185
|
+
message: "No Prettier configured \u2014 code formatting not standardized",
|
|
186
|
+
fixCommand: "npm install -D prettier",
|
|
187
|
+
fixDescription: "Install prettier and create .prettierrc"
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
id: "prettier",
|
|
192
|
+
label: "Prettier config",
|
|
193
|
+
status: "pass",
|
|
194
|
+
message: "Prettier configured"
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
async function checkESLintConfig(projectPath) {
|
|
198
|
+
const info = await detectProject(projectPath);
|
|
199
|
+
if (!info.hasESLint) {
|
|
200
|
+
return {
|
|
201
|
+
id: "eslint-config",
|
|
202
|
+
label: "ESLint config",
|
|
203
|
+
status: "fail",
|
|
204
|
+
message: "No ESLint configured \u2014 no lint rules enforced",
|
|
205
|
+
fixCommand: "npm init @eslint/config",
|
|
206
|
+
fixDescription: "Initialize ESLint configuration"
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
return {
|
|
210
|
+
id: "eslint-config",
|
|
211
|
+
label: "ESLint config",
|
|
212
|
+
status: "pass",
|
|
213
|
+
message: "ESLint configured"
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
async function checkTsconfig(projectPath) {
|
|
217
|
+
const info = await detectProject(projectPath);
|
|
218
|
+
const hasTsconfig = existsSync(join(projectPath, "tsconfig.json"));
|
|
219
|
+
if (info.hasTypeScript && !hasTsconfig) {
|
|
220
|
+
return {
|
|
221
|
+
id: "tsconfig",
|
|
222
|
+
label: "TypeScript config",
|
|
223
|
+
status: "fail",
|
|
224
|
+
message: "TypeScript deps found but no tsconfig.json",
|
|
225
|
+
fixCommand: "npx tsc --init",
|
|
226
|
+
fixDescription: "Generate tsconfig.json"
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
if (!info.hasTypeScript) {
|
|
230
|
+
return {
|
|
231
|
+
id: "tsconfig",
|
|
232
|
+
label: "TypeScript",
|
|
233
|
+
status: "warn",
|
|
234
|
+
message: "TypeScript not in use (consider adopting)"
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return {
|
|
238
|
+
id: "tsconfig",
|
|
239
|
+
label: "TypeScript config",
|
|
240
|
+
status: "pass",
|
|
241
|
+
message: "tsconfig.json found"
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async function checkEnvExample(projectPath) {
|
|
245
|
+
const hasEnv = existsSync(join(projectPath, ".env"));
|
|
246
|
+
const hasExample = existsSync(join(projectPath, ".env.example")) || existsSync(join(projectPath, ".env.template")) || existsSync(join(projectPath, ".env.sample"));
|
|
247
|
+
if (hasEnv && !hasExample) {
|
|
248
|
+
return {
|
|
249
|
+
id: "env-example",
|
|
250
|
+
label: ".env.example",
|
|
251
|
+
status: "warn",
|
|
252
|
+
message: ".env exists but no .env.example \u2014 team members won't know required vars",
|
|
253
|
+
fixDescription: "Create .env.example with variable names (no values)"
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
if (!hasEnv) {
|
|
257
|
+
return {
|
|
258
|
+
id: "env-example",
|
|
259
|
+
label: ".env.example",
|
|
260
|
+
status: "pass",
|
|
261
|
+
message: "No .env file (not applicable)"
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
return {
|
|
265
|
+
id: "env-example",
|
|
266
|
+
label: ".env.example",
|
|
267
|
+
status: "pass",
|
|
268
|
+
message: ".env.example exists"
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
async function checkReactVersions(projectPath) {
|
|
272
|
+
const pkg = JSON.parse(
|
|
273
|
+
readFileSync(join(projectPath, "package.json"), "utf-8")
|
|
274
|
+
);
|
|
275
|
+
const deps = { ...pkg.dependencies ?? {}, ...pkg.devDependencies ?? {} };
|
|
276
|
+
const react = deps["react"];
|
|
277
|
+
const reactDom = deps["react-dom"];
|
|
278
|
+
if (!react) {
|
|
279
|
+
return {
|
|
280
|
+
id: "react-versions",
|
|
281
|
+
label: "React version consistency",
|
|
282
|
+
status: "pass",
|
|
283
|
+
message: "Not a React project"
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
if (!reactDom) {
|
|
287
|
+
return {
|
|
288
|
+
id: "react-versions",
|
|
289
|
+
label: "React version consistency",
|
|
290
|
+
status: "warn",
|
|
291
|
+
message: "react installed but react-dom missing",
|
|
292
|
+
fixCommand: `npm install react-dom@${react}`,
|
|
293
|
+
fixDescription: "Install react-dom matching react version"
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
if (react !== reactDom) {
|
|
297
|
+
return {
|
|
298
|
+
id: "react-versions",
|
|
299
|
+
label: "React version consistency",
|
|
300
|
+
status: "fail",
|
|
301
|
+
message: `react@${react} and react-dom@${reactDom} version mismatch`,
|
|
302
|
+
fixCommand: `npm install react-dom@${react}`,
|
|
303
|
+
fixDescription: "Align react-dom version with react"
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
return {
|
|
307
|
+
id: "react-versions",
|
|
308
|
+
label: "React version consistency",
|
|
309
|
+
status: "pass",
|
|
310
|
+
message: `react and react-dom both at ${react}`
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
var ALL_DIAGNOSTICS = [
|
|
314
|
+
checkGitignore,
|
|
315
|
+
checkEnginesField,
|
|
316
|
+
checkBrowserslist,
|
|
317
|
+
checkNodeVersion,
|
|
318
|
+
checkNpmScripts,
|
|
319
|
+
checkLockfile,
|
|
320
|
+
checkEditorconfig,
|
|
321
|
+
checkPrettier,
|
|
322
|
+
checkESLintConfig,
|
|
323
|
+
checkTsconfig,
|
|
324
|
+
checkEnvExample,
|
|
325
|
+
checkReactVersions
|
|
326
|
+
];
|
|
327
|
+
async function runDiagnostics(projectPath) {
|
|
328
|
+
const results = [];
|
|
329
|
+
for (const check of ALL_DIAGNOSTICS) {
|
|
330
|
+
try {
|
|
331
|
+
results.push(await check(projectPath));
|
|
332
|
+
} catch (err) {
|
|
333
|
+
results.push({
|
|
334
|
+
id: "unknown",
|
|
335
|
+
label: "Unknown check",
|
|
336
|
+
status: "fail",
|
|
337
|
+
message: `Check failed: ${err instanceof Error ? err.message : String(err)}`
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
return results;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/components/DoctorApp.tsx
|
|
345
|
+
var STATUS_CONFIG = {
|
|
346
|
+
pass: { icon: "\u2713", color: "green" },
|
|
347
|
+
fail: { icon: "\u2717", color: "red" },
|
|
348
|
+
warn: { icon: "\u26A0", color: "yellow" }
|
|
349
|
+
};
|
|
350
|
+
function DiagnosticsList({ results }) {
|
|
351
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginLeft: 2 }, results.map((r) => {
|
|
352
|
+
const { icon, color } = STATUS_CONFIG[r.status];
|
|
353
|
+
return /* @__PURE__ */ React.createElement(Box, { key: r.id, flexDirection: "column" }, /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color }, icon, " "), /* @__PURE__ */ React.createElement(Text, { bold: r.status !== "pass" }, r.label), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " \u2014 ", r.message)), r.status !== "pass" && r.fixCommand && /* @__PURE__ */ React.createElement(Box, { marginLeft: 4 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "fix: "), /* @__PURE__ */ React.createElement(Text, { color: "cyan" }, r.fixCommand)), r.status !== "pass" && !r.fixCommand && r.fixDescription && /* @__PURE__ */ React.createElement(Box, { marginLeft: 4 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2192 ", r.fixDescription)));
|
|
354
|
+
}));
|
|
355
|
+
}
|
|
356
|
+
function DiagnosticsSummary({ results }) {
|
|
357
|
+
const passed = results.filter((r) => r.status === "pass").length;
|
|
358
|
+
const warned = results.filter((r) => r.status === "warn").length;
|
|
359
|
+
const failed = results.filter((r) => r.status === "fail").length;
|
|
360
|
+
return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Text, { color: "green" }, " \u2713 ", passed, " passed"), /* @__PURE__ */ React.createElement(Text, { color: "yellow" }, " \u26A0 ", warned, " warnings"), /* @__PURE__ */ React.createElement(Text, { color: "red" }, " \u2717 ", failed, " failed"), /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " (", results.length, " checks)"));
|
|
361
|
+
}
|
|
362
|
+
function DoctorApp({
|
|
363
|
+
projectPath,
|
|
364
|
+
jsonOutput,
|
|
365
|
+
isMonorepo,
|
|
366
|
+
packagePaths,
|
|
367
|
+
packageNames
|
|
368
|
+
}) {
|
|
369
|
+
const { exit } = useApp();
|
|
370
|
+
const [results, setResults] = useState([]);
|
|
371
|
+
const [packageResults, setPackageResults] = useState(
|
|
372
|
+
[]
|
|
373
|
+
);
|
|
374
|
+
const [running, setRunning] = useState(true);
|
|
375
|
+
useEffect(() => {
|
|
376
|
+
if (isMonorepo && packagePaths && packageNames) {
|
|
377
|
+
Promise.all(
|
|
378
|
+
packagePaths.map(async (pkgPath) => {
|
|
379
|
+
const name = packageNames.get(pkgPath) ?? pkgPath;
|
|
380
|
+
const r = await runDiagnostics(pkgPath);
|
|
381
|
+
return { name, path: pkgPath, results: r };
|
|
382
|
+
})
|
|
383
|
+
).then((all) => {
|
|
384
|
+
setPackageResults(all);
|
|
385
|
+
setRunning(false);
|
|
386
|
+
if (jsonOutput) {
|
|
387
|
+
const output = all.map((p) => ({
|
|
388
|
+
package: p.name,
|
|
389
|
+
path: p.path,
|
|
390
|
+
results: p.results
|
|
391
|
+
}));
|
|
392
|
+
process.stdout.write(JSON.stringify(output, null, 2) + "\n");
|
|
393
|
+
}
|
|
394
|
+
setTimeout(() => exit(), 100);
|
|
395
|
+
}).catch((err) => {
|
|
396
|
+
setPackageResults([
|
|
397
|
+
{
|
|
398
|
+
name: "error",
|
|
399
|
+
path: projectPath,
|
|
400
|
+
results: [
|
|
401
|
+
{
|
|
402
|
+
id: "error",
|
|
403
|
+
label: "Doctor",
|
|
404
|
+
status: "fail",
|
|
405
|
+
message: `Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
}
|
|
409
|
+
]);
|
|
410
|
+
setRunning(false);
|
|
411
|
+
setTimeout(() => exit(), 100);
|
|
412
|
+
});
|
|
413
|
+
} else {
|
|
414
|
+
runDiagnostics(projectPath).then((r) => {
|
|
415
|
+
setResults(r);
|
|
416
|
+
setRunning(false);
|
|
417
|
+
if (jsonOutput) {
|
|
418
|
+
process.stdout.write(JSON.stringify(r, null, 2) + "\n");
|
|
419
|
+
}
|
|
420
|
+
setTimeout(() => exit(), 100);
|
|
421
|
+
}).catch((err) => {
|
|
422
|
+
setResults([
|
|
423
|
+
{
|
|
424
|
+
id: "error",
|
|
425
|
+
label: "Doctor",
|
|
426
|
+
status: "fail",
|
|
427
|
+
message: `Failed: ${err instanceof Error ? err.message : String(err)}`
|
|
428
|
+
}
|
|
429
|
+
]);
|
|
430
|
+
setRunning(false);
|
|
431
|
+
setTimeout(() => exit(), 100);
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
}, []);
|
|
435
|
+
if (running) {
|
|
436
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Header, null), /* @__PURE__ */ React.createElement(Text, null, /* @__PURE__ */ React.createElement(Text, { color: "green" }, /* @__PURE__ */ React.createElement(Spinner, { type: "dots" })), " ", "Running project diagnostics", isMonorepo ? ` across ${packagePaths?.length} packages` : "", "..."));
|
|
437
|
+
}
|
|
438
|
+
if (jsonOutput) return null;
|
|
439
|
+
if (isMonorepo && packageResults.length > 0) {
|
|
440
|
+
const allResults = packageResults.flatMap((p) => p.results);
|
|
441
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Header, null), /* @__PURE__ */ React.createElement(Text, { bold: true }, "Monorepo Setup Diagnosis"), packageResults.map((pkg) => /* @__PURE__ */ React.createElement(Box, { key: pkg.path, flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { bold: true, color: "cyan" }, shortName(pkg.name)), /* @__PURE__ */ React.createElement(DiagnosticsList, { results: pkg.results }))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2501".repeat(52))), /* @__PURE__ */ React.createElement(DiagnosticsSummary, { results: allResults }));
|
|
442
|
+
}
|
|
443
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React.createElement(Header, null), /* @__PURE__ */ React.createElement(Text, { bold: true }, "Project Setup Diagnosis"), /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginTop: 1 }, /* @__PURE__ */ React.createElement(DiagnosticsList, { results })), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, "\u2501".repeat(52))), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(DiagnosticsSummary, { results })));
|
|
444
|
+
}
|
|
445
|
+
export {
|
|
446
|
+
DoctorApp
|
|
447
|
+
};
|