sickbay 1.15.10 → 1.16.1

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.
Files changed (39) hide show
  1. package/dist/{DiffApp-W7AYJXAC.js → DiffApp-V3GF6YM7.js} +2 -2
  2. package/dist/{DoctorApp-3MUEJRYX.js → DoctorApp-OS5MITI5.js} +3 -3
  3. package/dist/{FixApp-H7W77W6M.js → FixApp-WUUS3QM6.js} +3 -3
  4. package/dist/{StatsApp-XYGCOHKG.js → StatsApp-BF5LYVRA.js} +3 -3
  5. package/dist/{TrendApp-5LK7JZ3Y.js → TrendApp-SZURVP7W.js} +3 -3
  6. package/dist/{TuiApp-GN57TL66.js → TuiApp-3ZU3KG24.js} +9 -7
  7. package/dist/{chunk-W4GJ5ISW.js → chunk-DJA6K3MN.js} +15 -1
  8. package/dist/{chunk-S7IEDXU2.js → chunk-GK73SXW6.js} +1 -1
  9. package/dist/{chunk-TYG7ZQBP.js → chunk-LZOEMCE7.js} +27 -0
  10. package/dist/{chunk-IQYSZ3UW.js → chunk-VBM6NZAY.js} +1 -1
  11. package/dist/config.js +1 -1
  12. package/dist/{dist-IEANON4U.js → dist-LQY3FYCP.js} +1 -1
  13. package/dist/index.js +34 -29
  14. package/dist/{init-PVZHRY3T.js → init-DD2HOQE2.js} +1 -1
  15. package/dist/{resolve-package-LP7CD7JU.js → resolve-package-774YTW5Q.js} +2 -2
  16. package/dist/web/assets/{ChatDrawer-dCdqFiGs.js → ChatDrawer-Bbnv0gOr.js} +2 -2
  17. package/dist/web/assets/{ChatDrawer-dCdqFiGs.js.map → ChatDrawer-Bbnv0gOr.js.map} +1 -1
  18. package/dist/web/assets/{DependencyGraph-BSJPytrP.js → DependencyGraph-DwrNnbRv.js} +2 -2
  19. package/dist/web/assets/{DependencyGraph-BSJPytrP.js.map → DependencyGraph-DwrNnbRv.js.map} +1 -1
  20. package/dist/web/assets/MonorepoOverview-B5pKk2xN.js +2 -0
  21. package/dist/web/assets/MonorepoOverview-B5pKk2xN.js.map +1 -0
  22. package/dist/web/assets/{index-B23n764F.css → index-CPMhENPs.css} +1 -1
  23. package/dist/web/assets/index-CqHC2egK.js +16 -0
  24. package/dist/web/assets/index-CqHC2egK.js.map +1 -0
  25. package/dist/web/assets/issue-grouping-183B2uea.js +2 -0
  26. package/dist/web/assets/issue-grouping-183B2uea.js.map +1 -0
  27. package/dist/web/assets/{markdown-oPAUxr3B.js → markdown-vE-W5L19.js} +2 -2
  28. package/dist/web/assets/{markdown-oPAUxr3B.js.map → markdown-vE-W5L19.js.map} +1 -1
  29. package/dist/web/assets/{react-DeNSbYyc.js → react-Cd_U1vkF.js} +3 -3
  30. package/dist/web/assets/{react-DeNSbYyc.js.map → react-Cd_U1vkF.js.map} +1 -1
  31. package/dist/web/index.html +5 -5
  32. package/dist/{web-3JO6YQIG.js → web-2KWCYTW4.js} +1 -1
  33. package/package.json +6 -6
  34. package/dist/web/assets/MonorepoOverview-DDbHHZi0.js +0 -2
  35. package/dist/web/assets/MonorepoOverview-DDbHHZi0.js.map +0 -1
  36. package/dist/web/assets/constants-DYzuOu1F.js +0 -2
  37. package/dist/web/assets/constants-DYzuOu1F.js.map +0 -1
  38. package/dist/web/assets/index-Bzeb-9jh.js +0 -16
  39. package/dist/web/assets/index-Bzeb-9jh.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  Header
3
- } from "./chunk-S7IEDXU2.js";
3
+ } from "./chunk-GK73SXW6.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-IEANON4U.js");
122
+ const { runSickbay } = await import("./dist-LQY3FYCP.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-IQYSZ3UW.js";
3
+ } from "./chunk-VBM6NZAY.js";
4
4
  import {
5
5
  Header
6
- } from "./chunk-S7IEDXU2.js";
6
+ } from "./chunk-GK73SXW6.js";
7
7
  import {
8
8
  detectPackageManager,
9
9
  detectProject
10
- } from "./chunk-W4GJ5ISW.js";
10
+ } from "./chunk-DJA6K3MN.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-IQYSZ3UW.js";
3
+ } from "./chunk-VBM6NZAY.js";
4
4
  import {
5
5
  ProgressList
6
6
  } from "./chunk-MBVA75EM.js";
7
7
  import {
8
8
  Header
9
- } from "./chunk-S7IEDXU2.js";
9
+ } from "./chunk-GK73SXW6.js";
10
10
  import {
11
11
  runSickbay
12
- } from "./chunk-W4GJ5ISW.js";
12
+ } from "./chunk-DJA6K3MN.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-IQYSZ3UW.js";
3
+ } from "./chunk-VBM6NZAY.js";
4
4
  import {
5
5
  Header
6
- } from "./chunk-S7IEDXU2.js";
6
+ } from "./chunk-GK73SXW6.js";
7
7
  import {
8
8
  detectProject
9
- } from "./chunk-W4GJ5ISW.js";
9
+ } from "./chunk-DJA6K3MN.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-IQYSZ3UW.js";
7
+ } from "./chunk-VBM6NZAY.js";
8
8
  import {
9
9
  Header
10
- } from "./chunk-S7IEDXU2.js";
11
- import "./chunk-W4GJ5ISW.js";
10
+ } from "./chunk-GK73SXW6.js";
11
+ import "./chunk-DJA6K3MN.js";
12
12
  import {
13
13
  detectRegressions,
14
14
  loadHistory
@@ -4,8 +4,9 @@ import {
4
4
  } from "./chunk-SHO3ZXTH.js";
5
5
  import {
6
6
  LOADING_MESSAGES,
7
- UpdateNotice
8
- } from "./chunk-TYG7ZQBP.js";
7
+ UpdateNotice,
8
+ countUniqueIssues
9
+ } from "./chunk-LZOEMCE7.js";
9
10
  import {
10
11
  checkForUpdate
11
12
  } from "./chunk-TWCTPAXQ.js";
@@ -14,7 +15,7 @@ import {
14
15
  detectMonorepo,
15
16
  runSickbay,
16
17
  runSickbayMonorepo
17
- } from "./chunk-W4GJ5ISW.js";
18
+ } from "./chunk-DJA6K3MN.js";
18
19
  import {
19
20
  loadHistory
20
21
  } from "./chunk-3OR2GFVE.js";
@@ -595,7 +596,8 @@ function ScorePanel({ report, previousScore, animate = true }) {
595
596
  return /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "Waiting for scan..."));
596
597
  }
597
598
  const delta = previousScore !== null ? report.overallScore - previousScore : null;
598
- return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: scoreColor3(displayScore), bold: true }, displayScore, "/100"), /* @__PURE__ */ React9.createElement(Text9, null, " "), /* @__PURE__ */ React9.createElement(Text9, { color: scoreColor3(displayScore) }, scoreBar3(displayScore))), delta !== null && /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, delta > 0 ? `+${delta}` : delta === 0 ? "\xB10" : `${delta}`, " since last scan"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "red" }, "\u2717", " ", report.summary.critical, " critical"), /* @__PURE__ */ React9.createElement(Text9, null, " "), /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u26A0", " ", report.summary.warnings, " warn"), /* @__PURE__ */ React9.createElement(Text9, null, " "), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "i ", report.summary.info, " info"))), report.quote && /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, dimColor: true }, '"', report.quote.text, '" \u2014 ', report.quote.source)), report.config?.hasCustomConfig && /* @__PURE__ */ React9.createElement(Text9, { dimColor: true, italic: true }, "Custom config"));
599
+ const u = countUniqueIssues(report.checks);
600
+ return /* @__PURE__ */ React9.createElement(Box9, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: scoreColor3(displayScore), bold: true }, displayScore, "/100"), /* @__PURE__ */ React9.createElement(Text9, null, " "), /* @__PURE__ */ React9.createElement(Text9, { color: scoreColor3(displayScore) }, scoreBar3(displayScore))), delta !== null && /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, delta > 0 ? `+${delta}` : delta === 0 ? "\xB10" : `${delta}`, " since last scan"), /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Box9, null, /* @__PURE__ */ React9.createElement(Text9, { color: "red" }, "\u2717", " ", u.critical, " critical", u.totalCritical > u.critical ? ` (${u.totalCritical})` : ""), /* @__PURE__ */ React9.createElement(Text9, null, " "), /* @__PURE__ */ React9.createElement(Text9, { color: "yellow" }, "\u26A0", " ", u.warnings, " warn", u.totalWarnings > u.warnings ? ` (${u.totalWarnings})` : ""), /* @__PURE__ */ React9.createElement(Text9, null, " "), /* @__PURE__ */ React9.createElement(Text9, { dimColor: true }, "i ", u.info, " info"))), report.quote && /* @__PURE__ */ React9.createElement(Box9, { marginTop: 1 }, /* @__PURE__ */ React9.createElement(Text9, { italic: true, dimColor: true }, '"', report.quote.text, '" \u2014 ', report.quote.source)), report.config?.hasCustomConfig && /* @__PURE__ */ React9.createElement(Text9, { dimColor: true, italic: true }, "Custom config"));
599
601
  }
600
602
 
601
603
  // src/components/tui/TrendPanel.tsx
@@ -705,7 +707,7 @@ function TuiApp({
705
707
  return () => timers.forEach(clearTimeout);
706
708
  }, []);
707
709
  useEffect7(() => {
708
- checkForUpdate("1.15.9").then((info) => {
710
+ checkForUpdate("1.16.0").then((info) => {
709
711
  if (info) setUpdateInfo(info);
710
712
  });
711
713
  }, []);
@@ -731,7 +733,7 @@ function TuiApp({
731
733
  } catch {
732
734
  }
733
735
  try {
734
- const { getDependencyTree } = await import("./dist-IEANON4U.js");
736
+ const { getDependencyTree } = await import("./dist-LQY3FYCP.js");
735
737
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
736
738
  const tree = await getDependencyTree(projectPath, result.projectInfo.packageManager);
737
739
  saveDepTree(projectPath, tree);
@@ -835,7 +837,7 @@ function TuiApp({
835
837
  const webReport = monorepoReportRef.current ?? reportRef.current;
836
838
  if (!webReport) return;
837
839
  try {
838
- const { serveWeb } = await import("./web-3JO6YQIG.js");
840
+ const { serveWeb } = await import("./web-2KWCYTW4.js");
839
841
  const { default: openBrowser } = await import("open");
840
842
  let aiService;
841
843
  if (withAI && process.env.ANTHROPIC_API_KEY && !monorepoReportRef.current) {
@@ -4271,9 +4271,23 @@ var ReactPerfRunner = class extends BaseRunner {
4271
4271
  fix: { description: getFixDescription(f.pattern) },
4272
4272
  reportedBy: ["react-perf"]
4273
4273
  }));
4274
+ const patternCounts = /* @__PURE__ */ new Map();
4275
+ for (const f of activeFindings) {
4276
+ const idx = f.pattern.indexOf(" \u2014 ");
4277
+ const key = idx >= 0 ? f.pattern.slice(idx + 3) : f.pattern;
4278
+ const entry = patternCounts.get(key) ?? { warnings: 0, infos: 0 };
4279
+ if (f.severity === "warning") entry.warnings++;
4280
+ else entry.infos++;
4281
+ patternCounts.set(key, entry);
4282
+ }
4283
+ let penalty = 0;
4284
+ for (const [, counts] of patternCounts) {
4285
+ if (counts.warnings > 0) penalty += 10 + Math.log2(counts.warnings) * 3;
4286
+ if (counts.infos > 0) penalty += 3 + Math.log2(counts.infos);
4287
+ }
4288
+ const score = Math.max(20, Math.round(100 - penalty));
4274
4289
  const warningCount = activeFindings.filter((f) => f.severity === "warning").length;
4275
4290
  const infoCount = activeFindings.filter((f) => f.severity === "info").length;
4276
- const score = Math.max(20, 100 - warningCount * 3 - infoCount * 1);
4277
4291
  return {
4278
4292
  id: "react-perf",
4279
4293
  category: this.category,
@@ -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.9")), 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.16.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 {
@@ -11,6 +11,32 @@ function UpdateNotice({ currentVersion, latestVersion }) {
11
11
  return /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", marginBottom: 1 }, /* @__PURE__ */ React.createElement(Text, { color: "yellow", dimColor: true }, `\u256D${"\u2500".repeat(boxWidth)}\u256E`), /* @__PURE__ */ React.createElement(Box, { paddingX: padding }, /* @__PURE__ */ React.createElement(Text, { color: "yellow", dimColor: true }, line1)), /* @__PURE__ */ React.createElement(Box, { paddingX: padding }, /* @__PURE__ */ React.createElement(Text, { color: "yellow", dimColor: true }, line2)), /* @__PURE__ */ React.createElement(Box, { paddingX: padding }, /* @__PURE__ */ React.createElement(Text, { color: "yellow", dimColor: true }, line3)), /* @__PURE__ */ React.createElement(Text, { color: "yellow", dimColor: true }, `\u2570${"\u2500".repeat(boxWidth)}\u256F`));
12
12
  }
13
13
 
14
+ // src/lib/issue-grouping.ts
15
+ function extractPatternStem(message) {
16
+ const idx = message.indexOf(" \u2014 ");
17
+ return idx >= 0 ? message.slice(idx + 3) : message;
18
+ }
19
+ function countUniqueIssues(checks) {
20
+ const seen = { critical: /* @__PURE__ */ new Set(), warning: /* @__PURE__ */ new Set(), info: /* @__PURE__ */ new Set() };
21
+ const totals = { critical: 0, warning: 0, info: 0 };
22
+ for (const check of checks) {
23
+ for (const issue of check.issues) {
24
+ const stem = extractPatternStem(issue.message);
25
+ const key = `${check.id}::${stem}`;
26
+ seen[issue.severity].add(key);
27
+ totals[issue.severity]++;
28
+ }
29
+ }
30
+ return {
31
+ critical: seen.critical.size,
32
+ warnings: seen.warning.size,
33
+ info: seen.info.size,
34
+ totalCritical: totals.critical,
35
+ totalWarnings: totals.warning,
36
+ totalInfo: totals.info
37
+ };
38
+ }
39
+
14
40
  // src/lib/messages.ts
15
41
  var LOADING_MESSAGES = [
16
42
  "Scanning for pre-existing conditions\u2026",
@@ -30,6 +56,7 @@ var LOADING_MESSAGES = [
30
56
  ];
31
57
 
32
58
  export {
59
+ countUniqueIssues,
33
60
  LOADING_MESSAGES,
34
61
  UpdateNotice
35
62
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  detectMonorepo
3
- } from "./chunk-W4GJ5ISW.js";
3
+ } from "./chunk-DJA6K3MN.js";
4
4
 
5
5
  // src/lib/resolve-package.ts
6
6
  import { readFileSync } from "fs";
package/dist/config.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  defineConfig
3
- } from "./chunk-W4GJ5ISW.js";
3
+ } from "./chunk-DJA6K3MN.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-W4GJ5ISW.js";
32
+ } from "./chunk-DJA6K3MN.js";
33
33
  export {
34
34
  BaseAdvisor,
35
35
  CATEGORY_WEIGHTS,
package/dist/index.js CHANGED
@@ -4,16 +4,17 @@ import {
4
4
  } from "./chunk-MBVA75EM.js";
5
5
  import {
6
6
  LOADING_MESSAGES,
7
- UpdateNotice
8
- } from "./chunk-TYG7ZQBP.js";
7
+ UpdateNotice,
8
+ countUniqueIssues
9
+ } from "./chunk-LZOEMCE7.js";
9
10
  import {
10
11
  Header
11
- } from "./chunk-S7IEDXU2.js";
12
+ } from "./chunk-GK73SXW6.js";
12
13
  import {
13
14
  getScoreEmoji,
14
15
  runSickbay,
15
16
  runSickbayMonorepo
16
- } from "./chunk-W4GJ5ISW.js";
17
+ } from "./chunk-DJA6K3MN.js";
17
18
 
18
19
  // src/index.ts
19
20
  import { existsSync } from "fs";
@@ -119,7 +120,8 @@ function formatDuration(ms) {
119
120
  return `${minutes}m ${remainingSeconds}s`;
120
121
  }
121
122
  function Summary({ report, scanDuration }) {
122
- return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, "\u2501".repeat(52)), /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { bold: true }, "Overall Health Score: "), /* @__PURE__ */ React5.createElement(ScoreBar, { score: report.overallScore, width: 12 }), /* @__PURE__ */ React5.createElement(Text5, null, " ", getScoreEmoji(report.overallScore)), scanDuration != null && /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " ", formatDuration(scanDuration))), /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "red" }, " \u2717 ", report.summary.critical, " critical"), /* @__PURE__ */ React5.createElement(Text5, { color: "yellow" }, " \u26A0 ", report.summary.warnings, " warnings"), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, " i ", report.summary.info, " info")), report.quote && /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { italic: true, dimColor: true }, '"', report.quote.text, '"'), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2014 ", report.quote.source)), report.config?.hasCustomConfig && /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true, italic: true }, "Custom config active", report.config.disabledChecks.length > 0 && ` (${report.config.disabledChecks.length} check${report.config.disabledChecks.length === 1 ? "" : "s"} disabled)`)));
123
+ const u = countUniqueIssues(report.checks);
124
+ return /* @__PURE__ */ React5.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, "\u2501".repeat(52)), /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { bold: true }, "Overall Health Score: "), /* @__PURE__ */ React5.createElement(ScoreBar, { score: report.overallScore, width: 12 }), /* @__PURE__ */ React5.createElement(Text5, null, " ", getScoreEmoji(report.overallScore)), scanDuration != null && /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " ", formatDuration(scanDuration))), /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { color: "red" }, " ", "\u2717 ", u.critical, " critical", u.totalCritical > u.critical ? ` (${u.totalCritical} total)` : ""), /* @__PURE__ */ React5.createElement(Text5, { color: "yellow" }, " ", "\u26A0 ", u.warnings, " warning", u.warnings !== 1 ? "s" : "", u.totalWarnings > u.warnings ? ` (${u.totalWarnings} total)` : ""), /* @__PURE__ */ React5.createElement(Text5, { color: "gray" }, " i ", u.info, " info")), report.quote && /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { italic: true, dimColor: true }, '"', report.quote.text, '"'), /* @__PURE__ */ React5.createElement(Text5, { dimColor: true }, " \u2014 ", report.quote.source)), report.config?.hasCustomConfig && /* @__PURE__ */ React5.createElement(Box5, { marginTop: 1 }, /* @__PURE__ */ React5.createElement(Text5, { dimColor: true, italic: true }, "Custom config active", report.config.disabledChecks.length > 0 && ` (${report.config.disabledChecks.length} check${report.config.disabledChecks.length === 1 ? "" : "s"} disabled)`)));
123
125
  }
124
126
 
125
127
  // src/components/App.tsx
@@ -190,7 +192,7 @@ function App({
190
192
  setMonorepoReport(r);
191
193
  setProjectName(`monorepo (${r.packages.length} packages)`);
192
194
  try {
193
- const { getDependencyTree } = await import("./dist-IEANON4U.js");
195
+ const { getDependencyTree } = await import("./dist-LQY3FYCP.js");
194
196
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
195
197
  const packages = {};
196
198
  for (const pkg of r.packages) {
@@ -202,7 +204,7 @@ function App({
202
204
  if (openWeb) {
203
205
  setPhase("opening-web");
204
206
  try {
205
- const { serveWeb } = await import("./web-3JO6YQIG.js");
207
+ const { serveWeb } = await import("./web-2KWCYTW4.js");
206
208
  const { default: openBrowser } = await import("open");
207
209
  let aiService;
208
210
  if (enableAI && process.env.ANTHROPIC_API_KEY) {
@@ -259,7 +261,7 @@ function App({
259
261
  } catch {
260
262
  }
261
263
  try {
262
- const { getDependencyTree } = await import("./dist-IEANON4U.js");
264
+ const { getDependencyTree } = await import("./dist-LQY3FYCP.js");
263
265
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
264
266
  const tree = await getDependencyTree(projectPath, r.projectInfo.packageManager);
265
267
  saveDepTree(projectPath, tree);
@@ -268,7 +270,7 @@ function App({
268
270
  if (openWeb) {
269
271
  setPhase("opening-web");
270
272
  try {
271
- const { serveWeb } = await import("./web-3JO6YQIG.js");
273
+ const { serveWeb } = await import("./web-2KWCYTW4.js");
272
274
  const { default: openBrowser } = await import("open");
273
275
  let aiService;
274
276
  if (enableAI && process.env.ANTHROPIC_API_KEY) {
@@ -307,7 +309,10 @@ function MonorepoSummaryTable({
307
309
  scanDuration
308
310
  }) {
309
311
  const scoreColor = (score) => score >= 80 ? "green" : score >= 60 ? "yellow" : "red";
310
- return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box6, { marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Monorepo \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, report.monorepoType, " workspaces \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, report.packages.length, " packages")), report.packages.map((pkg) => /* @__PURE__ */ React6.createElement(Box6, { key: pkg.path, marginLeft: 2, gap: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: scoreColor(pkg.score) }, scoreBar(pkg.score)), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: scoreColor(pkg.score) }, String(pkg.score).padStart(3)), /* @__PURE__ */ React6.createElement(Text6, null, pkg.name), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, pkg.framework), pkg.summary.critical > 0 && /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, " ", pkg.summary.critical, " critical"))), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, gap: 2 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Overall: "), /* @__PURE__ */ React6.createElement(Text6, { color: scoreColor(report.overallScore), bold: true }, report.overallScore), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, report.summary.critical, " critical"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, report.summary.warnings, " warnings"), scanDuration !== null && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\xB7 "), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, formatDuration2(scanDuration)))), report.quote && /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { italic: true, dimColor: true }, '"', report.quote.text, '"'), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \u2014 ", report.quote.source)), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "Per-package details: "), /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, "sickbay --web")));
312
+ return /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column" }, /* @__PURE__ */ React6.createElement(Box6, { marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Monorepo \xB7 "), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, report.monorepoType, " workspaces \xB7 "), /* @__PURE__ */ React6.createElement(Text6, null, report.packages.length, " packages")), report.packages.map((pkg) => /* @__PURE__ */ React6.createElement(Box6, { key: pkg.path, marginLeft: 2, gap: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: scoreColor(pkg.score) }, scoreBar(pkg.score)), /* @__PURE__ */ React6.createElement(Text6, { bold: true, color: scoreColor(pkg.score) }, String(pkg.score).padStart(3)), /* @__PURE__ */ React6.createElement(Text6, null, pkg.name), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, pkg.framework), pkg.summary.critical > 0 && /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, " ", pkg.summary.critical, " critical"))), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1, gap: 2 }, /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "Overall: "), /* @__PURE__ */ React6.createElement(Text6, { color: scoreColor(report.overallScore), bold: true }, report.overallScore), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\xB7 "), (() => {
313
+ const u = countUniqueIssues(report.packages.flatMap((p) => p.checks));
314
+ return /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "red" }, u.critical, " critical", u.totalCritical > u.critical ? ` (${u.totalCritical} total)` : ""), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\xB7 "), /* @__PURE__ */ React6.createElement(Text6, { color: "yellow" }, u.warnings, " warnings", u.totalWarnings > u.warnings ? ` (${u.totalWarnings} total)` : ""));
315
+ })(), scanDuration !== null && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "\xB7 "), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, formatDuration2(scanDuration)))), report.quote && /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { italic: true, dimColor: true }, '"', report.quote.text, '"'), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " \u2014 ", report.quote.source)), /* @__PURE__ */ React6.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, "Per-package details: "), /* @__PURE__ */ React6.createElement(Text6, { color: "cyan" }, "sickbay --web")));
311
316
  }
312
317
 
313
318
  // src/index.ts
@@ -317,7 +322,7 @@ if (existsSync(globalConfigPath)) {
317
322
  }
318
323
  config({ debug: false, quiet: true });
319
324
  var program = new Command();
320
- program.name("sickbay").description("React project health check CLI").version("1.15.9", "-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) => {
325
+ program.name("sickbay").description("React project health check CLI").version("1.16.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) => {
321
326
  if (!existsSync(options.path)) {
322
327
  process.stderr.write(`Error: path does not exist: ${options.path}
323
328
  `);
@@ -332,13 +337,13 @@ program.name("sickbay").description("React project health check CLI").version("1
332
337
  const updatePromise = (async () => {
333
338
  try {
334
339
  const { checkForUpdate } = await import("./update-check-M7IFOMLJ.js");
335
- return await checkForUpdate("1.15.9");
340
+ return await checkForUpdate("1.16.0");
336
341
  } catch {
337
342
  return null;
338
343
  }
339
344
  })();
340
345
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
341
- const { detectMonorepo, runSickbay: runSickbay2, runSickbayMonorepo: runSickbayMonorepo2, getAvailableChecks } = await import("./dist-IEANON4U.js");
346
+ const { detectMonorepo, runSickbay: runSickbay2, runSickbayMonorepo: runSickbayMonorepo2, getAvailableChecks } = await import("./dist-LQY3FYCP.js");
342
347
  if (checks && checks.length > 0) {
343
348
  const knownNames = new Set(getAvailableChecks().map((c) => c.name));
344
349
  const unknown = checks.filter((c) => !knownNames.has(c));
@@ -410,7 +415,7 @@ program.name("sickbay").description("React project health check CLI").version("1
410
415
  } catch {
411
416
  }
412
417
  try {
413
- const { getDependencyTree } = await import("./dist-IEANON4U.js");
418
+ const { getDependencyTree } = await import("./dist-LQY3FYCP.js");
414
419
  const { saveDepTree } = await import("./history-XLNVZEDI.js");
415
420
  const tree = await getDependencyTree(options.path, report.projectInfo.packageManager);
416
421
  saveDepTree(options.path, tree);
@@ -437,16 +442,16 @@ program.command("init").description("Initialize .sickbay/ folder and run an init
437
442
  "add newly available checks to existing config without touching existing entries"
438
443
  ).option("--reset-config", "regenerate config from scratch (overwrites existing)").action(async (options) => {
439
444
  if (options.resetConfig) {
440
- const { generateConfigFile } = await import("./init-PVZHRY3T.js");
445
+ const { generateConfigFile } = await import("./init-DD2HOQE2.js");
441
446
  await generateConfigFile(options.path, { force: true });
442
447
  return;
443
448
  }
444
449
  if (options.sync) {
445
- const { syncConfigFile } = await import("./init-PVZHRY3T.js");
450
+ const { syncConfigFile } = await import("./init-DD2HOQE2.js");
446
451
  await syncConfigFile(options.path);
447
452
  return;
448
453
  }
449
- const { initSickbay } = await import("./init-PVZHRY3T.js");
454
+ const { initSickbay } = await import("./init-DD2HOQE2.js");
450
455
  await initSickbay(options.path);
451
456
  });
452
457
  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) => {
@@ -456,9 +461,9 @@ program.command("fix").description("Interactively fix issues found by sickbay sc
456
461
  config({ path: projectEnvPath, override: true });
457
462
  }
458
463
  }
459
- const { resolveProject } = await import("./resolve-package-LP7CD7JU.js");
464
+ const { resolveProject } = await import("./resolve-package-774YTW5Q.js");
460
465
  const resolution = await resolveProject(options.path, options.package);
461
- const { FixApp } = await import("./FixApp-H7W77W6M.js");
466
+ const { FixApp } = await import("./FixApp-WUUS3QM6.js");
462
467
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
463
468
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
464
469
  render(
@@ -481,10 +486,10 @@ program.command("trend").description("Show score history and trends over time").
481
486
  config({ path: projectEnvPath, override: true });
482
487
  }
483
488
  }
484
- const { resolveProject } = await import("./resolve-package-LP7CD7JU.js");
489
+ const { resolveProject } = await import("./resolve-package-774YTW5Q.js");
485
490
  const resolution = await resolveProject(options.path, options.package);
486
491
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
487
- const { TrendApp } = await import("./TrendApp-5LK7JZ3Y.js");
492
+ const { TrendApp } = await import("./TrendApp-SZURVP7W.js");
488
493
  render(
489
494
  React7.createElement(TrendApp, {
490
495
  projectPath,
@@ -503,10 +508,10 @@ program.command("stats").description("Show a quick codebase overview and project
503
508
  config({ path: projectEnvPath, override: true });
504
509
  }
505
510
  }
506
- const { resolveProject } = await import("./resolve-package-LP7CD7JU.js");
511
+ const { resolveProject } = await import("./resolve-package-774YTW5Q.js");
507
512
  const resolution = await resolveProject(options.path, options.package);
508
513
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
509
- const { StatsApp } = await import("./StatsApp-XYGCOHKG.js");
514
+ const { StatsApp } = await import("./StatsApp-BF5LYVRA.js");
510
515
  render(
511
516
  React7.createElement(StatsApp, {
512
517
  projectPath,
@@ -518,7 +523,7 @@ program.command("stats").description("Show a quick codebase overview and project
518
523
  );
519
524
  });
520
525
  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) => {
521
- const { TuiApp } = await import("./TuiApp-GN57TL66.js");
526
+ const { TuiApp } = await import("./TuiApp-3ZU3KG24.js");
522
527
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
523
528
  render(
524
529
  React7.createElement(TuiApp, {
@@ -538,10 +543,10 @@ program.command("doctor").description("Diagnose project setup and configuration
538
543
  config({ path: projectEnvPath, override: true });
539
544
  }
540
545
  }
541
- const { resolveProject } = await import("./resolve-package-LP7CD7JU.js");
546
+ const { resolveProject } = await import("./resolve-package-774YTW5Q.js");
542
547
  const resolution = await resolveProject(options.path, options.package);
543
548
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
544
- const { DoctorApp } = await import("./DoctorApp-3MUEJRYX.js");
549
+ const { DoctorApp } = await import("./DoctorApp-OS5MITI5.js");
545
550
  render(
546
551
  React7.createElement(DoctorApp, {
547
552
  projectPath,
@@ -554,13 +559,13 @@ program.command("doctor").description("Diagnose project setup and configuration
554
559
  );
555
560
  });
556
561
  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) => {
557
- const { resolveProject } = await import("./resolve-package-LP7CD7JU.js");
562
+ const { resolveProject } = await import("./resolve-package-774YTW5Q.js");
558
563
  const resolution = await resolveProject(options.path, options.package);
559
564
  const projectPath = resolution.isMonorepo ? resolution.targetPath ?? options.path : resolution.targetPath;
560
565
  const { loadScoreFromLastReport, badgeUrl, badgeMarkdown, badgeHtml } = await import("./badge-KQ73KEIN.js");
561
566
  let score = options.scan ? null : loadScoreFromLastReport(projectPath);
562
567
  if (score === null) {
563
- const { runSickbay: runSickbay2 } = await import("./dist-IEANON4U.js");
568
+ const { runSickbay: runSickbay2 } = await import("./dist-LQY3FYCP.js");
564
569
  const report = await runSickbay2({ projectPath, quotes: false });
565
570
  try {
566
571
  const { saveEntry, saveLastReport } = await import("./history-XLNVZEDI.js");
@@ -593,7 +598,7 @@ program.command("diff <branch>").description("Compare health score against anoth
593
598
  }
594
599
  }
595
600
  const checks = options.checks ? options.checks.split(",").map((s) => s.trim()) : void 0;
596
- const { DiffApp } = await import("./DiffApp-W7AYJXAC.js");
601
+ const { DiffApp } = await import("./DiffApp-V3GF6YM7.js");
597
602
  render(
598
603
  React7.createElement(DiffApp, {
599
604
  projectPath: options.path,
@@ -4,7 +4,7 @@ import {
4
4
  getAvailableChecks,
5
5
  runSickbay,
6
6
  runSickbayMonorepo
7
- } from "./chunk-W4GJ5ISW.js";
7
+ } from "./chunk-DJA6K3MN.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-IQYSZ3UW.js";
5
- import "./chunk-W4GJ5ISW.js";
4
+ } from "./chunk-VBM6NZAY.js";
5
+ import "./chunk-DJA6K3MN.js";
6
6
  export {
7
7
  resolveProject,
8
8
  shortName
@@ -1,2 +1,2 @@
1
- import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{a as t,i as n,n as r,r as i,t as a}from"./markdown-oPAUxr3B.js";import{i as o}from"./react-DeNSbYyc.js";var s=o(),c=e(t(),1),l=n();function u(e){let t=(0,s.c)(3),{content:n}=e,o;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(o={code(e){let{className:t,children:n,...i}=e,o=/language-(\w+)/.exec(t||``);return o?(0,l.jsx)(r,{style:a,language:o[1],PreTag:`div`,className:`rounded-md bg-black/30! mt-2! mb-2!`,customStyle:{margin:0,padding:`0.75rem`},...i,children:String(n).replace(/\n$/,``)}):(0,l.jsx)(`code`,{className:`bg-black/30 px-1.5 py-0.5 rounded-sm text-accent font-mono text-xs`,...i,children:n})},p(e){let{children:t}=e;return(0,l.jsx)(`p`,{className:`mb-2 last:mb-0`,children:t})},ul(e){let{children:t}=e;return(0,l.jsx)(`ul`,{className:`list-disc list-inside mb-2 space-y-1`,children:t})},ol(e){let{children:t}=e;return(0,l.jsx)(`ol`,{className:`list-decimal list-inside mb-2 space-y-1`,children:t})},li(e){let{children:t}=e;return(0,l.jsx)(`li`,{className:`text-sm`,children:t})},strong(e){let{children:t}=e;return(0,l.jsx)(`strong`,{className:`font-semibold text-white`,children:t})},em(e){let{children:t}=e;return(0,l.jsx)(`em`,{className:`italic text-gray-200`,children:t})},a(e){let{href:t,children:n}=e;return(0,l.jsx)(`a`,{href:t,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent hover:underline`,children:n})}},t[0]=o):o=t[0];let c;return t[1]===n?c=t[2]:(c=(0,l.jsx)(`div`,{className:`prose prose-invert prose-sm max-w-none`,children:(0,l.jsx)(i,{components:o,children:n})}),t[1]=n,t[2]=c),c}function d({report:e,packageName:t}){let[n,r]=(0,c.useState)(!1),[i,a]=(0,c.useState)(null),[o,s]=(0,c.useState)([]),[d,f]=(0,c.useState)(``),[p,m]=(0,c.useState)(!1),h=(0,c.useRef)(null);(0,c.useEffect)(()=>{fetch(`/ai/summary`,{method:`HEAD`}).then(e=>a(e.ok)).catch(()=>a(!1))},[]),(0,c.useEffect)(()=>{s([]),r(!1)},[t]),(0,c.useEffect)(()=>{h.current?.scrollIntoView({behavior:`smooth`})},[o]);let g=async()=>{if(!d.trim()||p)return;let e={role:`user`,content:d};s(t=>[...t,e]),f(``),m(!0);try{let e=t?`/ai/chat?package=${encodeURIComponent(t)}`:`/ai/chat`,n=await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({message:d,history:o})});if(n.ok){let e={role:`assistant`,content:(await n.json()).response};s(t=>[...t,e])}else{let e={role:`assistant`,content:`Sorry, I encountered an error. Please try again.`};s(t=>[...t,e])}}catch{let e={role:`assistant`,content:`Sorry, I encountered an error. Please try again.`};s(t=>[...t,e])}finally{m(!1)}};return i===!1?null:(0,l.jsxs)(l.Fragment,{children:[!n&&(0,l.jsx)(`button`,{onClick:()=>r(!0),className:`fixed bottom-6 right-6 w-14 h-14 bg-accent text-black rounded-sm shadow-lg hover:shadow-xl transition-all hover:scale-110 flex items-center justify-center text-2xl z-50`,title:`AI Assistant`,children:`VAI`}),n&&(0,l.jsxs)(`div`,{className:`fixed bottom-6 right-6 w-140 h-200 bg-surface border border-border rounded-lg shadow-2xl flex flex-col z-50`,children:[(0,l.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-3 border-b border-border`,children:[(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(`span`,{className:`text-lg`,children:(0,l.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`32`,height:`32`,viewBox:`0 0 24 24`,children:(0,l.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeWidth:`1.5`,d:`M9.6 6.112c.322-.816 1.478-.816 1.8 0l.91 2.31a5.8 5.8 0 0 0 3.268 3.268l2.31.91c.816.322.816 1.478 0 1.8l-2.31.91a5.8 5.8 0 0 0-3.268 3.268l-.91 2.31c-.322.816-1.478.816-1.8 0l-.91-2.31a5.8 5.8 0 0 0-3.268-3.268l-2.31-.91c-.816-.322-.816-1.478 0-1.8l2.31-.91A5.8 5.8 0 0 0 8.69 8.422zm8.563-3.382a.363.363 0 0 1 .674 0l.342.866c.221.56.665 1.004 1.225 1.225l.866.342a.363.363 0 0 1 0 .674l-.866.342a2.18 2.18 0 0 0-1.225 1.225l-.342.866a.363.363 0 0 1-.674 0l-.342-.866a2.18 2.18 0 0 0-1.225-1.225l-.867-.342a.363.363 0 0 1 0-.674l.867-.342a2.18 2.18 0 0 0 1.225-1.225z`})})}),(0,l.jsx)(`span`,{className:`font-semibold text-sm`,children:`AI Assistant`})]}),(0,l.jsx)(`button`,{onClick:()=>r(!1),className:`text-gray-500 hover:text-white transition-colors text-lg`,children:`✕`})]}),(0,l.jsxs)(`div`,{className:`flex-1 overflow-y-auto p-4 space-y-3`,children:[o.length===0&&(0,l.jsxs)(`div`,{className:`text-sm text-gray-500 text-center py-8`,children:[`Ask me anything about your project health!`,(0,l.jsx)(`div`,{className:`mt-2 text-xs text-gray-600`,children:`Try: "What should I fix first?" or "Explain the security issues"`})]}),o.map((e,t)=>(0,l.jsx)(`div`,{className:`flex ${e.role===`user`?`justify-end`:`justify-start`}`,children:(0,l.jsx)(`div`,{className:`max-w-[80%] px-3 py-2 rounded-lg text-sm ${e.role===`user`?`bg-accent text-black font-medium`:`bg-card text-gray-300`}`,children:e.role===`assistant`?(0,l.jsx)(u,{content:e.content}):e.content})},`${e.role}-${t}`)),p&&(0,l.jsx)(`div`,{className:`flex justify-start`,children:(0,l.jsx)(`div`,{className:`bg-card text-gray-500 px-3 py-2 rounded-lg text-sm`,children:(0,l.jsx)(`span`,{className:`animate-pulse`,children:`⠋ thinking...`})})}),(0,l.jsx)(`div`,{ref:h})]}),(0,l.jsx)(`div`,{className:`px-4 py-3 border-t border-border`,children:(0,l.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),g()},className:`flex gap-2`,children:[(0,l.jsx)(`input`,{type:`text`,value:d,onChange:e=>f(e.target.value),placeholder:`Ask about your project...`,disabled:p,className:`flex-1 bg-card border border-border rounded-sm px-3 py-2 text-sm focus:outline-hidden focus:border-accent disabled:opacity-50`}),(0,l.jsx)(`button`,{type:`submit`,disabled:p||!d.trim(),className:`px-4 py-2 bg-accent text-black rounded-sm text-sm font-semibold hover:bg-accent/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,children:`Send`})]})})]})]})}export{d as ChatDrawer};
2
- //# sourceMappingURL=ChatDrawer-dCdqFiGs.js.map
1
+ import{i as e}from"./rolldown-runtime-B1FJdls4.js";import{a as t,i as n,n as r,r as i,t as a}from"./markdown-vE-W5L19.js";import{i as o}from"./react-Cd_U1vkF.js";var s=o(),c=e(t(),1),l=n();function u(e){let t=(0,s.c)(3),{content:n}=e,o;t[0]===Symbol.for(`react.memo_cache_sentinel`)?(o={code(e){let{className:t,children:n,...i}=e,o=/language-(\w+)/.exec(t||``);return o?(0,l.jsx)(r,{style:a,language:o[1],PreTag:`div`,className:`rounded-md bg-black/30! mt-2! mb-2!`,customStyle:{margin:0,padding:`0.75rem`},...i,children:String(n).replace(/\n$/,``)}):(0,l.jsx)(`code`,{className:`bg-black/30 px-1.5 py-0.5 rounded-sm text-accent font-mono text-xs`,...i,children:n})},p(e){let{children:t}=e;return(0,l.jsx)(`p`,{className:`mb-2 last:mb-0`,children:t})},ul(e){let{children:t}=e;return(0,l.jsx)(`ul`,{className:`list-disc list-inside mb-2 space-y-1`,children:t})},ol(e){let{children:t}=e;return(0,l.jsx)(`ol`,{className:`list-decimal list-inside mb-2 space-y-1`,children:t})},li(e){let{children:t}=e;return(0,l.jsx)(`li`,{className:`text-sm`,children:t})},strong(e){let{children:t}=e;return(0,l.jsx)(`strong`,{className:`font-semibold text-white`,children:t})},em(e){let{children:t}=e;return(0,l.jsx)(`em`,{className:`italic text-gray-200`,children:t})},a(e){let{href:t,children:n}=e;return(0,l.jsx)(`a`,{href:t,target:`_blank`,rel:`noopener noreferrer`,className:`text-accent hover:underline`,children:n})}},t[0]=o):o=t[0];let c;return t[1]===n?c=t[2]:(c=(0,l.jsx)(`div`,{className:`prose prose-invert prose-sm max-w-none`,children:(0,l.jsx)(i,{components:o,children:n})}),t[1]=n,t[2]=c),c}function d({report:e,packageName:t}){let[n,r]=(0,c.useState)(!1),[i,a]=(0,c.useState)(null),[o,s]=(0,c.useState)([]),[d,f]=(0,c.useState)(``),[p,m]=(0,c.useState)(!1),h=(0,c.useRef)(null);(0,c.useEffect)(()=>{fetch(`/ai/summary`,{method:`HEAD`}).then(e=>a(e.ok)).catch(()=>a(!1))},[]),(0,c.useEffect)(()=>{s([]),r(!1)},[t]),(0,c.useEffect)(()=>{h.current?.scrollIntoView({behavior:`smooth`})},[o]);let g=async()=>{if(!d.trim()||p)return;let e={role:`user`,content:d};s(t=>[...t,e]),f(``),m(!0);try{let e=t?`/ai/chat?package=${encodeURIComponent(t)}`:`/ai/chat`,n=await fetch(e,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({message:d,history:o})});if(n.ok){let e={role:`assistant`,content:(await n.json()).response};s(t=>[...t,e])}else{let e={role:`assistant`,content:`Sorry, I encountered an error. Please try again.`};s(t=>[...t,e])}}catch{let e={role:`assistant`,content:`Sorry, I encountered an error. Please try again.`};s(t=>[...t,e])}finally{m(!1)}};return i===!1?null:(0,l.jsxs)(l.Fragment,{children:[!n&&(0,l.jsx)(`button`,{onClick:()=>r(!0),className:`fixed bottom-6 right-6 w-14 h-14 bg-accent text-black rounded-sm shadow-lg hover:shadow-xl transition-all hover:scale-110 flex items-center justify-center text-2xl z-50`,title:`AI Assistant`,children:`VAI`}),n&&(0,l.jsxs)(`div`,{className:`fixed bottom-6 right-6 w-140 h-200 bg-surface border border-border rounded-lg shadow-2xl flex flex-col z-50`,children:[(0,l.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-3 border-b border-border`,children:[(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsx)(`span`,{className:`text-lg`,children:(0,l.jsx)(`svg`,{xmlns:`http://www.w3.org/2000/svg`,width:`32`,height:`32`,viewBox:`0 0 24 24`,children:(0,l.jsx)(`path`,{fill:`none`,stroke:`currentColor`,strokeWidth:`1.5`,d:`M9.6 6.112c.322-.816 1.478-.816 1.8 0l.91 2.31a5.8 5.8 0 0 0 3.268 3.268l2.31.91c.816.322.816 1.478 0 1.8l-2.31.91a5.8 5.8 0 0 0-3.268 3.268l-.91 2.31c-.322.816-1.478.816-1.8 0l-.91-2.31a5.8 5.8 0 0 0-3.268-3.268l-2.31-.91c-.816-.322-.816-1.478 0-1.8l2.31-.91A5.8 5.8 0 0 0 8.69 8.422zm8.563-3.382a.363.363 0 0 1 .674 0l.342.866c.221.56.665 1.004 1.225 1.225l.866.342a.363.363 0 0 1 0 .674l-.866.342a2.18 2.18 0 0 0-1.225 1.225l-.342.866a.363.363 0 0 1-.674 0l-.342-.866a2.18 2.18 0 0 0-1.225-1.225l-.867-.342a.363.363 0 0 1 0-.674l.867-.342a2.18 2.18 0 0 0 1.225-1.225z`})})}),(0,l.jsx)(`span`,{className:`font-semibold text-sm`,children:`AI Assistant`})]}),(0,l.jsx)(`button`,{onClick:()=>r(!1),className:`text-gray-500 hover:text-white transition-colors text-lg`,children:`✕`})]}),(0,l.jsxs)(`div`,{className:`flex-1 overflow-y-auto p-4 space-y-3`,children:[o.length===0&&(0,l.jsxs)(`div`,{className:`text-sm text-gray-500 text-center py-8`,children:[`Ask me anything about your project health!`,(0,l.jsx)(`div`,{className:`mt-2 text-xs text-gray-600`,children:`Try: "What should I fix first?" or "Explain the security issues"`})]}),o.map((e,t)=>(0,l.jsx)(`div`,{className:`flex ${e.role===`user`?`justify-end`:`justify-start`}`,children:(0,l.jsx)(`div`,{className:`max-w-[80%] px-3 py-2 rounded-lg text-sm ${e.role===`user`?`bg-accent text-black font-medium`:`bg-card text-gray-300`}`,children:e.role===`assistant`?(0,l.jsx)(u,{content:e.content}):e.content})},`${e.role}-${t}`)),p&&(0,l.jsx)(`div`,{className:`flex justify-start`,children:(0,l.jsx)(`div`,{className:`bg-card text-gray-500 px-3 py-2 rounded-lg text-sm`,children:(0,l.jsx)(`span`,{className:`animate-pulse`,children:`⠋ thinking...`})})}),(0,l.jsx)(`div`,{ref:h})]}),(0,l.jsx)(`div`,{className:`px-4 py-3 border-t border-border`,children:(0,l.jsxs)(`form`,{onSubmit:e=>{e.preventDefault(),g()},className:`flex gap-2`,children:[(0,l.jsx)(`input`,{type:`text`,value:d,onChange:e=>f(e.target.value),placeholder:`Ask about your project...`,disabled:p,className:`flex-1 bg-card border border-border rounded-sm px-3 py-2 text-sm focus:outline-hidden focus:border-accent disabled:opacity-50`}),(0,l.jsx)(`button`,{type:`submit`,disabled:p||!d.trim(),className:`px-4 py-2 bg-accent text-black rounded-sm text-sm font-semibold hover:bg-accent/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors`,children:`Send`})]})})]})]})}export{d as ChatDrawer};
2
+ //# sourceMappingURL=ChatDrawer-Bbnv0gOr.js.map