sickbay 1.15.3 → 1.15.4

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 CHANGED
@@ -1,6 +1,6 @@
1
- # @nebulord/sickbay
1
+ # sickbay
2
2
 
3
- The terminal interface for Sickbay. Built with [Ink](https://github.com/vadimdemedes/ink) (React for terminals) and [Commander](https://github.com/tj/commander.js).
3
+ The terminal interface for Sickbay. Published to npm as the unscoped `sickbay` package. Built with [Ink](https://github.com/vadimdemedes/ink) (React for terminals) and [Commander](https://github.com/tj/commander.js).
4
4
 
5
5
  ## Quickstart
6
6
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Header
3
- } from "./chunk-O23F4LLA.js";
3
+ } from "./chunk-PD5OA3SZ.js";
4
4
 
5
5
  // src/components/DiffApp.tsx
6
6
  import React, { useState, useEffect } from "react";
@@ -119,7 +119,7 @@ function DiffApp({ projectPath, branch, jsonOutput, checks, verbose }) {
119
119
  useEffect(() => {
120
120
  (async () => {
121
121
  try {
122
- const { runSickbay } = await import("./dist-CEJKDCQM.js");
122
+ const { runSickbay } = await import("./dist-G7GDVJT5.js");
123
123
  const currentReport = await runSickbay({
124
124
  projectPath,
125
125
  checks,
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  shortName
3
- } from "./chunk-QAVKOJFG.js";
3
+ } from "./chunk-MCHTDD7R.js";
4
4
  import {
5
5
  Header
6
- } from "./chunk-O23F4LLA.js";
6
+ } from "./chunk-PD5OA3SZ.js";
7
7
  import {
8
8
  detectPackageManager,
9
9
  detectProject
10
- } from "./chunk-BI2RMQIV.js";
10
+ } from "./chunk-WEGMDILT.js";
11
11
 
12
12
  // src/components/DoctorApp.tsx
13
13
  import React, { useState, useEffect } from "react";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  shortName
3
- } from "./chunk-QAVKOJFG.js";
3
+ } from "./chunk-MCHTDD7R.js";
4
4
  import {
5
5
  ProgressList
6
6
  } from "./chunk-MBVA75EM.js";
7
7
  import {
8
8
  Header
9
- } from "./chunk-O23F4LLA.js";
9
+ } from "./chunk-PD5OA3SZ.js";
10
10
  import {
11
11
  runSickbay
12
- } from "./chunk-BI2RMQIV.js";
12
+ } from "./chunk-WEGMDILT.js";
13
13
 
14
14
  // src/components/FixApp.tsx
15
15
  import React, { useState, useEffect, useCallback } from "react";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  shortName
3
- } from "./chunk-QAVKOJFG.js";
3
+ } from "./chunk-MCHTDD7R.js";
4
4
  import {
5
5
  Header
6
- } from "./chunk-O23F4LLA.js";
6
+ } from "./chunk-PD5OA3SZ.js";
7
7
  import {
8
8
  detectProject
9
- } from "./chunk-BI2RMQIV.js";
9
+ } from "./chunk-WEGMDILT.js";
10
10
 
11
11
  // src/components/StatsApp.tsx
12
12
  import React, { useState, useEffect } from "react";
@@ -4,11 +4,11 @@ import {
4
4
  } from "./chunk-SHO3ZXTH.js";
5
5
  import {
6
6
  shortName
7
- } from "./chunk-QAVKOJFG.js";
7
+ } from "./chunk-MCHTDD7R.js";
8
8
  import {
9
9
  Header
10
- } from "./chunk-O23F4LLA.js";
11
- import "./chunk-BI2RMQIV.js";
10
+ } from "./chunk-PD5OA3SZ.js";
11
+ import "./chunk-WEGMDILT.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-BI2RMQIV.js";
17
+ } from "./chunk-WEGMDILT.js";
18
18
  import {
19
19
  loadHistory
20
20
  } from "./chunk-3OR2GFVE.js";
@@ -689,7 +689,7 @@ function TuiApp({
689
689
  return () => timers.forEach(clearTimeout);
690
690
  }, []);
691
691
  useEffect7(() => {
692
- checkForUpdate("1.15.2").then((info) => {
692
+ checkForUpdate("1.15.3").then((info) => {
693
693
  if (info) setUpdateInfo(info);
694
694
  });
695
695
  }, []);
@@ -715,7 +715,7 @@ function TuiApp({
715
715
  } catch {
716
716
  }
717
717
  try {
718
- const { getDependencyTree } = await import("./dist-CEJKDCQM.js");
718
+ const { getDependencyTree } = await import("./dist-G7GDVJT5.js");
719
719
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
720
720
  const tree = await getDependencyTree(projectPath, result.projectInfo.packageManager);
721
721
  saveDepTree(projectPath, tree);
@@ -819,7 +819,7 @@ function TuiApp({
819
819
  const webReport = monorepoReportRef.current ?? reportRef.current;
820
820
  if (!webReport) return;
821
821
  try {
822
- const { serveWeb } = await import("./web-KRYFOBSH.js");
822
+ const { serveWeb } = await import("./web-EUG7IJKA.js");
823
823
  const { default: openBrowser } = await import("open");
824
824
  let aiService;
825
825
  if (withAI && process.env.ANTHROPIC_API_KEY && !monorepoReportRef.current) {
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  detectMonorepo
3
- } from "./chunk-BI2RMQIV.js";
3
+ } from "./chunk-WEGMDILT.js";
4
4
 
5
5
  // src/lib/resolve-package.ts
6
6
  import { readFileSync } from "fs";
@@ -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.15.2")), projectName && /* @__PURE__ */ React.createElement(Box, { marginTop: 1 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, " Analyzing "), /* @__PURE__ */ React.createElement(Text, { bold: true, color: "white" }, 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.15.3")), 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 {
@@ -1,5 +1,6 @@
1
1
  // ../../packages/core/dist/index.js
2
- import { relative as relative2 } from "path";
2
+ import { existsSync as existsSync27, readFileSync as readFileSync31 } from "fs";
3
+ import { basename as basename3, join as join38, relative as relative2 } from "path";
3
4
  import { readFileSync, readdirSync, statSync, existsSync } from "fs";
4
5
  import { join, extname } from "path";
5
6
  import { readFileSync as readFileSync2, readdirSync as readdirSync2, existsSync as existsSync2 } from "fs";
@@ -77,20 +78,20 @@ import { existsSync as existsSync21 } from "fs";
77
78
  import { dirname as dirname4, join as join31, relative } from "path";
78
79
  import { execa as execa10 } from "execa";
79
80
  import { execa as execa11 } from "execa";
80
- import { readFileSync as readFileSync26, readdirSync as readdirSync16, statSync as statSync15 } from "fs";
81
+ import { existsSync as existsSync22, readFileSync as readFileSync26, readdirSync as readdirSync16, statSync as statSync15 } from "fs";
81
82
  import { join as join32, extname as extname7 } from "path";
82
- import { readFileSync as readFileSync27, readdirSync as readdirSync17, statSync as statSync16, existsSync as existsSync22 } from "fs";
83
+ import { readFileSync as readFileSync27, readdirSync as readdirSync17, statSync as statSync16, existsSync as existsSync23 } from "fs";
83
84
  import { join as join33, extname as extname8, basename as basename2 } from "path";
84
85
  import { statSync as statSync17, readFileSync as readFileSync28 } from "fs";
85
86
  import { join as join34 } from "path";
86
87
  import { execa as execa12 } from "execa";
87
88
  import { globby } from "globby";
88
- import { readFileSync as readFileSync29, readdirSync as readdirSync18, statSync as statSync18, existsSync as existsSync23 } from "fs";
89
+ import { readFileSync as readFileSync29, readdirSync as readdirSync18, statSync as statSync18, existsSync as existsSync24 } from "fs";
89
90
  import { join as join35, extname as extname9 } from "path";
90
- import { existsSync as existsSync24 } from "fs";
91
+ import { existsSync as existsSync25 } from "fs";
91
92
  import { join as join36 } from "path";
92
93
  import { execa as execa13 } from "execa";
93
- import { existsSync as existsSync25, readFileSync as readFileSync30 } from "fs";
94
+ import { existsSync as existsSync26, readFileSync as readFileSync30 } from "fs";
94
95
  import { join as join37, resolve as resolve2 } from "path";
95
96
  import { globby as globby2 } from "globby";
96
97
  import picomatch2 from "picomatch";
@@ -2049,6 +2050,7 @@ async function detectProject(projectPath) {
2049
2050
  }
2050
2051
  function detectFramework(deps) {
2051
2052
  if ("next" in deps) return "next";
2053
+ if ("@angular/core" in deps) return "angular";
2052
2054
  if ("@vitejs/plugin-react" in deps || "vite" in deps) return "vite";
2053
2055
  if ("react-scripts" in deps) return "cra";
2054
2056
  if ("react" in deps) return "react";
@@ -2554,7 +2556,8 @@ var GitRunner = class extends BaseRunner {
2554
2556
  const commitCount = logCountResult.status === "fulfilled" ? parseInt(logCountResult.value.stdout.trim(), 10) : 0;
2555
2557
  const contributorCount = contributorsResult.status === "fulfilled" ? contributorsResult.value.stdout.trim().split("\n").filter(Boolean).length : 0;
2556
2558
  const issues = [];
2557
- const isStale = lastCommit.includes("year") || lastCommit.includes("month") && parseInt(lastCommit) > staleMonths;
2559
+ const lastCommitMonths = lastCommit.includes("year") ? parseGitRelativeCount(lastCommit) * 12 : lastCommit.includes("month") ? parseGitRelativeCount(lastCommit) : 0;
2560
+ const isStale = lastCommitMonths > staleMonths;
2558
2561
  if (isStale) {
2559
2562
  issues.push({
2560
2563
  severity: "warning",
@@ -2597,6 +2600,12 @@ var GitRunner = class extends BaseRunner {
2597
2600
  }
2598
2601
  }
2599
2602
  };
2603
+ function parseGitRelativeCount(s) {
2604
+ const trimmed = s.trim().toLowerCase();
2605
+ if (trimmed.startsWith("a ") || trimmed.startsWith("an ")) return 1;
2606
+ const match = trimmed.match(/^(\d+)\b/);
2607
+ return match ? parseInt(match[1], 10) : 0;
2608
+ }
2600
2609
  var HEAVY_DEPS = {
2601
2610
  moment: {
2602
2611
  alternative: "dayjs or date-fns",
@@ -4225,18 +4234,24 @@ function getUpdateType(current, latest) {
4225
4234
  if (curMin < latMin) return "minor";
4226
4235
  return "patch";
4227
4236
  }
4237
+ var SOURCE_DIRS2 = ["src", "app", "lib"];
4228
4238
  var COMPONENT_EXTENSIONS3 = /* @__PURE__ */ new Set([".tsx", ".jsx"]);
4229
4239
  var ReactPerfRunner = class extends BaseRunner {
4230
4240
  name = "react-perf";
4231
4241
  category = "performance";
4232
4242
  applicableFrameworks = ["react", "next", "remix"];
4243
+ async isApplicable(projectPath) {
4244
+ return SOURCE_DIRS2.some((dir) => existsSync22(join32(projectPath, dir)));
4245
+ }
4233
4246
  async run(projectPath, options) {
4234
4247
  const elapsed = timer();
4235
4248
  const isExcluded = createExcludeFilter(options?.checkConfig?.exclude ?? []);
4236
4249
  try {
4237
4250
  const hasReactCompiler = detectReactCompiler(projectPath);
4238
4251
  const findings = [];
4239
- const files = scanDirectory2(join32(projectPath, "src"), projectPath, isExcluded);
4252
+ const files = SOURCE_DIRS2.flatMap(
4253
+ (dir) => existsSync22(join32(projectPath, dir)) ? scanDirectory2(join32(projectPath, dir), projectPath, isExcluded) : []
4254
+ );
4240
4255
  for (const file of files) {
4241
4256
  findings.push(...analyzeFile(file.path, file.fullPath, file.lines));
4242
4257
  }
@@ -4453,7 +4468,7 @@ var SecretsRunner = class extends BaseRunner {
4453
4468
  const findings = [];
4454
4469
  const envFiles = [".env", ".env.local", ".env.production"];
4455
4470
  for (const envFile of envFiles) {
4456
- if (existsSync22(join33(projectPath, envFile))) {
4471
+ if (existsSync23(join33(projectPath, envFile))) {
4457
4472
  const gitignorePath = join33(projectPath, ".gitignore");
4458
4473
  let ignored = false;
4459
4474
  try {
@@ -4470,9 +4485,14 @@ var SecretsRunner = class extends BaseRunner {
4470
4485
  }
4471
4486
  }
4472
4487
  }
4473
- if (existsSync22(join33(projectPath, "src"))) {
4474
- findings.push(...scanDirectory3(join33(projectPath, "src"), projectPath, isExcluded));
4488
+ const SCAN_DIRS = ["src", "app", "lib", "config", "scripts", ".github/workflows"];
4489
+ for (const dir of SCAN_DIRS) {
4490
+ const fullDir = join33(projectPath, dir);
4491
+ if (existsSync23(fullDir)) {
4492
+ findings.push(...scanDirectory3(fullDir, projectPath, isExcluded));
4493
+ }
4475
4494
  }
4495
+ findings.push(...scanRootFiles(projectPath, isExcluded));
4476
4496
  const issues = findings.map((f) => ({
4477
4497
  severity: "critical",
4478
4498
  message: f.line > 0 ? `${f.file}:${f.line} \u2014 ${f.pattern} detected` : `${f.file} \u2014 ${f.pattern}`,
@@ -4543,6 +4563,29 @@ function scanDirectory3(dir, projectRoot, isExcluded) {
4543
4563
  function isTestFile2(filename) {
4544
4564
  return /\.(test|spec)\.(ts|tsx|js|jsx|mts|cts)$/.test(filename);
4545
4565
  }
4566
+ function scanRootFiles(projectRoot, isExcluded) {
4567
+ const findings = [];
4568
+ try {
4569
+ for (const entry of readdirSync17(projectRoot)) {
4570
+ const fullPath = join33(projectRoot, entry);
4571
+ let stat;
4572
+ try {
4573
+ stat = statSync16(fullPath);
4574
+ } catch {
4575
+ continue;
4576
+ }
4577
+ if (!stat.isFile()) continue;
4578
+ if (!SCAN_EXTENSIONS.has(extname8(entry))) continue;
4579
+ if (SKIP_FILES.has(basename2(entry))) continue;
4580
+ if (entry === "package.json") continue;
4581
+ if (isTestFile2(entry)) continue;
4582
+ if (isExcluded(entry)) continue;
4583
+ findings.push(...scanFile(fullPath, projectRoot));
4584
+ }
4585
+ } catch {
4586
+ }
4587
+ return findings;
4588
+ }
4546
4589
  function scanFile(filePath, projectRoot) {
4547
4590
  const findings = [];
4548
4591
  try {
@@ -4762,7 +4805,7 @@ var TodoScannerRunner = class extends BaseRunner {
4762
4805
  name = "todo-scanner";
4763
4806
  category = "code-quality";
4764
4807
  async isApplicable(projectPath) {
4765
- return existsSync23(join35(projectPath, "src"));
4808
+ return existsSync24(join35(projectPath, "src"));
4766
4809
  }
4767
4810
  async run(projectPath, options) {
4768
4811
  const elapsed = timer();
@@ -4861,7 +4904,7 @@ var TypeScriptRunner = class extends BaseRunner {
4861
4904
  name = "typescript";
4862
4905
  category = "code-quality";
4863
4906
  async isApplicable(projectPath) {
4864
- return existsSync24(join36(projectPath, "tsconfig.json"));
4907
+ return existsSync25(join36(projectPath, "tsconfig.json"));
4865
4908
  }
4866
4909
  async run(projectPath, options) {
4867
4910
  const elapsed = timer();
@@ -5116,12 +5159,12 @@ async function discoverPackages(rootPath, patterns) {
5116
5159
  ignore: ["**/node_modules/**"]
5117
5160
  });
5118
5161
  return matched.filter((dir) => {
5119
- return dir !== resolve2(rootPath) && existsSync25(join37(dir, "package.json"));
5162
+ return dir !== resolve2(rootPath) && existsSync26(join37(dir, "package.json"));
5120
5163
  });
5121
5164
  }
5122
5165
  function detectSignals(rootPath) {
5123
5166
  const pnpmWs = join37(rootPath, "pnpm-workspace.yaml");
5124
- if (existsSync25(pnpmWs)) {
5167
+ if (existsSync26(pnpmWs)) {
5125
5168
  try {
5126
5169
  const content = readFileSync30(pnpmWs, "utf-8");
5127
5170
  const patterns = parseYamlPackagesArray(content);
@@ -5131,7 +5174,7 @@ function detectSignals(rootPath) {
5131
5174
  }
5132
5175
  }
5133
5176
  const lernaJson = join37(rootPath, "lerna.json");
5134
- if (existsSync25(lernaJson)) {
5177
+ if (existsSync26(lernaJson)) {
5135
5178
  try {
5136
5179
  const lerna = JSON.parse(readFileSync30(lernaJson, "utf-8"));
5137
5180
  const patterns = Array.isArray(lerna.packages) ? lerna.packages : ["packages/*"];
@@ -5141,27 +5184,27 @@ function detectSignals(rootPath) {
5141
5184
  }
5142
5185
  }
5143
5186
  const pkgJson = join37(rootPath, "package.json");
5144
- if (existsSync25(pkgJson)) {
5187
+ if (existsSync26(pkgJson)) {
5145
5188
  try {
5146
5189
  const pkg = JSON.parse(readFileSync30(pkgJson, "utf-8"));
5147
5190
  const workspaces = Array.isArray(pkg.workspaces) ? pkg.workspaces : Array.isArray(pkg.workspaces?.packages) ? pkg.workspaces.packages : void 0;
5148
5191
  if (workspaces && workspaces.length > 0) {
5149
- if (existsSync25(join37(rootPath, "turbo.json"))) {
5192
+ if (existsSync26(join37(rootPath, "turbo.json"))) {
5150
5193
  return { type: "turbo", patterns: workspaces };
5151
5194
  }
5152
- if (existsSync25(join37(rootPath, "nx.json"))) {
5195
+ if (existsSync26(join37(rootPath, "nx.json"))) {
5153
5196
  return { type: "nx", patterns: workspaces };
5154
5197
  }
5155
- const hasYarn = existsSync25(join37(rootPath, "yarn.lock"));
5198
+ const hasYarn = existsSync26(join37(rootPath, "yarn.lock"));
5156
5199
  return { type: hasYarn ? "yarn" : "npm", patterns: workspaces };
5157
5200
  }
5158
5201
  } catch {
5159
5202
  }
5160
5203
  }
5161
- if (existsSync25(join37(rootPath, "turbo.json"))) {
5204
+ if (existsSync26(join37(rootPath, "turbo.json"))) {
5162
5205
  return { type: "turbo", patterns: ["packages/*", "apps/*"] };
5163
5206
  }
5164
- if (existsSync25(join37(rootPath, "nx.json"))) {
5207
+ if (existsSync26(join37(rootPath, "nx.json"))) {
5165
5208
  return { type: "nx", patterns: ["packages/*", "apps/*", "libs/*"] };
5166
5209
  }
5167
5210
  return null;
@@ -5268,6 +5311,17 @@ var ALL_ADVISORS = [
5268
5311
  new NextBestPracticesAdvisor(),
5269
5312
  new UniversalBestPracticesAdvisor()
5270
5313
  ];
5314
+ function readPackageName(pkgPath) {
5315
+ const pkgJsonPath = join38(pkgPath, "package.json");
5316
+ if (existsSync27(pkgJsonPath)) {
5317
+ try {
5318
+ const pkg = JSON.parse(readFileSync31(pkgJsonPath, "utf-8"));
5319
+ if (pkg.name) return pkg.name;
5320
+ } catch {
5321
+ }
5322
+ }
5323
+ return basename3(pkgPath);
5324
+ }
5271
5325
  function getAvailableChecks(context) {
5272
5326
  const runners = context ? ALL_RUNNERS.filter((r) => r.isApplicableToContext(context)) : ALL_RUNNERS;
5273
5327
  return runners.map((r) => ({ name: r.name, category: r.category }));
@@ -5372,9 +5426,9 @@ async function runSickbayMonorepo(options = {}) {
5372
5426
  monorepoInfo.packagePaths.map(async (pkgPath) => {
5373
5427
  const pkgConfig = await loadConfig(pkgPath);
5374
5428
  const mergedConfig = mergeConfigs(rootConfig, pkgConfig);
5429
+ options.onPackageStart?.(readPackageName(pkgPath));
5375
5430
  const report = await runSickbay({ ...options, projectPath: pkgPath, _config: mergedConfig });
5376
5431
  const context = await detectContext(pkgPath);
5377
- options.onPackageStart?.(report.projectInfo.name);
5378
5432
  const packageReport = {
5379
5433
  name: report.projectInfo.name,
5380
5434
  path: pkgPath,
package/dist/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  defineConfig
3
- } from "./chunk-BI2RMQIV.js";
3
+ } from "./chunk-WEGMDILT.js";
4
4
  export {
5
5
  defineConfig
6
6
  };
@@ -29,7 +29,7 @@ import {
29
29
  runSickbay,
30
30
  runSickbayMonorepo,
31
31
  validateConfig
32
- } from "./chunk-BI2RMQIV.js";
32
+ } from "./chunk-WEGMDILT.js";
33
33
  export {
34
34
  BaseAdvisor,
35
35
  CATEGORY_WEIGHTS,
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-O23F4LLA.js";
11
+ } from "./chunk-PD5OA3SZ.js";
12
12
  import {
13
13
  getScoreEmoji,
14
14
  runSickbay,
15
15
  runSickbayMonorepo
16
- } from "./chunk-BI2RMQIV.js";
16
+ } from "./chunk-WEGMDILT.js";
17
17
 
18
18
  // src/index.ts
19
19
  import { existsSync } from "fs";
@@ -190,7 +190,7 @@ function App({
190
190
  setMonorepoReport(r);
191
191
  setProjectName(`monorepo (${r.packages.length} packages)`);
192
192
  try {
193
- const { getDependencyTree } = await import("./dist-CEJKDCQM.js");
193
+ const { getDependencyTree } = await import("./dist-G7GDVJT5.js");
194
194
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
195
195
  const packages = {};
196
196
  for (const pkg of r.packages) {
@@ -202,7 +202,7 @@ function App({
202
202
  if (openWeb) {
203
203
  setPhase("opening-web");
204
204
  try {
205
- const { serveWeb } = await import("./web-KRYFOBSH.js");
205
+ const { serveWeb } = await import("./web-EUG7IJKA.js");
206
206
  const { default: openBrowser } = await import("open");
207
207
  let aiService;
208
208
  if (enableAI && process.env.ANTHROPIC_API_KEY) {
@@ -259,7 +259,7 @@ function App({
259
259
  } catch {
260
260
  }
261
261
  try {
262
- const { getDependencyTree } = await import("./dist-CEJKDCQM.js");
262
+ const { getDependencyTree } = await import("./dist-G7GDVJT5.js");
263
263
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
264
264
  const tree = await getDependencyTree(projectPath, r.projectInfo.packageManager);
265
265
  saveDepTree(projectPath, tree);
@@ -268,7 +268,7 @@ function App({
268
268
  if (openWeb) {
269
269
  setPhase("opening-web");
270
270
  try {
271
- const { serveWeb } = await import("./web-KRYFOBSH.js");
271
+ const { serveWeb } = await import("./web-EUG7IJKA.js");
272
272
  const { default: openBrowser } = await import("open");
273
273
  let aiService;
274
274
  if (enableAI && process.env.ANTHROPIC_API_KEY) {
@@ -317,7 +317,7 @@ if (existsSync(globalConfigPath)) {
317
317
  }
318
318
  config({ debug: false, quiet: true });
319
319
  var program = new Command();
320
- program.name("sickbay").description("React project health check CLI").version("1.15.2", "-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) => {
320
+ program.name("sickbay").description("React project health check CLI").version("1.15.3", "-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) => {
321
321
  if (options.path && options.path !== process.cwd()) {
322
322
  const projectEnvPath = join(options.path, ".env");
323
323
  if (existsSync(projectEnvPath)) {
@@ -327,13 +327,13 @@ program.name("sickbay").description("React project health check CLI").version("1
327
327
  const updatePromise = (async () => {
328
328
  try {
329
329
  const { checkForUpdate } = await import("./update-check-M7IFOMLJ.js");
330
- return await checkForUpdate("1.15.2");
330
+ return await checkForUpdate("1.15.3");
331
331
  } catch {
332
332
  return null;
333
333
  }
334
334
  })();
335
335
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
336
- const { detectMonorepo, runSickbay: runSickbay2, runSickbayMonorepo: runSickbayMonorepo2 } = await import("./dist-CEJKDCQM.js");
336
+ const { detectMonorepo, runSickbay: runSickbay2, runSickbayMonorepo: runSickbayMonorepo2 } = await import("./dist-G7GDVJT5.js");
337
337
  const monorepoInfo = await detectMonorepo(options.path);
338
338
  if (options.package && monorepoInfo.isMonorepo) {
339
339
  const { readFileSync } = await import("fs");
@@ -397,7 +397,7 @@ program.name("sickbay").description("React project health check CLI").version("1
397
397
  } catch {
398
398
  }
399
399
  try {
400
- const { getDependencyTree } = await import("./dist-CEJKDCQM.js");
400
+ const { getDependencyTree } = await import("./dist-G7GDVJT5.js");
401
401
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
402
402
  const tree = await getDependencyTree(options.path, report.projectInfo.packageManager);
403
403
  saveDepTree(options.path, tree);
@@ -424,16 +424,16 @@ program.command("init").description("Initialize .sickbay/ folder and run an init
424
424
  "add newly available checks to existing config without touching existing entries"
425
425
  ).option("--reset-config", "regenerate config from scratch (overwrites existing)").action(async (options) => {
426
426
  if (options.resetConfig) {
427
- const { generateConfigFile } = await import("./init-WGMAAQSO.js");
427
+ const { generateConfigFile } = await import("./init-BBKWOHRV.js");
428
428
  await generateConfigFile(options.path, { force: true });
429
429
  return;
430
430
  }
431
431
  if (options.sync) {
432
- const { syncConfigFile } = await import("./init-WGMAAQSO.js");
432
+ const { syncConfigFile } = await import("./init-BBKWOHRV.js");
433
433
  await syncConfigFile(options.path);
434
434
  return;
435
435
  }
436
- const { initSickbay } = await import("./init-WGMAAQSO.js");
436
+ const { initSickbay } = await import("./init-BBKWOHRV.js");
437
437
  await initSickbay(options.path);
438
438
  });
439
439
  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) => {
@@ -443,9 +443,9 @@ program.command("fix").description("Interactively fix issues found by sickbay sc
443
443
  config({ path: projectEnvPath, override: true });
444
444
  }
445
445
  }
446
- const { resolveProject } = await import("./resolve-package-FYX3J6PS.js");
446
+ const { resolveProject } = await import("./resolve-package-CB3KDANT.js");
447
447
  const resolution = await resolveProject(options.path, options.package);
448
- const { FixApp } = await import("./FixApp-HT7PHJKO.js");
448
+ const { FixApp } = await import("./FixApp-6JU4B3EJ.js");
449
449
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
450
450
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
451
451
  render(
@@ -468,10 +468,10 @@ program.command("trend").description("Show score history and trends over time").
468
468
  config({ path: projectEnvPath, override: true });
469
469
  }
470
470
  }
471
- const { resolveProject } = await import("./resolve-package-FYX3J6PS.js");
471
+ const { resolveProject } = await import("./resolve-package-CB3KDANT.js");
472
472
  const resolution = await resolveProject(options.path, options.package);
473
473
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
474
- const { TrendApp } = await import("./TrendApp-CB7CNPZI.js");
474
+ const { TrendApp } = await import("./TrendApp-TB4E7ZUU.js");
475
475
  render(
476
476
  React7.createElement(TrendApp, {
477
477
  projectPath,
@@ -490,10 +490,10 @@ program.command("stats").description("Show a quick codebase overview and project
490
490
  config({ path: projectEnvPath, override: true });
491
491
  }
492
492
  }
493
- const { resolveProject } = await import("./resolve-package-FYX3J6PS.js");
493
+ const { resolveProject } = await import("./resolve-package-CB3KDANT.js");
494
494
  const resolution = await resolveProject(options.path, options.package);
495
495
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
496
- const { StatsApp } = await import("./StatsApp-GOCP43YN.js");
496
+ const { StatsApp } = await import("./StatsApp-EYYWVSGZ.js");
497
497
  render(
498
498
  React7.createElement(StatsApp, {
499
499
  projectPath,
@@ -505,7 +505,7 @@ program.command("stats").description("Show a quick codebase overview and project
505
505
  );
506
506
  });
507
507
  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) => {
508
- const { TuiApp } = await import("./TuiApp-SX22YRN7.js");
508
+ const { TuiApp } = await import("./TuiApp-4JRQCD7M.js");
509
509
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
510
510
  render(
511
511
  React7.createElement(TuiApp, {
@@ -525,10 +525,10 @@ program.command("doctor").description("Diagnose project setup and configuration
525
525
  config({ path: projectEnvPath, override: true });
526
526
  }
527
527
  }
528
- const { resolveProject } = await import("./resolve-package-FYX3J6PS.js");
528
+ const { resolveProject } = await import("./resolve-package-CB3KDANT.js");
529
529
  const resolution = await resolveProject(options.path, options.package);
530
530
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
531
- const { DoctorApp } = await import("./DoctorApp-VIDISA3A.js");
531
+ const { DoctorApp } = await import("./DoctorApp-VKJCRS2I.js");
532
532
  render(
533
533
  React7.createElement(DoctorApp, {
534
534
  projectPath,
@@ -541,13 +541,13 @@ program.command("doctor").description("Diagnose project setup and configuration
541
541
  );
542
542
  });
543
543
  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) => {
544
- const { resolveProject } = await import("./resolve-package-FYX3J6PS.js");
544
+ const { resolveProject } = await import("./resolve-package-CB3KDANT.js");
545
545
  const resolution = await resolveProject(options.path, options.package);
546
546
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
547
547
  const { loadScoreFromLastReport, badgeUrl, badgeMarkdown, badgeHtml } = await import("./badge-KQ73KEIN.js");
548
548
  let score = options.scan ? null : loadScoreFromLastReport(projectPath);
549
549
  if (score === null) {
550
- const { runSickbay: runSickbay2 } = await import("./dist-CEJKDCQM.js");
550
+ const { runSickbay: runSickbay2 } = await import("./dist-G7GDVJT5.js");
551
551
  const report = await runSickbay2({ projectPath, quotes: false });
552
552
  try {
553
553
  const { saveEntry, saveLastReport } = await import("./history-XLNVZEDI.js");
@@ -580,7 +580,7 @@ program.command("diff <branch>").description("Compare health score against anoth
580
580
  }
581
581
  }
582
582
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
583
- const { DiffApp } = await import("./DiffApp-M3D3HGI4.js");
583
+ const { DiffApp } = await import("./DiffApp-KR745TCV.js");
584
584
  render(
585
585
  React7.createElement(DiffApp, {
586
586
  projectPath: options.path,
@@ -4,7 +4,7 @@ import {
4
4
  getAvailableChecks,
5
5
  runSickbay,
6
6
  runSickbayMonorepo
7
- } from "./chunk-BI2RMQIV.js";
7
+ } from "./chunk-WEGMDILT.js";
8
8
  import {
9
9
  saveEntry
10
10
  } from "./chunk-3OR2GFVE.js";
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  resolveProject,
3
3
  shortName
4
- } from "./chunk-QAVKOJFG.js";
5
- import "./chunk-BI2RMQIV.js";
4
+ } from "./chunk-MCHTDD7R.js";
5
+ import "./chunk-WEGMDILT.js";
6
6
  export {
7
7
  resolveProject,
8
8
  shortName
@@ -106,7 +106,7 @@ async function serveWeb(report, preferredPort = 3030, aiService) {
106
106
  if (url === "/sickbay-config.json") {
107
107
  const basePath = "isMonorepo" in report ? report.rootPath : report.projectPath;
108
108
  try {
109
- const { loadConfig } = await import("./dist-CEJKDCQM.js");
109
+ const { loadConfig } = await import("./dist-G7GDVJT5.js");
110
110
  const config = await loadConfig(basePath);
111
111
  if (config) {
112
112
  res.writeHead(200, { "Content-Type": "application/json" });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sickbay",
3
- "version": "1.15.3",
3
+ "version": "1.15.4",
4
4
  "description": "Zero-config health check CLI for JavaScript and TypeScript projects",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -63,5 +63,6 @@
63
63
  "tsup": "catalog:",
64
64
  "typescript": "catalog:",
65
65
  "vitest": "catalog:"
66
- }
66
+ },
67
+ "_bundleNote": "tsup bundles @nebulord/sickbay-core inline (see tsup.config.ts noExternal). Core's runtime deps are mirrored in `dependencies` below so the bundled require() calls resolve at runtime. Do NOT delete entries that look unused from cli source — they are needed by core's bundled code. Drift is enforced by `pnpm check:bundled-deps` (scripts/check-bundled-deps.mjs)."
67
68
  }