sickbay 1.12.0 → 1.13.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/{DiffApp-QTG772WX.js → DiffApp-RFUMM4XU.js} +2 -2
- package/dist/{DoctorApp-T45ZNMZQ.js → DoctorApp-7MSN36GO.js} +3 -3
- package/dist/{FixApp-P2FHGJKZ.js → FixApp-47DDF2OF.js} +3 -3
- package/dist/{StatsApp-ONUVROC5.js → StatsApp-F3CQ6W26.js} +3 -3
- package/dist/{TrendApp-OXM6QDE5.js → TrendApp-J2GF5A2Y.js} +3 -3
- package/dist/{TuiApp-6MPPK4JT.js → TuiApp-PD3L2N5U.js} +4 -4
- package/dist/{chunk-YAGUN3VM.js → chunk-KMO5PHVP.js} +1 -1
- package/dist/{chunk-YHFU2XTS.js → chunk-QZHCVNMM.js} +37 -2
- package/dist/{chunk-FEM4GJAY.js → chunk-S5UHV6SX.js} +1 -1
- package/dist/config.js +1 -1
- package/dist/{dist-FNOE2KCN.js → dist-6ZVGDRA5.js} +1 -1
- package/dist/index.js +25 -25
- package/dist/{init-JY7XQS3Q.js → init-WZUCGPVX.js} +1 -1
- package/dist/{resolve-package-U5UYD7TW.js → resolve-package-D6EHBJ5J.js} +2 -2
- package/dist/web/assets/{index-Bt4RJTHa.css → index-B23n764F.css} +1 -1
- package/dist/web/assets/{index-BuiDF5iO.js → index-BSAa6zMs.js} +7 -7
- package/dist/web/assets/index-BSAa6zMs.js.map +1 -0
- package/dist/web/index.html +2 -2
- package/dist/{web-T63BRGAM.js → web-MOY3FJJU.js} +1 -1
- package/package.json +1 -1
- package/dist/web/assets/index-BuiDF5iO.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Header
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-KMO5PHVP.js";
|
|
4
4
|
import "./chunk-JSBRDJBE.js";
|
|
5
5
|
|
|
6
6
|
// src/components/DiffApp.tsx
|
|
@@ -120,7 +120,7 @@ function DiffApp({ projectPath, branch, jsonOutput, checks, verbose }) {
|
|
|
120
120
|
useEffect(() => {
|
|
121
121
|
(async () => {
|
|
122
122
|
try {
|
|
123
|
-
const { runSickbay } = await import("./dist-
|
|
123
|
+
const { runSickbay } = await import("./dist-6ZVGDRA5.js");
|
|
124
124
|
const currentReport = await runSickbay({
|
|
125
125
|
projectPath,
|
|
126
126
|
checks,
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
shortName
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-S5UHV6SX.js";
|
|
4
4
|
import {
|
|
5
5
|
Header
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KMO5PHVP.js";
|
|
7
7
|
import {
|
|
8
8
|
detectPackageManager,
|
|
9
9
|
detectProject
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-QZHCVNMM.js";
|
|
11
11
|
import "./chunk-JSBRDJBE.js";
|
|
12
12
|
|
|
13
13
|
// src/components/DoctorApp.tsx
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
shortName
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-S5UHV6SX.js";
|
|
4
4
|
import {
|
|
5
5
|
ProgressList
|
|
6
6
|
} from "./chunk-MBVA75EM.js";
|
|
7
7
|
import {
|
|
8
8
|
Header
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KMO5PHVP.js";
|
|
10
10
|
import {
|
|
11
11
|
runSickbay
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QZHCVNMM.js";
|
|
13
13
|
import "./chunk-JSBRDJBE.js";
|
|
14
14
|
|
|
15
15
|
// src/components/FixApp.tsx
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
shortName
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-S5UHV6SX.js";
|
|
4
4
|
import {
|
|
5
5
|
Header
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KMO5PHVP.js";
|
|
7
7
|
import {
|
|
8
8
|
detectProject
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QZHCVNMM.js";
|
|
10
10
|
import "./chunk-JSBRDJBE.js";
|
|
11
11
|
|
|
12
12
|
// src/components/StatsApp.tsx
|
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
} from "./chunk-SHO3ZXTH.js";
|
|
5
5
|
import {
|
|
6
6
|
shortName
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-S5UHV6SX.js";
|
|
8
8
|
import {
|
|
9
9
|
Header
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-KMO5PHVP.js";
|
|
11
|
+
import "./chunk-QZHCVNMM.js";
|
|
12
12
|
import {
|
|
13
13
|
detectRegressions,
|
|
14
14
|
loadHistory
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
detectMonorepo,
|
|
15
15
|
runSickbay,
|
|
16
16
|
runSickbayMonorepo
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-QZHCVNMM.js";
|
|
18
18
|
import {
|
|
19
19
|
loadHistory
|
|
20
20
|
} from "./chunk-3OR2GFVE.js";
|
|
@@ -690,7 +690,7 @@ function TuiApp({
|
|
|
690
690
|
return () => timers.forEach(clearTimeout);
|
|
691
691
|
}, []);
|
|
692
692
|
useEffect7(() => {
|
|
693
|
-
checkForUpdate("1.
|
|
693
|
+
checkForUpdate("1.12.0").then((info) => {
|
|
694
694
|
if (info) setUpdateInfo(info);
|
|
695
695
|
});
|
|
696
696
|
}, []);
|
|
@@ -716,7 +716,7 @@ function TuiApp({
|
|
|
716
716
|
} catch {
|
|
717
717
|
}
|
|
718
718
|
try {
|
|
719
|
-
const { getDependencyTree } = await import("./dist-
|
|
719
|
+
const { getDependencyTree } = await import("./dist-6ZVGDRA5.js");
|
|
720
720
|
const { saveDepTree } = await import("./history-KXLC45VS.js");
|
|
721
721
|
const tree = await getDependencyTree(projectPath, result.projectInfo.packageManager);
|
|
722
722
|
saveDepTree(projectPath, tree);
|
|
@@ -820,7 +820,7 @@ function TuiApp({
|
|
|
820
820
|
const webReport = monorepoReportRef.current ?? reportRef.current;
|
|
821
821
|
if (!webReport) return;
|
|
822
822
|
try {
|
|
823
|
-
const { serveWeb } = await import("./web-
|
|
823
|
+
const { serveWeb } = await import("./web-MOY3FJJU.js");
|
|
824
824
|
const { default: openBrowser } = await import("open");
|
|
825
825
|
let aiService;
|
|
826
826
|
if (withAI && process.env.ANTHROPIC_API_KEY && !monorepoReportRef.current) {
|
|
@@ -11,7 +11,7 @@ var ASCII_ART = `
|
|
|
11
11
|
A vitals health check for your app
|
|
12
12
|
`.trim();
|
|
13
13
|
function Header({ projectName }) {
|
|
14
|
-
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "green" }, ASCII_ART), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " v", "1.
|
|
14
|
+
return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "green" }, ASCII_ART), /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " v", "1.12.0")), projectName && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " Analyzing "), /* @__PURE__ */ React.createElement(Text, { bold: true, color: "white" }, projectName)));
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export {
|
|
@@ -2796,6 +2796,7 @@ var AngularChangeDetectionRunner = class extends BaseRunner {
|
|
|
2796
2796
|
severity: "warning",
|
|
2797
2797
|
message: `${file} \u2014 component missing OnPush change detection`,
|
|
2798
2798
|
file,
|
|
2799
|
+
suppressMatch: file,
|
|
2799
2800
|
fix: {
|
|
2800
2801
|
description: "Add `changeDetection: ChangeDetectionStrategy.OnPush` to the @Component decorator to prevent unnecessary re-renders."
|
|
2801
2802
|
},
|
|
@@ -2902,6 +2903,7 @@ var AngularLazyRoutesRunner = class extends BaseRunner {
|
|
|
2902
2903
|
severity: "warning",
|
|
2903
2904
|
message: `${relPath}:${i + 1} \u2014 static route component import; consider lazy loading`,
|
|
2904
2905
|
file: relPath,
|
|
2906
|
+
suppressMatch: relPath,
|
|
2905
2907
|
fix: {
|
|
2906
2908
|
description: "Replace `component: MyComponent` with `loadComponent: () => import('./my.component').then(m => m.MyComponent)` to enable route-level code splitting."
|
|
2907
2909
|
},
|
|
@@ -2996,6 +2998,7 @@ var AngularSecurityRunner = class extends BaseRunner {
|
|
|
2996
2998
|
severity: "warning",
|
|
2997
2999
|
message: `${relPath}:${i + 1} \u2014 DomSanitizer ${method.slice(0, -1)}() bypasses XSS protection`,
|
|
2998
3000
|
file: relPath,
|
|
3001
|
+
suppressMatch: relPath,
|
|
2999
3002
|
fix: {
|
|
3000
3003
|
description: "Avoid bypassing Angular's built-in sanitization. Use safe values or sanitize input before rendering."
|
|
3001
3004
|
},
|
|
@@ -3008,6 +3011,7 @@ var AngularSecurityRunner = class extends BaseRunner {
|
|
|
3008
3011
|
severity: "warning",
|
|
3009
3012
|
message: `${relPath}:${i + 1} \u2014 [innerHTML] binding is a potential XSS vector if content is user-controlled`,
|
|
3010
3013
|
file: relPath,
|
|
3014
|
+
suppressMatch: relPath,
|
|
3011
3015
|
fix: {
|
|
3012
3016
|
description: "Prefer Angular's built-in text interpolation or use DomSanitizer explicitly when innerHTML is required."
|
|
3013
3017
|
},
|
|
@@ -3189,6 +3193,7 @@ var AngularSubscriptionsRunner = class extends BaseRunner {
|
|
|
3189
3193
|
severity: "warning",
|
|
3190
3194
|
message: `${file} \u2014 possible unguarded subscription (no takeUntilDestroyed, takeUntil, or ngOnDestroy found)`,
|
|
3191
3195
|
file,
|
|
3196
|
+
suppressMatch: file,
|
|
3192
3197
|
fix: {
|
|
3193
3198
|
description: "Use `takeUntilDestroyed()` from `@angular/core/rxjs-interop` or call `.unsubscribe()` in `ngOnDestroy` to prevent memory leaks."
|
|
3194
3199
|
},
|
|
@@ -3311,6 +3316,7 @@ function checkNgForTrackBy(template, relPath, issues) {
|
|
|
3311
3316
|
severity: "warning",
|
|
3312
3317
|
message: `${relPath} \u2014 *ngFor without trackBy causes full list re-renders on any array change`,
|
|
3313
3318
|
file: relPath,
|
|
3319
|
+
suppressMatch: relPath,
|
|
3314
3320
|
fix: {
|
|
3315
3321
|
description: 'Add a trackBy function to the *ngFor directive (e.g. *ngFor="let item of items; trackBy: trackById").'
|
|
3316
3322
|
},
|
|
@@ -3329,6 +3335,7 @@ function checkForTrack(template, relPath, issues) {
|
|
|
3329
3335
|
severity: "warning",
|
|
3330
3336
|
message: `${relPath} \u2014 @for without track expression causes full list re-renders`,
|
|
3331
3337
|
file: relPath,
|
|
3338
|
+
suppressMatch: relPath,
|
|
3332
3339
|
fix: {
|
|
3333
3340
|
description: "Add a track expression to the @for block (e.g. @for (item of items; track item.id))."
|
|
3334
3341
|
},
|
|
@@ -3345,8 +3352,9 @@ function checkFunctionCalls(template, relPath, issues) {
|
|
|
3345
3352
|
if (fnName === "$any" || fnName === "$event") continue;
|
|
3346
3353
|
issues.push({
|
|
3347
3354
|
severity: "warning",
|
|
3348
|
-
message: `${relPath} \u2014 function call {
|
|
3355
|
+
message: `${relPath} \u2014 function call \`${fnName}()\` in template re-runs on every change detection cycle`,
|
|
3349
3356
|
file: relPath,
|
|
3357
|
+
suppressMatch: relPath,
|
|
3350
3358
|
fix: {
|
|
3351
3359
|
description: "Replace the function call with a pre-computed property, a pipe, or use memoization to avoid re-execution on every change detection cycle."
|
|
3352
3360
|
},
|
|
@@ -3359,8 +3367,9 @@ function checkFunctionCalls(template, relPath, issues) {
|
|
|
3359
3367
|
if (fnName === "$any" || fnName === "$event") continue;
|
|
3360
3368
|
issues.push({
|
|
3361
3369
|
severity: "warning",
|
|
3362
|
-
message: `${relPath} \u2014 function call
|
|
3370
|
+
message: `${relPath} \u2014 function call \`${fnName}()\` in property binding re-runs on every change detection cycle`,
|
|
3363
3371
|
file: relPath,
|
|
3372
|
+
suppressMatch: relPath,
|
|
3364
3373
|
fix: {
|
|
3365
3374
|
description: "Replace the function call with a pre-computed property, a pipe, or use memoization to avoid re-execution on every change detection cycle."
|
|
3366
3375
|
},
|
|
@@ -3437,6 +3446,7 @@ var AssetSizeRunner = class extends BaseRunner {
|
|
|
3437
3446
|
issues.push({
|
|
3438
3447
|
severity: "critical",
|
|
3439
3448
|
message: `${asset.path} \u2014 ${sizeMB}MB image (exceeds 2MB)`,
|
|
3449
|
+
suppressMatch: asset.path,
|
|
3440
3450
|
file: asset.path,
|
|
3441
3451
|
fix: {
|
|
3442
3452
|
description: "Compress with tools like squoosh.app, tinypng.com, or convert to WebP/AVIF format"
|
|
@@ -3447,6 +3457,7 @@ var AssetSizeRunner = class extends BaseRunner {
|
|
|
3447
3457
|
issues.push({
|
|
3448
3458
|
severity: "warning",
|
|
3449
3459
|
message: `${asset.path} \u2014 ${sizeKB}KB image (exceeds 500KB)`,
|
|
3460
|
+
suppressMatch: asset.path,
|
|
3450
3461
|
file: asset.path,
|
|
3451
3462
|
fix: { description: "Compress or convert to a more efficient format (WebP, AVIF)" },
|
|
3452
3463
|
reportedBy: ["asset-size"]
|
|
@@ -3457,6 +3468,7 @@ var AssetSizeRunner = class extends BaseRunner {
|
|
|
3457
3468
|
issues.push({
|
|
3458
3469
|
severity: "warning",
|
|
3459
3470
|
message: `${asset.path} \u2014 ${sizeKB}KB SVG (exceeds 100KB, likely unoptimized)`,
|
|
3471
|
+
suppressMatch: asset.path,
|
|
3460
3472
|
file: asset.path,
|
|
3461
3473
|
fix: {
|
|
3462
3474
|
description: "Optimize with SVGO or svgomg.net \u2014 remove metadata, simplify paths"
|
|
@@ -3469,6 +3481,7 @@ var AssetSizeRunner = class extends BaseRunner {
|
|
|
3469
3481
|
issues.push({
|
|
3470
3482
|
severity: "warning",
|
|
3471
3483
|
message: `${asset.path} \u2014 ${sizeKB}KB font (exceeds 500KB)`,
|
|
3484
|
+
suppressMatch: asset.path,
|
|
3472
3485
|
file: asset.path,
|
|
3473
3486
|
fix: {
|
|
3474
3487
|
description: "Subset the font to include only needed characters, or use WOFF2 format"
|
|
@@ -3673,6 +3686,7 @@ var ComplexityRunner = class extends BaseRunner {
|
|
|
3673
3686
|
issues.push({
|
|
3674
3687
|
severity: f.lines >= critical ? "warning" : "info",
|
|
3675
3688
|
message: `${f.path} (${label}): ${f.lines} lines \u2014 consider splitting (threshold: ${warn})`,
|
|
3689
|
+
suppressMatch: f.path,
|
|
3676
3690
|
fix: { description: "Extract concerns into smaller, focused files" },
|
|
3677
3691
|
reportedBy: ["complexity"]
|
|
3678
3692
|
});
|
|
@@ -4146,6 +4160,7 @@ var DepcheckRunner = class extends BaseRunner {
|
|
|
4146
4160
|
issues.push({
|
|
4147
4161
|
severity: "critical",
|
|
4148
4162
|
message: `Missing dependency: ${dep} (used in ${files.length} file${files.length > 1 ? "s" : ""})`,
|
|
4163
|
+
suppressMatch: dep,
|
|
4149
4164
|
fix: { description: `Install ${dep}` },
|
|
4150
4165
|
reportedBy: ["depcheck"]
|
|
4151
4166
|
});
|
|
@@ -4219,6 +4234,7 @@ var ESLintRunner = class extends BaseRunner {
|
|
|
4219
4234
|
issues.push({
|
|
4220
4235
|
severity: file.errorCount > 0 ? "warning" : "info",
|
|
4221
4236
|
message: `${relPath}: ${parts.join(", ")}`,
|
|
4237
|
+
suppressMatch: relPath,
|
|
4222
4238
|
fix: {
|
|
4223
4239
|
description: `Fix ESLint issues in ${relPath}`,
|
|
4224
4240
|
command: `eslint ${relPath} --fix`,
|
|
@@ -4447,6 +4463,7 @@ var HeavyDepsRunner = class extends BaseRunner {
|
|
|
4447
4463
|
const issues = found.map((f) => ({
|
|
4448
4464
|
severity: f.info.severity,
|
|
4449
4465
|
message: `${f.name} \u2014 ${f.info.reason}`,
|
|
4466
|
+
suppressMatch: f.name,
|
|
4450
4467
|
fix: {
|
|
4451
4468
|
description: `Consider replacing with ${f.info.alternative}`
|
|
4452
4469
|
},
|
|
@@ -4604,6 +4621,7 @@ var KnipRunner = class extends BaseRunner {
|
|
|
4604
4621
|
issues.push({
|
|
4605
4622
|
severity: "warning",
|
|
4606
4623
|
message: `Unused file: ${filePath}`,
|
|
4624
|
+
suppressMatch: filePath,
|
|
4607
4625
|
file: filePath,
|
|
4608
4626
|
fix: { description: `Remove ${filePath}` },
|
|
4609
4627
|
reportedBy: ["knip"]
|
|
@@ -4626,6 +4644,7 @@ var KnipRunner = class extends BaseRunner {
|
|
|
4626
4644
|
(dep) => issues.push({
|
|
4627
4645
|
severity: "warning",
|
|
4628
4646
|
message: `Unused dependency: ${dep}`,
|
|
4647
|
+
suppressMatch: dep,
|
|
4629
4648
|
fix: { description: `Remove ${dep}` },
|
|
4630
4649
|
reportedBy: ["knip"]
|
|
4631
4650
|
})
|
|
@@ -4634,6 +4653,7 @@ var KnipRunner = class extends BaseRunner {
|
|
|
4634
4653
|
(dep) => issues.push({
|
|
4635
4654
|
severity: "info",
|
|
4636
4655
|
message: `Unused devDependency: ${dep}`,
|
|
4656
|
+
suppressMatch: dep,
|
|
4637
4657
|
fix: { description: `Remove ${dep}` },
|
|
4638
4658
|
reportedBy: ["knip"]
|
|
4639
4659
|
})
|
|
@@ -4642,6 +4662,7 @@ var KnipRunner = class extends BaseRunner {
|
|
|
4642
4662
|
(exp) => issues.push({
|
|
4643
4663
|
severity: "info",
|
|
4644
4664
|
message: `Unused export: ${exp}`,
|
|
4665
|
+
suppressMatch: exp,
|
|
4645
4666
|
reportedBy: ["knip"]
|
|
4646
4667
|
})
|
|
4647
4668
|
);
|
|
@@ -4711,6 +4732,7 @@ var LicenseCheckerRunner = class extends BaseRunner {
|
|
|
4711
4732
|
issues.push({
|
|
4712
4733
|
severity: "warning",
|
|
4713
4734
|
message: `${pkg} uses ${license} license \u2014 may be incompatible with commercial use`,
|
|
4735
|
+
suppressMatch: pkg.lastIndexOf("@") > 0 ? pkg.slice(0, pkg.lastIndexOf("@")) : pkg,
|
|
4714
4736
|
fix: { description: `Review or replace ${pkg.split("@")[0]}` },
|
|
4715
4737
|
reportedBy: ["license-checker"]
|
|
4716
4738
|
});
|
|
@@ -4812,6 +4834,7 @@ var MadgeRunner = class extends BaseRunner {
|
|
|
4812
4834
|
const issues = circles.map((cycle) => ({
|
|
4813
4835
|
severity: "warning",
|
|
4814
4836
|
message: `Circular dependency: ${cycle.join(" \u2192 ")}`,
|
|
4837
|
+
suppressMatch: cycle[0],
|
|
4815
4838
|
fix: { description: "Refactor to break the circular dependency cycle" },
|
|
4816
4839
|
reportedBy: ["madge"]
|
|
4817
4840
|
}));
|
|
@@ -4871,6 +4894,7 @@ var NextClientComponentsRunner = class extends BaseRunner {
|
|
|
4871
4894
|
severity: "warning",
|
|
4872
4895
|
message: `${file} \u2014 may not need 'use client' (no hooks or event handlers detected)`,
|
|
4873
4896
|
file,
|
|
4897
|
+
suppressMatch: file,
|
|
4874
4898
|
fix: {
|
|
4875
4899
|
description: "This component may not need 'use client' \u2014 it contains no hooks or event handlers. Moving it to a Server Component reduces client bundle size."
|
|
4876
4900
|
},
|
|
@@ -4970,6 +4994,7 @@ var NextFontsRunner = class extends BaseRunner {
|
|
|
4970
4994
|
severity: "warning",
|
|
4971
4995
|
message: `${layoutPath} \u2014 Google Fonts loaded via external stylesheet; use next/font/google`,
|
|
4972
4996
|
file: layoutPath,
|
|
4997
|
+
suppressMatch: layoutPath,
|
|
4973
4998
|
fix: {
|
|
4974
4999
|
description: "Use next/font/google instead of a <link> stylesheet to self-host fonts and improve Core Web Vitals (eliminates render-blocking request)."
|
|
4975
5000
|
},
|
|
@@ -5030,6 +5055,7 @@ var NextImagesRunner = class extends BaseRunner {
|
|
|
5030
5055
|
severity: "warning",
|
|
5031
5056
|
message: `${file} \u2014 raw image element; use next/image for automatic optimization`,
|
|
5032
5057
|
file,
|
|
5058
|
+
suppressMatch: file,
|
|
5033
5059
|
fix: {
|
|
5034
5060
|
description: "Replace <img> with the <Image> component from next/image for automatic optimization, lazy loading, and Core Web Vitals improvements."
|
|
5035
5061
|
},
|
|
@@ -5116,6 +5142,7 @@ var NextLinkRunner = class extends BaseRunner {
|
|
|
5116
5142
|
severity: "warning",
|
|
5117
5143
|
message: `${file} \u2014 raw anchor tag for internal navigation; use next/link`,
|
|
5118
5144
|
file,
|
|
5145
|
+
suppressMatch: file,
|
|
5119
5146
|
fix: {
|
|
5120
5147
|
description: 'Replace <a href="/path"> with <Link href="/path"> from next/link to enable client-side navigation and prefetching.'
|
|
5121
5148
|
},
|
|
@@ -5203,6 +5230,7 @@ var NextMissingBoundariesRunner = class extends BaseRunner {
|
|
|
5203
5230
|
issues.push({
|
|
5204
5231
|
severity: "info",
|
|
5205
5232
|
message: `${relDir} \u2014 missing loading.tsx (Suspense boundary for this route segment)`,
|
|
5233
|
+
suppressMatch: relDir,
|
|
5206
5234
|
fix: {
|
|
5207
5235
|
description: "Add loading.tsx to show a skeleton UI while this route's data loads (App Router Suspense boundary)."
|
|
5208
5236
|
},
|
|
@@ -5214,6 +5242,7 @@ var NextMissingBoundariesRunner = class extends BaseRunner {
|
|
|
5214
5242
|
issues.push({
|
|
5215
5243
|
severity: "info",
|
|
5216
5244
|
message: `${relDir} \u2014 missing error.tsx (error boundary for this route segment)`,
|
|
5245
|
+
suppressMatch: relDir,
|
|
5217
5246
|
fix: {
|
|
5218
5247
|
description: "Add error.tsx with 'use client' to gracefully handle errors in this route segment."
|
|
5219
5248
|
},
|
|
@@ -5783,6 +5812,7 @@ function parseNpmAudit(data) {
|
|
|
5783
5812
|
issues.push({
|
|
5784
5813
|
severity: vuln.severity === "critical" || vuln.severity === "high" ? "critical" : "warning",
|
|
5785
5814
|
message: formatAuditMessage(vuln.name, title, url),
|
|
5815
|
+
suppressMatch: vuln.name,
|
|
5786
5816
|
fix: typeof vuln.fixAvailable === "object" ? { description: `Upgrade to ${vuln.fixAvailable.name}@${vuln.fixAvailable.version}` } : { description: "No automatic fix available" },
|
|
5787
5817
|
reportedBy: ["npm-audit"],
|
|
5788
5818
|
...url && { file: url }
|
|
@@ -5805,6 +5835,7 @@ function parsePnpmAudit(data, projectPath) {
|
|
|
5805
5835
|
advisory.title || `Vulnerability in ${pkgName}`,
|
|
5806
5836
|
advisory.url
|
|
5807
5837
|
),
|
|
5838
|
+
suppressMatch: pkgName,
|
|
5808
5839
|
fix: advisory.recommendation ? { description: advisory.recommendation } : { description: "No automatic fix available" },
|
|
5809
5840
|
reportedBy: ["npm-audit"],
|
|
5810
5841
|
...advisory.url && { file: advisory.url }
|
|
@@ -5867,6 +5898,7 @@ var OutdatedRunner = class extends BaseRunner {
|
|
|
5867
5898
|
return {
|
|
5868
5899
|
severity: isMajor ? "warning" : "info",
|
|
5869
5900
|
message: `${e.name}: ${e.current} \u2192 ${e.latest} (${updateType})`,
|
|
5901
|
+
suppressMatch: e.name,
|
|
5870
5902
|
fix: isMajor ? {
|
|
5871
5903
|
description: `Update ${e.name} to ${e.latest} (major \u2014 review changelog before upgrading)`
|
|
5872
5904
|
} : {
|
|
@@ -5960,6 +5992,7 @@ var ReactPerfRunner = class extends BaseRunner {
|
|
|
5960
5992
|
severity: f.severity,
|
|
5961
5993
|
message: f.line > 0 ? `${f.file}:${f.line} \u2014 ${f.pattern}` : `${f.file} \u2014 ${f.pattern}`,
|
|
5962
5994
|
file: f.file,
|
|
5995
|
+
suppressMatch: f.file,
|
|
5963
5996
|
fix: { description: getFixDescription(f.pattern) },
|
|
5964
5997
|
reportedBy: ["react-perf"]
|
|
5965
5998
|
}));
|
|
@@ -6190,6 +6223,7 @@ var SecretsRunner = class extends BaseRunner {
|
|
|
6190
6223
|
const issues = findings.map((f) => ({
|
|
6191
6224
|
severity: "critical",
|
|
6192
6225
|
message: f.line > 0 ? `${f.file}:${f.line} \u2014 ${f.pattern} detected` : `${f.file} \u2014 ${f.pattern}`,
|
|
6226
|
+
suppressMatch: f.pattern,
|
|
6193
6227
|
file: f.file,
|
|
6194
6228
|
fix: {
|
|
6195
6229
|
description: "Move secrets to environment variables",
|
|
@@ -6488,6 +6522,7 @@ var TodoScannerRunner = class extends BaseRunner {
|
|
|
6488
6522
|
const issues = todos.map((t) => ({
|
|
6489
6523
|
severity: t.kind === "FIXME" || t.kind === "HACK" ? "warning" : "info",
|
|
6490
6524
|
message: `${t.file}:${t.line} \u2014 ${t.kind}: ${t.text || "(no description)"}`,
|
|
6525
|
+
suppressMatch: t.file,
|
|
6491
6526
|
reportedBy: ["todo-scanner"]
|
|
6492
6527
|
}));
|
|
6493
6528
|
const fixmeCount = todos.filter((t) => t.kind === "FIXME" || t.kind === "HACK").length;
|
package/dist/config.js
CHANGED
package/dist/index.js
CHANGED
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
} from "./chunk-TYG7ZQBP.js";
|
|
9
9
|
import {
|
|
10
10
|
Header
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-KMO5PHVP.js";
|
|
12
12
|
import {
|
|
13
13
|
getScoreEmoji,
|
|
14
14
|
runSickbay,
|
|
15
15
|
runSickbayMonorepo
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-QZHCVNMM.js";
|
|
17
17
|
import "./chunk-JSBRDJBE.js";
|
|
18
18
|
|
|
19
19
|
// src/index.ts
|
|
@@ -177,7 +177,7 @@ function App({
|
|
|
177
177
|
setMonorepoReport(r);
|
|
178
178
|
setProjectName(`monorepo (${r.packages.length} packages)`);
|
|
179
179
|
try {
|
|
180
|
-
const { getDependencyTree } = await import("./dist-
|
|
180
|
+
const { getDependencyTree } = await import("./dist-6ZVGDRA5.js");
|
|
181
181
|
const { saveDepTree } = await import("./history-KXLC45VS.js");
|
|
182
182
|
const packages = {};
|
|
183
183
|
for (const pkg of r.packages) {
|
|
@@ -189,7 +189,7 @@ function App({
|
|
|
189
189
|
if (openWeb) {
|
|
190
190
|
setPhase("opening-web");
|
|
191
191
|
try {
|
|
192
|
-
const { serveWeb } = await import("./web-
|
|
192
|
+
const { serveWeb } = await import("./web-MOY3FJJU.js");
|
|
193
193
|
const { default: openBrowser } = await import("open");
|
|
194
194
|
let aiService;
|
|
195
195
|
if (enableAI && process.env.ANTHROPIC_API_KEY) {
|
|
@@ -246,7 +246,7 @@ function App({
|
|
|
246
246
|
} catch {
|
|
247
247
|
}
|
|
248
248
|
try {
|
|
249
|
-
const { getDependencyTree } = await import("./dist-
|
|
249
|
+
const { getDependencyTree } = await import("./dist-6ZVGDRA5.js");
|
|
250
250
|
const { saveDepTree } = await import("./history-KXLC45VS.js");
|
|
251
251
|
const tree = await getDependencyTree(projectPath, r.projectInfo.packageManager);
|
|
252
252
|
saveDepTree(projectPath, tree);
|
|
@@ -255,7 +255,7 @@ function App({
|
|
|
255
255
|
if (openWeb) {
|
|
256
256
|
setPhase("opening-web");
|
|
257
257
|
try {
|
|
258
|
-
const { serveWeb } = await import("./web-
|
|
258
|
+
const { serveWeb } = await import("./web-MOY3FJJU.js");
|
|
259
259
|
const { default: openBrowser } = await import("open");
|
|
260
260
|
let aiService;
|
|
261
261
|
if (enableAI && process.env.ANTHROPIC_API_KEY) {
|
|
@@ -304,7 +304,7 @@ if (existsSync(globalConfigPath)) {
|
|
|
304
304
|
}
|
|
305
305
|
config({ debug: false, quiet: true });
|
|
306
306
|
var program = new Command();
|
|
307
|
-
program.name("sickbay").description("React project health check CLI").version("1.
|
|
307
|
+
program.name("sickbay").description("React project health check CLI").version("1.12.0", "-v, --version").enablePositionalOptions().passThroughOptions().option("-p, --path <path>", "project path to analyze", process.cwd()).option("-c, --checks <checks>", "comma-separated list of checks to run").option("--package <name>", "scope to a single named package (monorepo only)").option("--json", "output raw JSON report").option("--web", "open web dashboard after scan").option("--no-ai", "disable AI features").option("--no-quotes", "suppress personality quotes in output").option("--verbose", "show verbose output").action(async (options) => {
|
|
308
308
|
if (options.path && options.path !== process.cwd()) {
|
|
309
309
|
const projectEnvPath = join(options.path, ".env");
|
|
310
310
|
if (existsSync(projectEnvPath)) {
|
|
@@ -314,13 +314,13 @@ program.name("sickbay").description("React project health check CLI").version("1
|
|
|
314
314
|
const updatePromise = (async () => {
|
|
315
315
|
try {
|
|
316
316
|
const { checkForUpdate } = await import("./update-check-QLG6GA4Z.js");
|
|
317
|
-
return await checkForUpdate("1.
|
|
317
|
+
return await checkForUpdate("1.12.0");
|
|
318
318
|
} catch {
|
|
319
319
|
return null;
|
|
320
320
|
}
|
|
321
321
|
})();
|
|
322
322
|
const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
|
|
323
|
-
const { detectMonorepo, runSickbay: runSickbay2, runSickbayMonorepo: runSickbayMonorepo2 } = await import("./dist-
|
|
323
|
+
const { detectMonorepo, runSickbay: runSickbay2, runSickbayMonorepo: runSickbayMonorepo2 } = await import("./dist-6ZVGDRA5.js");
|
|
324
324
|
const monorepoInfo = await detectMonorepo(options.path);
|
|
325
325
|
if (options.package && monorepoInfo.isMonorepo) {
|
|
326
326
|
const { readFileSync } = await import("fs");
|
|
@@ -384,7 +384,7 @@ program.name("sickbay").description("React project health check CLI").version("1
|
|
|
384
384
|
} catch {
|
|
385
385
|
}
|
|
386
386
|
try {
|
|
387
|
-
const { getDependencyTree } = await import("./dist-
|
|
387
|
+
const { getDependencyTree } = await import("./dist-6ZVGDRA5.js");
|
|
388
388
|
const { saveDepTree } = await import("./history-KXLC45VS.js");
|
|
389
389
|
const tree = await getDependencyTree(options.path, report.projectInfo.packageManager);
|
|
390
390
|
saveDepTree(options.path, tree);
|
|
@@ -411,16 +411,16 @@ program.command("init").description("Initialize .sickbay/ folder and run an init
|
|
|
411
411
|
"add newly available checks to existing config without touching existing entries"
|
|
412
412
|
).option("--reset-config", "regenerate config from scratch (overwrites existing)").action(async (options) => {
|
|
413
413
|
if (options.resetConfig) {
|
|
414
|
-
const { generateConfigFile } = await import("./init-
|
|
414
|
+
const { generateConfigFile } = await import("./init-WZUCGPVX.js");
|
|
415
415
|
await generateConfigFile(options.path, { force: true });
|
|
416
416
|
return;
|
|
417
417
|
}
|
|
418
418
|
if (options.sync) {
|
|
419
|
-
const { syncConfigFile } = await import("./init-
|
|
419
|
+
const { syncConfigFile } = await import("./init-WZUCGPVX.js");
|
|
420
420
|
await syncConfigFile(options.path);
|
|
421
421
|
return;
|
|
422
422
|
}
|
|
423
|
-
const { initSickbay } = await import("./init-
|
|
423
|
+
const { initSickbay } = await import("./init-WZUCGPVX.js");
|
|
424
424
|
await initSickbay(options.path);
|
|
425
425
|
});
|
|
426
426
|
program.command("fix").description("Interactively fix issues found by sickbay scan").option("-p, --path <path>", "project path to analyze", process.cwd()).option("-c, --checks <checks>", "comma-separated list of checks to run").option("--package <name>", "scope to a single package (monorepo only)").option("--all", "apply all available fixes without prompting").option("--dry-run", "show what would be fixed without executing").option("--verbose", "show verbose output").action(async (options) => {
|
|
@@ -430,9 +430,9 @@ program.command("fix").description("Interactively fix issues found by sickbay sc
|
|
|
430
430
|
config({ path: projectEnvPath, override: true });
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
|
-
const { resolveProject } = await import("./resolve-package-
|
|
433
|
+
const { resolveProject } = await import("./resolve-package-D6EHBJ5J.js");
|
|
434
434
|
const resolution = await resolveProject(options.path, options.package);
|
|
435
|
-
const { FixApp } = await import("./FixApp-
|
|
435
|
+
const { FixApp } = await import("./FixApp-47DDF2OF.js");
|
|
436
436
|
const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
|
|
437
437
|
const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
|
|
438
438
|
render(
|
|
@@ -455,10 +455,10 @@ program.command("trend").description("Show score history and trends over time").
|
|
|
455
455
|
config({ path: projectEnvPath, override: true });
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
|
-
const { resolveProject } = await import("./resolve-package-
|
|
458
|
+
const { resolveProject } = await import("./resolve-package-D6EHBJ5J.js");
|
|
459
459
|
const resolution = await resolveProject(options.path, options.package);
|
|
460
460
|
const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
|
|
461
|
-
const { TrendApp } = await import("./TrendApp-
|
|
461
|
+
const { TrendApp } = await import("./TrendApp-J2GF5A2Y.js");
|
|
462
462
|
render(
|
|
463
463
|
React6.createElement(TrendApp, {
|
|
464
464
|
projectPath,
|
|
@@ -477,10 +477,10 @@ program.command("stats").description("Show a quick codebase overview and project
|
|
|
477
477
|
config({ path: projectEnvPath, override: true });
|
|
478
478
|
}
|
|
479
479
|
}
|
|
480
|
-
const { resolveProject } = await import("./resolve-package-
|
|
480
|
+
const { resolveProject } = await import("./resolve-package-D6EHBJ5J.js");
|
|
481
481
|
const resolution = await resolveProject(options.path, options.package);
|
|
482
482
|
const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
|
|
483
|
-
const { StatsApp } = await import("./StatsApp-
|
|
483
|
+
const { StatsApp } = await import("./StatsApp-F3CQ6W26.js");
|
|
484
484
|
render(
|
|
485
485
|
React6.createElement(StatsApp, {
|
|
486
486
|
projectPath,
|
|
@@ -492,7 +492,7 @@ program.command("stats").description("Show a quick codebase overview and project
|
|
|
492
492
|
);
|
|
493
493
|
});
|
|
494
494
|
program.command("tui").description("Launch the persistent developer dashboard").option("-p, --path <path>", "project path to monitor", process.cwd()).option("--no-watch", "disable file-watching auto-refresh").option("--no-quotes", "suppress personality quotes in output").option("--refresh <seconds>", "auto-refresh interval in seconds", "300").option("-c, --checks <checks>", "comma-separated list of checks to run").action(async (options) => {
|
|
495
|
-
const { TuiApp } = await import("./TuiApp-
|
|
495
|
+
const { TuiApp } = await import("./TuiApp-PD3L2N5U.js");
|
|
496
496
|
const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
|
|
497
497
|
render(
|
|
498
498
|
React6.createElement(TuiApp, {
|
|
@@ -512,10 +512,10 @@ program.command("doctor").description("Diagnose project setup and configuration
|
|
|
512
512
|
config({ path: projectEnvPath, override: true });
|
|
513
513
|
}
|
|
514
514
|
}
|
|
515
|
-
const { resolveProject } = await import("./resolve-package-
|
|
515
|
+
const { resolveProject } = await import("./resolve-package-D6EHBJ5J.js");
|
|
516
516
|
const resolution = await resolveProject(options.path, options.package);
|
|
517
517
|
const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
|
|
518
|
-
const { DoctorApp } = await import("./DoctorApp-
|
|
518
|
+
const { DoctorApp } = await import("./DoctorApp-7MSN36GO.js");
|
|
519
519
|
render(
|
|
520
520
|
React6.createElement(DoctorApp, {
|
|
521
521
|
projectPath,
|
|
@@ -528,13 +528,13 @@ program.command("doctor").description("Diagnose project setup and configuration
|
|
|
528
528
|
);
|
|
529
529
|
});
|
|
530
530
|
program.command("badge").description("Generate a health score badge for your README").option("-p, --path <path>", "project path", process.cwd()).option("--package <name>", "scope to a single package (monorepo only)").option("--html", "output HTML <img> tag instead of markdown").option("--url", "output bare badge URL only").option("--label <text>", "custom badge label", "sickbay").option("--scan", "run a fresh scan instead of using last report").action(async (options) => {
|
|
531
|
-
const { resolveProject } = await import("./resolve-package-
|
|
531
|
+
const { resolveProject } = await import("./resolve-package-D6EHBJ5J.js");
|
|
532
532
|
const resolution = await resolveProject(options.path, options.package);
|
|
533
533
|
const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
|
|
534
534
|
const { loadScoreFromLastReport, badgeUrl, badgeMarkdown, badgeHtml } = await import("./badge-AO2FZVHJ.js");
|
|
535
535
|
let score = options.scan ? null : loadScoreFromLastReport(projectPath);
|
|
536
536
|
if (score === null) {
|
|
537
|
-
const { runSickbay: runSickbay2 } = await import("./dist-
|
|
537
|
+
const { runSickbay: runSickbay2 } = await import("./dist-6ZVGDRA5.js");
|
|
538
538
|
const report = await runSickbay2({ projectPath, quotes: false });
|
|
539
539
|
try {
|
|
540
540
|
const { saveEntry, saveLastReport } = await import("./history-KXLC45VS.js");
|
|
@@ -563,7 +563,7 @@ program.command("diff <branch>").description("Compare health score against anoth
|
|
|
563
563
|
}
|
|
564
564
|
}
|
|
565
565
|
const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
|
|
566
|
-
const { DiffApp } = await import("./DiffApp-
|
|
566
|
+
const { DiffApp } = await import("./DiffApp-RFUMM4XU.js");
|
|
567
567
|
render(
|
|
568
568
|
React6.createElement(DiffApp, {
|
|
569
569
|
projectPath: options.path,
|