sickbay 1.15.10 → 1.16.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-W7AYJXAC.js → DiffApp-ASQWWDLS.js} +2 -2
- package/dist/{DoctorApp-3MUEJRYX.js → DoctorApp-SMIZDD64.js} +3 -3
- package/dist/{FixApp-H7W77W6M.js → FixApp-63PU5VF7.js} +3 -3
- package/dist/{StatsApp-XYGCOHKG.js → StatsApp-CFZBEITZ.js} +3 -3
- package/dist/{TrendApp-5LK7JZ3Y.js → TrendApp-BKGRSP6Q.js} +3 -3
- package/dist/{TuiApp-GN57TL66.js → TuiApp-K7KP35RC.js} +9 -7
- package/dist/{chunk-S7IEDXU2.js → chunk-352RAVRZ.js} +1 -1
- package/dist/{chunk-W4GJ5ISW.js → chunk-DJA6K3MN.js} +15 -1
- package/dist/{chunk-TYG7ZQBP.js → chunk-LZOEMCE7.js} +27 -0
- package/dist/{chunk-IQYSZ3UW.js → chunk-VBM6NZAY.js} +1 -1
- package/dist/config.js +1 -1
- package/dist/{dist-IEANON4U.js → dist-LQY3FYCP.js} +1 -1
- package/dist/index.js +34 -29
- package/dist/{init-PVZHRY3T.js → init-DD2HOQE2.js} +1 -1
- package/dist/{resolve-package-LP7CD7JU.js → resolve-package-774YTW5Q.js} +2 -2
- package/dist/web/assets/{ChatDrawer-dCdqFiGs.js → ChatDrawer-Bbnv0gOr.js} +2 -2
- package/dist/web/assets/{ChatDrawer-dCdqFiGs.js.map → ChatDrawer-Bbnv0gOr.js.map} +1 -1
- package/dist/web/assets/{DependencyGraph-BSJPytrP.js → DependencyGraph-DwrNnbRv.js} +2 -2
- package/dist/web/assets/{DependencyGraph-BSJPytrP.js.map → DependencyGraph-DwrNnbRv.js.map} +1 -1
- package/dist/web/assets/MonorepoOverview-B5pKk2xN.js +2 -0
- package/dist/web/assets/MonorepoOverview-B5pKk2xN.js.map +1 -0
- package/dist/web/assets/{index-B23n764F.css → index-CPMhENPs.css} +1 -1
- package/dist/web/assets/index-CqHC2egK.js +16 -0
- package/dist/web/assets/index-CqHC2egK.js.map +1 -0
- package/dist/web/assets/issue-grouping-183B2uea.js +2 -0
- package/dist/web/assets/issue-grouping-183B2uea.js.map +1 -0
- package/dist/web/assets/{markdown-oPAUxr3B.js → markdown-vE-W5L19.js} +2 -2
- package/dist/web/assets/{markdown-oPAUxr3B.js.map → markdown-vE-W5L19.js.map} +1 -1
- package/dist/web/assets/{react-DeNSbYyc.js → react-Cd_U1vkF.js} +3 -3
- package/dist/web/assets/{react-DeNSbYyc.js.map → react-Cd_U1vkF.js.map} +1 -1
- package/dist/web/index.html +5 -5
- package/dist/{web-3JO6YQIG.js → web-2KWCYTW4.js} +1 -1
- package/package.json +6 -6
- package/dist/web/assets/MonorepoOverview-DDbHHZi0.js +0 -2
- package/dist/web/assets/MonorepoOverview-DDbHHZi0.js.map +0 -1
- package/dist/web/assets/constants-DYzuOu1F.js +0 -2
- package/dist/web/assets/constants-DYzuOu1F.js.map +0 -1
- package/dist/web/assets/index-Bzeb-9jh.js +0 -16
- package/dist/web/assets/index-Bzeb-9jh.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Header
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-352RAVRZ.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-
|
|
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-
|
|
3
|
+
} from "./chunk-VBM6NZAY.js";
|
|
4
4
|
import {
|
|
5
5
|
Header
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-352RAVRZ.js";
|
|
7
7
|
import {
|
|
8
8
|
detectPackageManager,
|
|
9
9
|
detectProject
|
|
10
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
9
|
+
} from "./chunk-352RAVRZ.js";
|
|
10
10
|
import {
|
|
11
11
|
runSickbay
|
|
12
|
-
} from "./chunk-
|
|
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-
|
|
3
|
+
} from "./chunk-VBM6NZAY.js";
|
|
4
4
|
import {
|
|
5
5
|
Header
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-352RAVRZ.js";
|
|
7
7
|
import {
|
|
8
8
|
detectProject
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
7
|
+
} from "./chunk-VBM6NZAY.js";
|
|
8
8
|
import {
|
|
9
9
|
Header
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
} from "./chunk-352RAVRZ.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
|
-
|
|
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-
|
|
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
|
-
|
|
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.
|
|
710
|
+
checkForUpdate("1.15.10").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-
|
|
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-
|
|
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) {
|
|
@@ -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.
|
|
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.10")), 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 {
|
|
@@ -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,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
|
};
|
package/dist/config.js
CHANGED
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
|
-
|
|
7
|
+
UpdateNotice,
|
|
8
|
+
countUniqueIssues
|
|
9
|
+
} from "./chunk-LZOEMCE7.js";
|
|
9
10
|
import {
|
|
10
11
|
Header
|
|
11
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-352RAVRZ.js";
|
|
12
13
|
import {
|
|
13
14
|
getScoreEmoji,
|
|
14
15
|
runSickbay,
|
|
15
16
|
runSickbayMonorepo
|
|
16
|
-
} from "./chunk-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 "),
|
|
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.
|
|
325
|
+
program.name("sickbay").description("React project health check CLI").version("1.15.10", "-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.
|
|
340
|
+
return await checkForUpdate("1.15.10");
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
466
|
+
const { FixApp } = await import("./FixApp-63PU5VF7.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-
|
|
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-
|
|
492
|
+
const { TrendApp } = await import("./TrendApp-BKGRSP6Q.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-
|
|
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-
|
|
514
|
+
const { StatsApp } = await import("./StatsApp-CFZBEITZ.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-
|
|
526
|
+
const { TuiApp } = await import("./TuiApp-K7KP35RC.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-
|
|
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-
|
|
549
|
+
const { DoctorApp } = await import("./DoctorApp-SMIZDD64.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-
|
|
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-
|
|
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-
|
|
601
|
+
const { DiffApp } = await import("./DiffApp-ASQWWDLS.js");
|
|
597
602
|
render(
|
|
598
603
|
React7.createElement(DiffApp, {
|
|
599
604
|
projectPath: options.path,
|
|
@@ -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-
|
|
2
|
-
//# sourceMappingURL=ChatDrawer-
|
|
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
|