glassbox 0.4.3 → 0.5.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/cli.js +291 -73
- package/dist/client/app.global.js +8 -8
- package/dist/client/styles.css +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -395,7 +395,7 @@ init_queries();
|
|
|
395
395
|
init_connection();
|
|
396
396
|
import { mkdirSync as mkdirSync7 } from "fs";
|
|
397
397
|
import { tmpdir } from "os";
|
|
398
|
-
import { join as join10, resolve as
|
|
398
|
+
import { join as join10, resolve as resolve5 } from "path";
|
|
399
399
|
|
|
400
400
|
// src/debug.ts
|
|
401
401
|
var debugEnabled = false;
|
|
@@ -1723,7 +1723,7 @@ async function updateReviewDiffs(reviewId, newDiffs, headCommit) {
|
|
|
1723
1723
|
// src/server.ts
|
|
1724
1724
|
import { serve } from "@hono/node-server";
|
|
1725
1725
|
import { exec } from "child_process";
|
|
1726
|
-
import { existsSync as existsSync6, readFileSync as
|
|
1726
|
+
import { existsSync as existsSync6, readFileSync as readFileSync9 } from "fs";
|
|
1727
1727
|
import { Hono as Hono4 } from "hono";
|
|
1728
1728
|
import { dirname, join as join7 } from "path";
|
|
1729
1729
|
import { fileURLToPath } from "url";
|
|
@@ -2445,8 +2445,8 @@ function isRetriable(err) {
|
|
|
2445
2445
|
return msg.includes("429") || msg.includes("500") || msg.includes("502") || msg.includes("503") || msg.includes("504") || msg.includes("rate_limit");
|
|
2446
2446
|
}
|
|
2447
2447
|
function sleep(ms) {
|
|
2448
|
-
return new Promise((
|
|
2449
|
-
setTimeout(
|
|
2448
|
+
return new Promise((resolve6) => {
|
|
2449
|
+
setTimeout(resolve6, ms);
|
|
2450
2450
|
});
|
|
2451
2451
|
}
|
|
2452
2452
|
|
|
@@ -2490,8 +2490,8 @@ function randomLines(count) {
|
|
|
2490
2490
|
return lines.sort((a, b) => a.line - b.line);
|
|
2491
2491
|
}
|
|
2492
2492
|
function sleep2(ms) {
|
|
2493
|
-
return new Promise((
|
|
2494
|
-
setTimeout(
|
|
2493
|
+
return new Promise((resolve6) => {
|
|
2494
|
+
setTimeout(resolve6, ms);
|
|
2495
2495
|
});
|
|
2496
2496
|
}
|
|
2497
2497
|
async function mockRiskAnalysisBatch(files) {
|
|
@@ -4059,6 +4059,71 @@ apiRoutes.get("/outline/:fileId", async (c) => {
|
|
|
4059
4059
|
const symbols = parseOutline(content, file.file_path);
|
|
4060
4060
|
return c.json({ symbols });
|
|
4061
4061
|
});
|
|
4062
|
+
apiRoutes.get("/symbol-definition", async (c) => {
|
|
4063
|
+
const name = c.req.query("name");
|
|
4064
|
+
const currentFileId = c.req.query("currentFileId");
|
|
4065
|
+
if (!name) return c.json({ definitions: [] });
|
|
4066
|
+
const reviewId = resolveReviewId(c);
|
|
4067
|
+
const repoRoot = c.get("repoRoot");
|
|
4068
|
+
const definitions = [];
|
|
4069
|
+
const searchedPaths = /* @__PURE__ */ new Set();
|
|
4070
|
+
const reviewFiles = await getReviewFiles(reviewId);
|
|
4071
|
+
for (const file of reviewFiles) {
|
|
4072
|
+
searchedPaths.add(file.file_path);
|
|
4073
|
+
const diff = JSON.parse(file.diff_data ?? "{}");
|
|
4074
|
+
const isDeleted = diff.status === "deleted";
|
|
4075
|
+
let content = "";
|
|
4076
|
+
try {
|
|
4077
|
+
content = isDeleted ? getFileContent(file.file_path, "HEAD", repoRoot) : getFileContent(file.file_path, "working", repoRoot);
|
|
4078
|
+
} catch {
|
|
4079
|
+
continue;
|
|
4080
|
+
}
|
|
4081
|
+
if (!content) continue;
|
|
4082
|
+
const symbols = parseOutline(content, file.file_path);
|
|
4083
|
+
collectDefinitions(symbols, name, file.id, file.file_path, definitions);
|
|
4084
|
+
}
|
|
4085
|
+
if (definitions.length === 0) {
|
|
4086
|
+
try {
|
|
4087
|
+
const allFiles = execSync5("git ls-files", { cwd: repoRoot, encoding: "utf-8" }).trim().split("\n").filter(Boolean);
|
|
4088
|
+
for (const filePath of allFiles) {
|
|
4089
|
+
if (searchedPaths.has(filePath)) continue;
|
|
4090
|
+
const ext = filePath.slice(filePath.lastIndexOf("."));
|
|
4091
|
+
if (!/\.(js|mjs|cjs|jsx|ts|tsx|mts|cts|java|go|rs|c|h|cpp|cc|cxx|hpp|cs|swift|php|kt|kts|scala|dart|groovy|py|rb)$/i.test(ext)) continue;
|
|
4092
|
+
let content = "";
|
|
4093
|
+
try {
|
|
4094
|
+
content = readFileSync7(resolve3(repoRoot, filePath), "utf-8");
|
|
4095
|
+
} catch {
|
|
4096
|
+
continue;
|
|
4097
|
+
}
|
|
4098
|
+
if (!content) continue;
|
|
4099
|
+
const symbols = parseOutline(content, filePath);
|
|
4100
|
+
collectDefinitions(symbols, name, null, filePath, definitions);
|
|
4101
|
+
if (definitions.length > 0) break;
|
|
4102
|
+
}
|
|
4103
|
+
} catch {
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
definitions.sort((a, b) => {
|
|
4107
|
+
if (a.fileId === currentFileId && b.fileId !== currentFileId) return -1;
|
|
4108
|
+
if (b.fileId === currentFileId && a.fileId !== currentFileId) return 1;
|
|
4109
|
+
if (a.fileId !== null && b.fileId === null) return -1;
|
|
4110
|
+
if (b.fileId !== null && a.fileId === null) return 1;
|
|
4111
|
+
if (a.kind === "class" && b.kind !== "class") return -1;
|
|
4112
|
+
if (b.kind === "class" && a.kind !== "class") return 1;
|
|
4113
|
+
return 0;
|
|
4114
|
+
});
|
|
4115
|
+
return c.json({ definitions });
|
|
4116
|
+
});
|
|
4117
|
+
function collectDefinitions(symbols, targetName, fileId, filePath, out) {
|
|
4118
|
+
for (const sym of symbols) {
|
|
4119
|
+
if (sym.name === targetName) {
|
|
4120
|
+
out.push({ fileId, filePath, name: sym.name, kind: sym.kind, line: sym.line });
|
|
4121
|
+
}
|
|
4122
|
+
if (sym.children?.length > 0) {
|
|
4123
|
+
collectDefinitions(sym.children, targetName, fileId, filePath, out);
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4062
4127
|
apiRoutes.get("/context/:fileId", async (c) => {
|
|
4063
4128
|
const repoRoot = c.get("repoRoot");
|
|
4064
4129
|
const file = await getReviewFile(c.req.param("fileId"));
|
|
@@ -4155,7 +4220,9 @@ apiRoutes.get("/image/:fileId/:side", async (c) => {
|
|
|
4155
4220
|
});
|
|
4156
4221
|
|
|
4157
4222
|
// src/routes/pages.tsx
|
|
4223
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
4158
4224
|
import { Hono as Hono3 } from "hono";
|
|
4225
|
+
import { resolve as resolve4 } from "path";
|
|
4159
4226
|
|
|
4160
4227
|
// src/utils/escapeHtml.ts
|
|
4161
4228
|
function escapeHtml(str) {
|
|
@@ -4332,6 +4399,9 @@ function jsx(tag, props) {
|
|
|
4332
4399
|
const childStr = children != null ? renderChildren(children) : "";
|
|
4333
4400
|
return new SafeHtml(`<${tag}${attrStr}>${childStr}</${tag}>`);
|
|
4334
4401
|
}
|
|
4402
|
+
function Fragment({ children }) {
|
|
4403
|
+
return new SafeHtml(children != null ? renderChildren(children) : "");
|
|
4404
|
+
}
|
|
4335
4405
|
|
|
4336
4406
|
// src/icons.tsx
|
|
4337
4407
|
var S14 = { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" };
|
|
@@ -4392,6 +4462,64 @@ function IconActualSize() {
|
|
|
4392
4462
|
] });
|
|
4393
4463
|
}
|
|
4394
4464
|
|
|
4465
|
+
// src/utils/charDiff.ts
|
|
4466
|
+
function charDiff(oldStr, newStr) {
|
|
4467
|
+
if (!oldStr && !newStr) return null;
|
|
4468
|
+
if (oldStr === newStr) return null;
|
|
4469
|
+
const lcs = lcsTable(oldStr, newStr);
|
|
4470
|
+
const lcsLen = lcs[oldStr.length][newStr.length];
|
|
4471
|
+
const maxLen = Math.max(oldStr.length, newStr.length);
|
|
4472
|
+
if (maxLen === 0) return null;
|
|
4473
|
+
if (lcsLen / maxLen < 0.2) return null;
|
|
4474
|
+
const oldCommon = /* @__PURE__ */ new Set();
|
|
4475
|
+
const newCommon = /* @__PURE__ */ new Set();
|
|
4476
|
+
let i = oldStr.length, j = newStr.length;
|
|
4477
|
+
while (i > 0 && j > 0) {
|
|
4478
|
+
if (oldStr[i - 1] === newStr[j - 1]) {
|
|
4479
|
+
oldCommon.add(i - 1);
|
|
4480
|
+
newCommon.add(j - 1);
|
|
4481
|
+
i--;
|
|
4482
|
+
j--;
|
|
4483
|
+
} else if (lcs[i - 1][j] > lcs[i][j - 1]) {
|
|
4484
|
+
i--;
|
|
4485
|
+
} else {
|
|
4486
|
+
j--;
|
|
4487
|
+
}
|
|
4488
|
+
}
|
|
4489
|
+
return {
|
|
4490
|
+
oldSegments: buildSegments(oldStr, oldCommon),
|
|
4491
|
+
newSegments: buildSegments(newStr, newCommon)
|
|
4492
|
+
};
|
|
4493
|
+
}
|
|
4494
|
+
function lcsTable(a, b) {
|
|
4495
|
+
const m = a.length, n = b.length;
|
|
4496
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
4497
|
+
for (let i = 1; i <= m; i++) {
|
|
4498
|
+
for (let j = 1; j <= n; j++) {
|
|
4499
|
+
dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] + 1 : Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
4500
|
+
}
|
|
4501
|
+
}
|
|
4502
|
+
return dp;
|
|
4503
|
+
}
|
|
4504
|
+
function buildSegments(str, commonPositions) {
|
|
4505
|
+
const segments = [];
|
|
4506
|
+
let current = "";
|
|
4507
|
+
let currentChanged = false;
|
|
4508
|
+
for (let i = 0; i < str.length; i++) {
|
|
4509
|
+
const changed = !commonPositions.has(i);
|
|
4510
|
+
if (changed !== currentChanged && current.length > 0) {
|
|
4511
|
+
segments.push({ text: current, changed: currentChanged });
|
|
4512
|
+
current = "";
|
|
4513
|
+
}
|
|
4514
|
+
currentChanged = changed;
|
|
4515
|
+
current += str[i];
|
|
4516
|
+
}
|
|
4517
|
+
if (current.length > 0) {
|
|
4518
|
+
segments.push({ text: current, changed: currentChanged });
|
|
4519
|
+
}
|
|
4520
|
+
return segments;
|
|
4521
|
+
}
|
|
4522
|
+
|
|
4395
4523
|
// src/components/imageDiff.tsx
|
|
4396
4524
|
function ImageDiff({ file, diff, fontWarning, baseWidth, baseHeight }) {
|
|
4397
4525
|
const fileId = file.id;
|
|
@@ -4519,7 +4647,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
|
|
|
4519
4647
|
"data-new-line": group.pair.left?.newNum ?? group.pair.right?.newNum ?? "",
|
|
4520
4648
|
children: [
|
|
4521
4649
|
/* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": group.pair.left?.oldNum ?? "" }),
|
|
4522
|
-
/* @__PURE__ */ jsx("span", { className: "code", children: group.pair
|
|
4650
|
+
/* @__PURE__ */ jsx("span", { className: "code", children: renderPairContent(group.pair, "left") })
|
|
4523
4651
|
]
|
|
4524
4652
|
}
|
|
4525
4653
|
),
|
|
@@ -4531,7 +4659,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
|
|
|
4531
4659
|
"data-side": "new",
|
|
4532
4660
|
children: [
|
|
4533
4661
|
/* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": group.pair.right?.newNum ?? "" }),
|
|
4534
|
-
/* @__PURE__ */ jsx("span", { className: "code", children: group.pair
|
|
4662
|
+
/* @__PURE__ */ jsx("span", { className: "code", children: renderPairContent(group.pair, "right") })
|
|
4535
4663
|
]
|
|
4536
4664
|
}
|
|
4537
4665
|
)
|
|
@@ -4581,7 +4709,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
|
|
|
4581
4709
|
"data-new-line": pair.left?.newNum ?? pair.right?.newNum ?? "",
|
|
4582
4710
|
children: [
|
|
4583
4711
|
/* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": pair.left?.oldNum ?? "" }),
|
|
4584
|
-
/* @__PURE__ */ jsx("span", { className: "code", children: pair
|
|
4712
|
+
/* @__PURE__ */ jsx("span", { className: "code", children: renderPairContent(pair, "left") })
|
|
4585
4713
|
]
|
|
4586
4714
|
}
|
|
4587
4715
|
);
|
|
@@ -4626,7 +4754,7 @@ function SplitDiff({ hunks, annotationsByLine }) {
|
|
|
4626
4754
|
"data-side": "new",
|
|
4627
4755
|
children: [
|
|
4628
4756
|
/* @__PURE__ */ jsx("span", { className: "gutter", "data-line-number": pair.right?.newNum ?? "" }),
|
|
4629
|
-
/* @__PURE__ */ jsx("span", { className: "code", children: pair
|
|
4757
|
+
/* @__PURE__ */ jsx("span", { className: "code", children: renderPairContent(pair, "right") })
|
|
4630
4758
|
]
|
|
4631
4759
|
}
|
|
4632
4760
|
);
|
|
@@ -4634,6 +4762,20 @@ function SplitDiff({ hunks, annotationsByLine }) {
|
|
|
4634
4762
|
] });
|
|
4635
4763
|
}) });
|
|
4636
4764
|
}
|
|
4765
|
+
function renderSegments(segments) {
|
|
4766
|
+
return /* @__PURE__ */ jsx(Fragment, { children: segments.map((s) => s.changed ? /* @__PURE__ */ jsx("span", { className: "char-change", children: s.text }) : /* @__PURE__ */ jsx(Fragment, { children: s.text })) });
|
|
4767
|
+
}
|
|
4768
|
+
function renderPairContent(pair, side) {
|
|
4769
|
+
const line = side === "left" ? pair.left : pair.right;
|
|
4770
|
+
if (!line) return "";
|
|
4771
|
+
if (pair.left && pair.right && pair.left.type === "remove" && pair.right.type === "add") {
|
|
4772
|
+
const diff = charDiff(pair.left.content, pair.right.content);
|
|
4773
|
+
if (diff) {
|
|
4774
|
+
return renderSegments(side === "left" ? diff.oldSegments : diff.newSegments);
|
|
4775
|
+
}
|
|
4776
|
+
}
|
|
4777
|
+
return line.content;
|
|
4778
|
+
}
|
|
4637
4779
|
function pairLines(lines) {
|
|
4638
4780
|
const pairs = [];
|
|
4639
4781
|
let i = 0;
|
|
@@ -4667,55 +4809,88 @@ function pairLines(lines) {
|
|
|
4667
4809
|
}
|
|
4668
4810
|
return pairs;
|
|
4669
4811
|
}
|
|
4812
|
+
function buildUnifiedCharDiffs(lines) {
|
|
4813
|
+
const result = /* @__PURE__ */ new Map();
|
|
4814
|
+
let i = 0;
|
|
4815
|
+
while (i < lines.length) {
|
|
4816
|
+
if (lines[i].type === "remove") {
|
|
4817
|
+
const removes = [];
|
|
4818
|
+
while (i < lines.length && lines[i].type === "remove") {
|
|
4819
|
+
removes.push(lines[i]);
|
|
4820
|
+
i++;
|
|
4821
|
+
}
|
|
4822
|
+
const adds = [];
|
|
4823
|
+
while (i < lines.length && lines[i].type === "add") {
|
|
4824
|
+
adds.push(lines[i]);
|
|
4825
|
+
i++;
|
|
4826
|
+
}
|
|
4827
|
+
const pairCount = Math.min(removes.length, adds.length);
|
|
4828
|
+
for (let j = 0; j < pairCount; j++) {
|
|
4829
|
+
const diff = charDiff(removes[j].content, adds[j].content);
|
|
4830
|
+
if (diff) {
|
|
4831
|
+
result.set(removes[j], diff.oldSegments);
|
|
4832
|
+
result.set(adds[j], diff.newSegments);
|
|
4833
|
+
}
|
|
4834
|
+
}
|
|
4835
|
+
} else {
|
|
4836
|
+
i++;
|
|
4837
|
+
}
|
|
4838
|
+
}
|
|
4839
|
+
return result;
|
|
4840
|
+
}
|
|
4670
4841
|
function UnifiedDiff({ hunks, annotationsByLine }) {
|
|
4671
4842
|
const lastHunk = hunks[hunks.length - 1];
|
|
4672
4843
|
const tailStart = lastHunk ? lastHunk.newStart + lastHunk.newCount : 1;
|
|
4673
4844
|
return /* @__PURE__ */ jsx("div", { className: "diff-table-unified", children: [
|
|
4674
|
-
hunks.map((hunk, hunkIdx) =>
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
"
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
"
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4845
|
+
hunks.map((hunk, hunkIdx) => {
|
|
4846
|
+
const charDiffs = buildUnifiedCharDiffs(hunk.lines);
|
|
4847
|
+
return /* @__PURE__ */ jsx("div", { className: "hunk-block", children: [
|
|
4848
|
+
/* @__PURE__ */ jsx(
|
|
4849
|
+
"div",
|
|
4850
|
+
{
|
|
4851
|
+
className: "hunk-separator",
|
|
4852
|
+
"data-hunk-idx": hunkIdx,
|
|
4853
|
+
"data-old-start": hunk.oldStart,
|
|
4854
|
+
"data-old-count": hunk.oldCount,
|
|
4855
|
+
"data-new-start": hunk.newStart,
|
|
4856
|
+
"data-new-count": hunk.newCount,
|
|
4857
|
+
children: [
|
|
4858
|
+
"@@ -",
|
|
4859
|
+
hunk.oldStart,
|
|
4860
|
+
",",
|
|
4861
|
+
hunk.oldCount,
|
|
4862
|
+
" +",
|
|
4863
|
+
hunk.newStart,
|
|
4864
|
+
",",
|
|
4865
|
+
hunk.newCount,
|
|
4866
|
+
" @@"
|
|
4867
|
+
]
|
|
4868
|
+
}
|
|
4869
|
+
),
|
|
4870
|
+
hunk.lines.map((line) => {
|
|
4871
|
+
const lineNum = line.type === "remove" ? line.oldNum : line.newNum;
|
|
4872
|
+
const side = line.type === "remove" ? "old" : "new";
|
|
4873
|
+
const anns = annotationsByLine[`${lineNum}:${side}`] ?? [];
|
|
4874
|
+
const segments = charDiffs.get(line);
|
|
4875
|
+
return /* @__PURE__ */ jsx("div", { children: [
|
|
4876
|
+
/* @__PURE__ */ jsx(
|
|
4877
|
+
"div",
|
|
4878
|
+
{
|
|
4879
|
+
className: `diff-line ${line.type}${anns.length ? " has-annotation" : ""}`,
|
|
4880
|
+
"data-line": lineNum,
|
|
4881
|
+
"data-side": side,
|
|
4882
|
+
children: [
|
|
4883
|
+
/* @__PURE__ */ jsx("span", { className: "gutter-old", "data-line-number": line.oldNum ?? "" }),
|
|
4884
|
+
/* @__PURE__ */ jsx("span", { className: "gutter-new", "data-line-number": line.newNum ?? "" }),
|
|
4885
|
+
/* @__PURE__ */ jsx("span", { className: "code", children: segments ? renderSegments(segments) : line.content })
|
|
4886
|
+
]
|
|
4887
|
+
}
|
|
4888
|
+
),
|
|
4889
|
+
anns.length > 0 ? /* @__PURE__ */ jsx(AnnotationRows, { annotations: anns }) : null
|
|
4890
|
+
] });
|
|
4891
|
+
})
|
|
4892
|
+
] });
|
|
4893
|
+
}),
|
|
4719
4894
|
/* @__PURE__ */ jsx("div", { className: "hunk-separator hunk-expander-tail", "data-start": tailStart, children: "\u2195 Show remaining lines" })
|
|
4720
4895
|
] });
|
|
4721
4896
|
}
|
|
@@ -4951,6 +5126,11 @@ pageRoutes.get("/", async (c) => {
|
|
|
4951
5126
|
] }),
|
|
4952
5127
|
/* @__PURE__ */ jsx("p", { className: "progress-summary", id: "progress-summary" })
|
|
4953
5128
|
] }),
|
|
5129
|
+
/* @__PURE__ */ jsx("div", { className: "diff-nav-bar", id: "diff-nav-bar", style: "display:none", children: [
|
|
5130
|
+
/* @__PURE__ */ jsx("button", { className: "nav-btn disabled", id: "nav-back-btn", disabled: true, title: "Back", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
5131
|
+
/* @__PURE__ */ jsx("button", { className: "nav-btn disabled", id: "nav-forward-btn", disabled: true, title: "Forward", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) }) }),
|
|
5132
|
+
/* @__PURE__ */ jsx("span", { className: "nav-file-path", id: "nav-file-path" })
|
|
5133
|
+
] }),
|
|
4954
5134
|
/* @__PURE__ */ jsx("div", { className: "diff-container", id: "diff-container", style: "display:none" }),
|
|
4955
5135
|
/* @__PURE__ */ jsx("div", { className: "diff-toolbar", id: "diff-toolbar", style: "display:none", children: [
|
|
4956
5136
|
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-svg-toggle", style: "display:none", children: /* @__PURE__ */ jsx("div", { className: "segmented-control", children: [
|
|
@@ -5053,6 +5233,39 @@ pageRoutes.get("/file/:fileId", async (c) => {
|
|
|
5053
5233
|
const html = /* @__PURE__ */ jsx(DiffView, { file, diff: finalDiff, annotations, mode });
|
|
5054
5234
|
return c.html(html.toString());
|
|
5055
5235
|
});
|
|
5236
|
+
pageRoutes.get("/file-raw", (c) => {
|
|
5237
|
+
const filePath = c.req.query("path");
|
|
5238
|
+
if (!filePath) return c.text("Missing path", 400);
|
|
5239
|
+
const repoRoot = c.get("repoRoot");
|
|
5240
|
+
let content;
|
|
5241
|
+
try {
|
|
5242
|
+
content = readFileSync8(resolve4(repoRoot, filePath), "utf-8");
|
|
5243
|
+
} catch {
|
|
5244
|
+
return c.text("File not found", 404);
|
|
5245
|
+
}
|
|
5246
|
+
const lines = content.split("\n");
|
|
5247
|
+
const diff = {
|
|
5248
|
+
filePath,
|
|
5249
|
+
oldPath: null,
|
|
5250
|
+
status: "added",
|
|
5251
|
+
isBinary: false,
|
|
5252
|
+
hunks: [{
|
|
5253
|
+
oldStart: 0,
|
|
5254
|
+
oldCount: 0,
|
|
5255
|
+
newStart: 1,
|
|
5256
|
+
newCount: lines.length,
|
|
5257
|
+
lines: lines.map((line, i) => ({
|
|
5258
|
+
type: "context",
|
|
5259
|
+
oldNum: i + 1,
|
|
5260
|
+
newNum: i + 1,
|
|
5261
|
+
content: line
|
|
5262
|
+
}))
|
|
5263
|
+
}]
|
|
5264
|
+
};
|
|
5265
|
+
const fakeFile = { id: "", review_id: "", file_path: filePath, status: "reviewed", diff_data: null };
|
|
5266
|
+
const html = /* @__PURE__ */ jsx(DiffView, { file: fakeFile, diff, annotations: [], mode: "unified" });
|
|
5267
|
+
return c.html(html.toString());
|
|
5268
|
+
});
|
|
5056
5269
|
pageRoutes.get("/review/:reviewId", async (c) => {
|
|
5057
5270
|
const reviewId = c.req.param("reviewId");
|
|
5058
5271
|
const currentReviewId = c.get("reviewId");
|
|
@@ -5102,6 +5315,11 @@ pageRoutes.get("/review/:reviewId", async (c) => {
|
|
|
5102
5315
|
] }),
|
|
5103
5316
|
/* @__PURE__ */ jsx("p", { className: "progress-summary", id: "progress-summary" })
|
|
5104
5317
|
] }),
|
|
5318
|
+
/* @__PURE__ */ jsx("div", { className: "diff-nav-bar", id: "diff-nav-bar", style: "display:none", children: [
|
|
5319
|
+
/* @__PURE__ */ jsx("button", { className: "nav-btn disabled", id: "nav-back-btn", disabled: true, title: "Back", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
5320
|
+
/* @__PURE__ */ jsx("button", { className: "nav-btn disabled", id: "nav-forward-btn", disabled: true, title: "Forward", children: /* @__PURE__ */ jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx("path", { d: "m9 18 6-6-6-6" }) }) }),
|
|
5321
|
+
/* @__PURE__ */ jsx("span", { className: "nav-file-path", id: "nav-file-path" })
|
|
5322
|
+
] }),
|
|
5105
5323
|
/* @__PURE__ */ jsx("div", { className: "diff-container", id: "diff-container", style: "display:none" }),
|
|
5106
5324
|
/* @__PURE__ */ jsx("div", { className: "diff-toolbar", id: "diff-toolbar", style: "display:none", children: [
|
|
5107
5325
|
/* @__PURE__ */ jsx("div", { className: "diff-toolbar-svg-toggle", style: "display:none", children: /* @__PURE__ */ jsx("div", { className: "segmented-control", children: [
|
|
@@ -5149,10 +5367,10 @@ pageRoutes.get("/history", async (c) => {
|
|
|
5149
5367
|
|
|
5150
5368
|
// src/server.ts
|
|
5151
5369
|
function tryServe(fetch2, port) {
|
|
5152
|
-
return new Promise((
|
|
5370
|
+
return new Promise((resolve6, reject) => {
|
|
5153
5371
|
const server = serve({ fetch: fetch2, port });
|
|
5154
5372
|
server.on("listening", () => {
|
|
5155
|
-
|
|
5373
|
+
resolve6(port);
|
|
5156
5374
|
});
|
|
5157
5375
|
server.on("error", (err) => {
|
|
5158
5376
|
if (err.code === "EADDRINUSE") {
|
|
@@ -5174,15 +5392,15 @@ async function startServer(port, reviewId, repoRoot, options) {
|
|
|
5174
5392
|
const selfDir = dirname(fileURLToPath(import.meta.url));
|
|
5175
5393
|
const distDir = existsSync6(join7(selfDir, "client", "styles.css")) ? join7(selfDir, "client") : join7(selfDir, "..", "dist", "client");
|
|
5176
5394
|
app.get("/static/styles.css", (c) => {
|
|
5177
|
-
const css =
|
|
5395
|
+
const css = readFileSync9(join7(distDir, "styles.css"), "utf-8");
|
|
5178
5396
|
return c.text(css, 200, { "Content-Type": "text/css", "Cache-Control": "no-cache" });
|
|
5179
5397
|
});
|
|
5180
5398
|
app.get("/static/app.js", (c) => {
|
|
5181
|
-
const js =
|
|
5399
|
+
const js = readFileSync9(join7(distDir, "app.global.js"), "utf-8");
|
|
5182
5400
|
return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
|
|
5183
5401
|
});
|
|
5184
5402
|
app.get("/static/history.js", (c) => {
|
|
5185
|
-
const js =
|
|
5403
|
+
const js = readFileSync9(join7(distDir, "history.global.js"), "utf-8");
|
|
5186
5404
|
return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
|
|
5187
5405
|
});
|
|
5188
5406
|
app.route("/api", apiRoutes);
|
|
@@ -5218,7 +5436,7 @@ async function startServer(port, reviewId, repoRoot, options) {
|
|
|
5218
5436
|
}
|
|
5219
5437
|
|
|
5220
5438
|
// src/skills.ts
|
|
5221
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as
|
|
5439
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
5222
5440
|
import { join as join8 } from "path";
|
|
5223
5441
|
var SKILL_VERSION = 1;
|
|
5224
5442
|
function versionHeader() {
|
|
@@ -5231,7 +5449,7 @@ function parseVersionHeader(content) {
|
|
|
5231
5449
|
}
|
|
5232
5450
|
function updateFile(path, content) {
|
|
5233
5451
|
if (existsSync7(path)) {
|
|
5234
|
-
const existing =
|
|
5452
|
+
const existing = readFileSync10(path, "utf-8");
|
|
5235
5453
|
const version = parseVersionHeader(existing);
|
|
5236
5454
|
if (version !== null && version >= SKILL_VERSION) {
|
|
5237
5455
|
return false;
|
|
@@ -5335,7 +5553,7 @@ function ensureSkills() {
|
|
|
5335
5553
|
}
|
|
5336
5554
|
|
|
5337
5555
|
// src/update-check.ts
|
|
5338
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as
|
|
5556
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
|
|
5339
5557
|
import { get } from "https";
|
|
5340
5558
|
import { homedir as homedir3 } from "os";
|
|
5341
5559
|
import { dirname as dirname2, join as join9 } from "path";
|
|
@@ -5346,7 +5564,7 @@ var PACKAGE_NAME = "glassbox";
|
|
|
5346
5564
|
function getCurrentVersion() {
|
|
5347
5565
|
try {
|
|
5348
5566
|
const dir = dirname2(fileURLToPath2(import.meta.url));
|
|
5349
|
-
const pkg = JSON.parse(
|
|
5567
|
+
const pkg = JSON.parse(readFileSync11(join9(dir, "..", "package.json"), "utf-8"));
|
|
5350
5568
|
return pkg.version;
|
|
5351
5569
|
} catch {
|
|
5352
5570
|
return "0.0.0";
|
|
@@ -5355,7 +5573,7 @@ function getCurrentVersion() {
|
|
|
5355
5573
|
function getLastCheckDate() {
|
|
5356
5574
|
try {
|
|
5357
5575
|
if (existsSync8(CHECK_FILE)) {
|
|
5358
|
-
return
|
|
5576
|
+
return readFileSync11(CHECK_FILE, "utf-8").trim();
|
|
5359
5577
|
}
|
|
5360
5578
|
} catch {
|
|
5361
5579
|
}
|
|
@@ -5372,10 +5590,10 @@ function isFirstUseToday() {
|
|
|
5372
5590
|
return last !== today;
|
|
5373
5591
|
}
|
|
5374
5592
|
function fetchLatestVersion() {
|
|
5375
|
-
return new Promise((
|
|
5593
|
+
return new Promise((resolve6) => {
|
|
5376
5594
|
const req = get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, { timeout: 5e3 }, (res) => {
|
|
5377
5595
|
if (res.statusCode !== 200) {
|
|
5378
|
-
|
|
5596
|
+
resolve6(null);
|
|
5379
5597
|
return;
|
|
5380
5598
|
}
|
|
5381
5599
|
let data = "";
|
|
@@ -5384,18 +5602,18 @@ function fetchLatestVersion() {
|
|
|
5384
5602
|
});
|
|
5385
5603
|
res.on("end", () => {
|
|
5386
5604
|
try {
|
|
5387
|
-
|
|
5605
|
+
resolve6(JSON.parse(data).version);
|
|
5388
5606
|
} catch {
|
|
5389
|
-
|
|
5607
|
+
resolve6(null);
|
|
5390
5608
|
}
|
|
5391
5609
|
});
|
|
5392
5610
|
});
|
|
5393
5611
|
req.on("error", () => {
|
|
5394
|
-
|
|
5612
|
+
resolve6(null);
|
|
5395
5613
|
});
|
|
5396
5614
|
req.on("timeout", () => {
|
|
5397
5615
|
req.destroy();
|
|
5398
|
-
|
|
5616
|
+
resolve6(null);
|
|
5399
5617
|
});
|
|
5400
5618
|
});
|
|
5401
5619
|
}
|
|
@@ -5533,7 +5751,7 @@ function parseArgs(argv) {
|
|
|
5533
5751
|
port = parseInt(args[++i], 10);
|
|
5534
5752
|
break;
|
|
5535
5753
|
case "--data-dir":
|
|
5536
|
-
dataDir =
|
|
5754
|
+
dataDir = resolve5(args[++i]);
|
|
5537
5755
|
break;
|
|
5538
5756
|
case "--resume":
|
|
5539
5757
|
resume = true;
|
|
@@ -5589,7 +5807,7 @@ async function main() {
|
|
|
5589
5807
|
console.log("AI service test mode enabled \u2014 using mock AI responses");
|
|
5590
5808
|
}
|
|
5591
5809
|
if (debug) {
|
|
5592
|
-
console.log(`[debug] Build timestamp: ${"2026-03-
|
|
5810
|
+
console.log(`[debug] Build timestamp: ${"2026-03-23T04:00:15.529Z"}`);
|
|
5593
5811
|
}
|
|
5594
5812
|
if (projectDir) {
|
|
5595
5813
|
process.chdir(projectDir);
|