glassbox 0.15.0 → 0.16.0-beta.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.
- package/dist/cli.js +119 -159
- package/package.json +3 -2
package/dist/cli.js
CHANGED
|
@@ -16176,10 +16176,10 @@ __export(blob_store_exports, {
|
|
|
16176
16176
|
readDifftoolBlob: () => readDifftoolBlob,
|
|
16177
16177
|
writeDifftoolBlob: () => writeDifftoolBlob
|
|
16178
16178
|
});
|
|
16179
|
-
import { existsSync as
|
|
16180
|
-
import { join as
|
|
16179
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync7, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "fs";
|
|
16180
|
+
import { join as join8 } from "path";
|
|
16181
16181
|
function blobDir(dataDir) {
|
|
16182
|
-
return
|
|
16182
|
+
return join8(dataDir, "difftool-blobs");
|
|
16183
16183
|
}
|
|
16184
16184
|
function blobName(fileId, side) {
|
|
16185
16185
|
return `${fileId.replace(/[^a-z0-9]/gi, "")}-${side}`;
|
|
@@ -16188,11 +16188,11 @@ function writeDifftoolBlob(dataDir, fileId, side, bytes) {
|
|
|
16188
16188
|
if (bytes.length === 0) return;
|
|
16189
16189
|
const dir = blobDir(dataDir);
|
|
16190
16190
|
mkdirSync6(dir, { recursive: true });
|
|
16191
|
-
writeFileSync7(
|
|
16191
|
+
writeFileSync7(join8(dir, blobName(fileId, side)), bytes);
|
|
16192
16192
|
}
|
|
16193
16193
|
function readDifftoolBlob(dataDir, fileId, side) {
|
|
16194
|
-
const path =
|
|
16195
|
-
if (!
|
|
16194
|
+
const path = join8(blobDir(dataDir), blobName(fileId, side));
|
|
16195
|
+
if (!existsSync7(path)) return null;
|
|
16196
16196
|
try {
|
|
16197
16197
|
return readFileSync7(path);
|
|
16198
16198
|
} catch {
|
|
@@ -16715,17 +16715,17 @@ __export(difftool_discovery_exports, {
|
|
|
16715
16715
|
tryAcquireStartingLock: () => tryAcquireStartingLock,
|
|
16716
16716
|
writeDiscovery: () => writeDiscovery
|
|
16717
16717
|
});
|
|
16718
|
-
import { existsSync as
|
|
16718
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync12, readFileSync as readFileSync18, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync12 } from "fs";
|
|
16719
16719
|
import { homedir as homedir4 } from "os";
|
|
16720
|
-
import { join as
|
|
16720
|
+
import { join as join17 } from "path";
|
|
16721
16721
|
function difftoolHome() {
|
|
16722
|
-
return
|
|
16722
|
+
return join17(homedir4(), ".glassbox");
|
|
16723
16723
|
}
|
|
16724
16724
|
function discoveryPath(home = difftoolHome()) {
|
|
16725
|
-
return
|
|
16725
|
+
return join17(home, "difftool.lock");
|
|
16726
16726
|
}
|
|
16727
16727
|
function startingLockPath(home = difftoolHome()) {
|
|
16728
|
-
return
|
|
16728
|
+
return join17(home, "difftool-starting.lock");
|
|
16729
16729
|
}
|
|
16730
16730
|
function parseDiscovery(raw2) {
|
|
16731
16731
|
let parsed;
|
|
@@ -16739,7 +16739,7 @@ function parseDiscovery(raw2) {
|
|
|
16739
16739
|
}
|
|
16740
16740
|
function readDiscovery(home = difftoolHome()) {
|
|
16741
16741
|
const path = discoveryPath(home);
|
|
16742
|
-
if (!
|
|
16742
|
+
if (!existsSync14(path)) return null;
|
|
16743
16743
|
try {
|
|
16744
16744
|
return parseDiscovery(readFileSync18(path, "utf-8"));
|
|
16745
16745
|
} catch {
|
|
@@ -16797,9 +16797,9 @@ var init_difftool_discovery = __esm({
|
|
|
16797
16797
|
// src/cli.ts
|
|
16798
16798
|
init_connection();
|
|
16799
16799
|
init_queries();
|
|
16800
|
-
import { existsSync as
|
|
16800
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync13, realpathSync, statSync as statSync5 } from "fs";
|
|
16801
16801
|
import { tmpdir as tmpdir2 } from "os";
|
|
16802
|
-
import { basename as basename2, join as
|
|
16802
|
+
import { basename as basename2, join as join18, resolve as resolve10 } from "path";
|
|
16803
16803
|
|
|
16804
16804
|
// src/debug.ts
|
|
16805
16805
|
var debugEnabled = false;
|
|
@@ -18528,9 +18528,9 @@ async function updateReviewDiffs(reviewId, newDiffs, headCommit) {
|
|
|
18528
18528
|
|
|
18529
18529
|
// src/server.ts
|
|
18530
18530
|
import { serve } from "@hono/node-server";
|
|
18531
|
-
import { existsSync as
|
|
18531
|
+
import { existsSync as existsSync11, readFileSync as readFileSync15 } from "fs";
|
|
18532
18532
|
import { Hono as Hono19 } from "hono";
|
|
18533
|
-
import { dirname as dirname4, join as
|
|
18533
|
+
import { dirname as dirname4, join as join14 } from "path";
|
|
18534
18534
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
18535
18535
|
|
|
18536
18536
|
// src/channel-config.ts
|
|
@@ -18697,64 +18697,24 @@ function reviewNotesExportSection(repoRoot, filePaths) {
|
|
|
18697
18697
|
init_zod();
|
|
18698
18698
|
|
|
18699
18699
|
// src/ai/apple-foundation.ts
|
|
18700
|
-
|
|
18701
|
-
import { spawn } from "child_process";
|
|
18702
|
-
import { existsSync as existsSync6 } from "fs";
|
|
18703
|
-
import { join as join7 } from "path";
|
|
18704
|
-
var defaultRunner = (bin, args, stdin) => new Promise((resolve11, reject) => {
|
|
18705
|
-
const child = spawn(bin, args, { stdio: ["pipe", "pipe", "ignore"] });
|
|
18706
|
-
let stdout = "";
|
|
18707
|
-
child.stdout.setEncoding("utf-8");
|
|
18708
|
-
child.stdout.on("data", (chunk) => {
|
|
18709
|
-
stdout += chunk;
|
|
18710
|
-
});
|
|
18711
|
-
child.on("error", reject);
|
|
18712
|
-
child.on("close", (code) => {
|
|
18713
|
-
resolve11({ stdout, code: code ?? 0 });
|
|
18714
|
-
});
|
|
18715
|
-
child.stdin.end(stdin);
|
|
18716
|
-
});
|
|
18717
|
-
var runner = defaultRunner;
|
|
18718
|
-
var isDarwin = process.platform === "darwin";
|
|
18700
|
+
import { generate, isPlatformSupported, probe } from "apple-fm";
|
|
18719
18701
|
var availabilityCache = null;
|
|
18720
|
-
function appleFmBinPath() {
|
|
18721
|
-
const env = process.env.GLASSBOX_APPLE_FM_BIN;
|
|
18722
|
-
if (env !== void 0 && env !== "" && existsSync6(env)) return env;
|
|
18723
|
-
const fallback = join7(process.cwd(), "apple-fm-helper");
|
|
18724
|
-
if (existsSync6(fallback)) return fallback;
|
|
18725
|
-
return null;
|
|
18726
|
-
}
|
|
18727
18702
|
async function isAppleFoundationAvailable() {
|
|
18728
18703
|
if (availabilityCache !== null) return availabilityCache;
|
|
18729
18704
|
availabilityCache = await probeAvailability();
|
|
18730
18705
|
return availabilityCache;
|
|
18731
18706
|
}
|
|
18732
18707
|
async function probeAvailability() {
|
|
18733
|
-
if (!
|
|
18734
|
-
const bin = appleFmBinPath();
|
|
18735
|
-
if (bin === null) return false;
|
|
18708
|
+
if (!isPlatformSupported()) return false;
|
|
18736
18709
|
try {
|
|
18737
|
-
const
|
|
18738
|
-
return
|
|
18710
|
+
const result = await probe();
|
|
18711
|
+
return result.available;
|
|
18739
18712
|
} catch {
|
|
18740
18713
|
return false;
|
|
18741
18714
|
}
|
|
18742
18715
|
}
|
|
18743
|
-
var InferOutputSchema = external_exports.object({ content: external_exports.string() });
|
|
18744
18716
|
async function runAppleFoundationInfer(system, messages) {
|
|
18745
|
-
|
|
18746
|
-
if (bin === null) throw new Error("Apple Foundation Models helper not found");
|
|
18747
|
-
const { stdout, code } = await runner(bin, ["--infer"], JSON.stringify({ system, messages }));
|
|
18748
|
-
if (code !== 0) throw new Error(`Apple Foundation Models helper exited with code ${String(code)}`);
|
|
18749
|
-
let raw2;
|
|
18750
|
-
try {
|
|
18751
|
-
raw2 = JSON.parse(stdout);
|
|
18752
|
-
} catch {
|
|
18753
|
-
throw new Error("Apple Foundation Models helper returned non-JSON output");
|
|
18754
|
-
}
|
|
18755
|
-
const parsed = InferOutputSchema.safeParse(raw2);
|
|
18756
|
-
if (!parsed.success) throw new Error("Apple Foundation Models helper returned an unexpected payload");
|
|
18757
|
-
return parsed.data.content;
|
|
18717
|
+
return generate({ system, messages });
|
|
18758
18718
|
}
|
|
18759
18719
|
|
|
18760
18720
|
// src/ai/client.ts
|
|
@@ -21707,10 +21667,10 @@ init_queries();
|
|
|
21707
21667
|
init_zod();
|
|
21708
21668
|
init_queries();
|
|
21709
21669
|
import { spawnSync as spawnSync6 } from "child_process";
|
|
21710
|
-
import { appendFileSync, existsSync as
|
|
21670
|
+
import { appendFileSync, existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
21711
21671
|
import { homedir as homedir2 } from "os";
|
|
21712
|
-
import { join as
|
|
21713
|
-
var DISMISS_FILE =
|
|
21672
|
+
import { join as join7 } from "path";
|
|
21673
|
+
var DISMISS_FILE = join7(homedir2(), ".glassbox", "gitignore-dismissed.json");
|
|
21714
21674
|
var DISMISS_DAYS = 30;
|
|
21715
21675
|
var DismissalsSchema = external_exports.record(external_exports.string(), external_exports.number());
|
|
21716
21676
|
function loadDismissals() {
|
|
@@ -21722,7 +21682,7 @@ function loadDismissals() {
|
|
|
21722
21682
|
}
|
|
21723
21683
|
}
|
|
21724
21684
|
function saveDismissals(data) {
|
|
21725
|
-
const dir =
|
|
21685
|
+
const dir = join7(homedir2(), ".glassbox");
|
|
21726
21686
|
mkdirSync5(dir, { recursive: true });
|
|
21727
21687
|
writeFileSync6(DISMISS_FILE, JSON.stringify(data), "utf-8");
|
|
21728
21688
|
}
|
|
@@ -21742,8 +21702,8 @@ function shouldPromptGitignore(repoRoot) {
|
|
|
21742
21702
|
return true;
|
|
21743
21703
|
}
|
|
21744
21704
|
function addGlassboxToGitignore(repoRoot) {
|
|
21745
|
-
const gitignorePath =
|
|
21746
|
-
if (
|
|
21705
|
+
const gitignorePath = join7(repoRoot, ".gitignore");
|
|
21706
|
+
if (existsSync6(gitignorePath)) {
|
|
21747
21707
|
const content = readFileSync6(gitignorePath, "utf-8");
|
|
21748
21708
|
if (!content.endsWith("\n")) {
|
|
21749
21709
|
appendFileSync(gitignorePath, "\n.glassbox/\n", "utf-8");
|
|
@@ -21760,16 +21720,16 @@ function dismissGitignorePrompt2(repoRoot) {
|
|
|
21760
21720
|
saveDismissals(dismissals);
|
|
21761
21721
|
}
|
|
21762
21722
|
function deleteReviewExport(reviewId, repoRoot) {
|
|
21763
|
-
const exportDir =
|
|
21764
|
-
const archivePath =
|
|
21765
|
-
if (
|
|
21723
|
+
const exportDir = join7(repoRoot, ".glassbox");
|
|
21724
|
+
const archivePath = join7(exportDir, `review-${reviewId}.md`);
|
|
21725
|
+
if (existsSync6(archivePath)) unlinkSync2(archivePath);
|
|
21766
21726
|
}
|
|
21767
21727
|
async function generateReviewExport(reviewId, repoRoot, isCurrent) {
|
|
21768
21728
|
const review = await getReview(reviewId);
|
|
21769
21729
|
if (!review) throw new Error("Review not found");
|
|
21770
21730
|
const files = await getReviewFiles(reviewId);
|
|
21771
21731
|
const annotations = await getAnnotationsForReview(reviewId);
|
|
21772
|
-
const exportDir =
|
|
21732
|
+
const exportDir = join7(repoRoot, ".glassbox");
|
|
21773
21733
|
mkdirSync5(exportDir, { recursive: true });
|
|
21774
21734
|
const byFile = {};
|
|
21775
21735
|
for (const a of annotations) {
|
|
@@ -21837,10 +21797,10 @@ async function generateReviewExport(reviewId, repoRoot, isCurrent) {
|
|
|
21837
21797
|
lines.push("6. **note** annotations are informational context. Consider them but they may not require code changes.");
|
|
21838
21798
|
lines.push("");
|
|
21839
21799
|
const content = lines.join("\n");
|
|
21840
|
-
const archivePath =
|
|
21800
|
+
const archivePath = join7(exportDir, `review-${review.id}.md`);
|
|
21841
21801
|
writeFileSync6(archivePath, content, "utf-8");
|
|
21842
21802
|
if (isCurrent) {
|
|
21843
|
-
const latestPath =
|
|
21803
|
+
const latestPath = join7(exportDir, "latest-review.md");
|
|
21844
21804
|
writeFileSync6(latestPath, content, "utf-8");
|
|
21845
21805
|
return latestPath;
|
|
21846
21806
|
}
|
|
@@ -21960,7 +21920,7 @@ import { resolve as resolve4 } from "path";
|
|
|
21960
21920
|
init_queries();
|
|
21961
21921
|
|
|
21962
21922
|
// src/utils/openOS.ts
|
|
21963
|
-
import { execFileSync, spawn
|
|
21923
|
+
import { execFileSync, spawn } from "child_process";
|
|
21964
21924
|
import { resolve as resolve3 } from "path";
|
|
21965
21925
|
function openOS(target, mode) {
|
|
21966
21926
|
if (mode === "edit") {
|
|
@@ -21992,7 +21952,7 @@ function openOS(target, mode) {
|
|
|
21992
21952
|
}
|
|
21993
21953
|
}
|
|
21994
21954
|
function launchDetached(command, args) {
|
|
21995
|
-
const child =
|
|
21955
|
+
const child = spawn(command, args, { detached: true, stdio: "ignore" });
|
|
21996
21956
|
child.on("error", (err) => {
|
|
21997
21957
|
debugLog(`launchDetached(${command}) failed: ${err.message}`);
|
|
21998
21958
|
});
|
|
@@ -22072,7 +22032,7 @@ import { Hono as Hono7 } from "hono";
|
|
|
22072
22032
|
// src/git/image.ts
|
|
22073
22033
|
import { spawnSync as spawnSync7 } from "child_process";
|
|
22074
22034
|
import { readFileSync as readFileSync8 } from "fs";
|
|
22075
|
-
import { join as
|
|
22035
|
+
import { join as join9, resolve as resolve5 } from "path";
|
|
22076
22036
|
|
|
22077
22037
|
// src/git/image-metadata.ts
|
|
22078
22038
|
var IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"]);
|
|
@@ -22361,7 +22321,7 @@ function readDiskImage(absPath) {
|
|
|
22361
22321
|
}
|
|
22362
22322
|
function getOldImage(mode, filePath, oldPath, repoRoot) {
|
|
22363
22323
|
if (mode.type === "diff") {
|
|
22364
|
-
return readDiskImage(
|
|
22324
|
+
return readDiskImage(join9(directComparisonRoots(mode).rootA, oldPath ?? filePath));
|
|
22365
22325
|
}
|
|
22366
22326
|
const ref = getOldRef(mode);
|
|
22367
22327
|
const path = oldPath ?? filePath;
|
|
@@ -22377,7 +22337,7 @@ function getOldImage(mode, filePath, oldPath, repoRoot) {
|
|
|
22377
22337
|
}
|
|
22378
22338
|
function getNewImage(mode, filePath, repoRoot) {
|
|
22379
22339
|
if (mode.type === "diff") {
|
|
22380
|
-
return readDiskImage(
|
|
22340
|
+
return readDiskImage(join9(directComparisonRoots(mode).rootB, filePath));
|
|
22381
22341
|
}
|
|
22382
22342
|
const ref = getNewRef(mode);
|
|
22383
22343
|
if (ref === null) {
|
|
@@ -22399,9 +22359,9 @@ function getNewImage(mode, filePath, repoRoot) {
|
|
|
22399
22359
|
import { Worker } from "worker_threads";
|
|
22400
22360
|
|
|
22401
22361
|
// src/git/svg-rasterize-render.ts
|
|
22402
|
-
import { existsSync as
|
|
22362
|
+
import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
|
|
22403
22363
|
import { createRequire } from "module";
|
|
22404
|
-
import { join as
|
|
22364
|
+
import { join as join10 } from "path";
|
|
22405
22365
|
var initialized = false;
|
|
22406
22366
|
var ResvgClass;
|
|
22407
22367
|
var fontBuffers = [];
|
|
@@ -22421,7 +22381,7 @@ function loadSystemFonts() {
|
|
|
22421
22381
|
const buffers = [];
|
|
22422
22382
|
const candidates = getFontCandidates();
|
|
22423
22383
|
for (const path of candidates) {
|
|
22424
|
-
if (!
|
|
22384
|
+
if (!existsSync8(path)) continue;
|
|
22425
22385
|
try {
|
|
22426
22386
|
buffers.push(readFileSync9(path));
|
|
22427
22387
|
} catch {
|
|
@@ -22436,24 +22396,24 @@ function getFontCandidates() {
|
|
|
22436
22396
|
const sup = "/System/Library/Fonts/Supplemental";
|
|
22437
22397
|
return [
|
|
22438
22398
|
// Core system fonts (serif, sans-serif, monospace)
|
|
22439
|
-
|
|
22440
|
-
|
|
22441
|
-
|
|
22442
|
-
|
|
22443
|
-
|
|
22444
|
-
|
|
22445
|
-
|
|
22399
|
+
join10(sys, "Helvetica.ttc"),
|
|
22400
|
+
join10(sys, "Times.ttc"),
|
|
22401
|
+
join10(sys, "Courier.ttc"),
|
|
22402
|
+
join10(sys, "Menlo.ttc"),
|
|
22403
|
+
join10(sys, "SFPro.ttf"),
|
|
22404
|
+
join10(sys, "SFNS.ttf"),
|
|
22405
|
+
join10(sys, "SFNSMono.ttf"),
|
|
22446
22406
|
// Supplemental (common named fonts in SVGs)
|
|
22447
|
-
|
|
22448
|
-
|
|
22449
|
-
|
|
22450
|
-
|
|
22451
|
-
|
|
22452
|
-
|
|
22453
|
-
|
|
22454
|
-
|
|
22455
|
-
|
|
22456
|
-
|
|
22407
|
+
join10(sup, "Arial.ttf"),
|
|
22408
|
+
join10(sup, "Arial Bold.ttf"),
|
|
22409
|
+
join10(sup, "Georgia.ttf"),
|
|
22410
|
+
join10(sup, "Verdana.ttf"),
|
|
22411
|
+
join10(sup, "Tahoma.ttf"),
|
|
22412
|
+
join10(sup, "Trebuchet MS.ttf"),
|
|
22413
|
+
join10(sup, "Impact.ttf"),
|
|
22414
|
+
join10(sup, "Comic Sans MS.ttf"),
|
|
22415
|
+
join10(sup, "Courier New.ttf"),
|
|
22416
|
+
join10(sup, "Times New Roman.ttf")
|
|
22457
22417
|
];
|
|
22458
22418
|
}
|
|
22459
22419
|
if (os === "linux") {
|
|
@@ -22472,17 +22432,17 @@ function getFontCandidates() {
|
|
|
22472
22432
|
];
|
|
22473
22433
|
}
|
|
22474
22434
|
if (os === "win32") {
|
|
22475
|
-
const winFonts =
|
|
22435
|
+
const winFonts = join10(process.env.WINDIR ?? "C:\\Windows", "Fonts");
|
|
22476
22436
|
return [
|
|
22477
|
-
|
|
22478
|
-
|
|
22479
|
-
|
|
22480
|
-
|
|
22481
|
-
|
|
22482
|
-
|
|
22483
|
-
|
|
22484
|
-
|
|
22485
|
-
|
|
22437
|
+
join10(winFonts, "arial.ttf"),
|
|
22438
|
+
join10(winFonts, "arialbd.ttf"),
|
|
22439
|
+
join10(winFonts, "times.ttf"),
|
|
22440
|
+
join10(winFonts, "cour.ttf"),
|
|
22441
|
+
join10(winFonts, "verdana.ttf"),
|
|
22442
|
+
join10(winFonts, "tahoma.ttf"),
|
|
22443
|
+
join10(winFonts, "georgia.ttf"),
|
|
22444
|
+
join10(winFonts, "consola.ttf"),
|
|
22445
|
+
join10(winFonts, "segoeui.ttf")
|
|
22486
22446
|
];
|
|
22487
22447
|
}
|
|
22488
22448
|
return [];
|
|
@@ -23115,14 +23075,14 @@ function collectDefinitions(symbols, targetName, fileId, filePath, out) {
|
|
|
23115
23075
|
}
|
|
23116
23076
|
|
|
23117
23077
|
// src/routes/api/project-settings.ts
|
|
23118
|
-
import { existsSync as
|
|
23078
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
|
|
23119
23079
|
import { Hono as Hono9 } from "hono";
|
|
23120
|
-
import { join as
|
|
23080
|
+
import { join as join11 } from "path";
|
|
23121
23081
|
var projectSettingsRoutes = new Hono9();
|
|
23122
23082
|
function readProjectSettings(repoRoot) {
|
|
23123
|
-
const settingsPath =
|
|
23083
|
+
const settingsPath = join11(repoRoot, ".glassbox", "settings.json");
|
|
23124
23084
|
try {
|
|
23125
|
-
if (
|
|
23085
|
+
if (existsSync9(settingsPath)) {
|
|
23126
23086
|
const raw2 = JSON.parse(readFileSync11(settingsPath, "utf-8"));
|
|
23127
23087
|
const parsed = ProjectSettingsSchema.safeParse(raw2);
|
|
23128
23088
|
if (parsed.success) return parsed.data;
|
|
@@ -23132,9 +23092,9 @@ function readProjectSettings(repoRoot) {
|
|
|
23132
23092
|
return {};
|
|
23133
23093
|
}
|
|
23134
23094
|
function writeProjectSettings(repoRoot, settings) {
|
|
23135
|
-
const dir =
|
|
23095
|
+
const dir = join11(repoRoot, ".glassbox");
|
|
23136
23096
|
mkdirSync7(dir, { recursive: true });
|
|
23137
|
-
writeFileSync8(
|
|
23097
|
+
writeFileSync8(join11(dir, "settings.json"), JSON.stringify(settings, null, 2), "utf-8");
|
|
23138
23098
|
}
|
|
23139
23099
|
projectSettingsRoutes.get("/project-settings", (c) => {
|
|
23140
23100
|
const repoRoot = c.get("repoRoot");
|
|
@@ -23356,13 +23316,13 @@ apiRoutes.route("/", systemRoutes);
|
|
|
23356
23316
|
import { spawnSync as spawnSync9 } from "child_process";
|
|
23357
23317
|
import { mkdirSync as mkdirSync8 } from "fs";
|
|
23358
23318
|
import { Hono as Hono15 } from "hono";
|
|
23359
|
-
import { join as
|
|
23319
|
+
import { join as join12 } from "path";
|
|
23360
23320
|
var channelApiRoutes = new Hono15();
|
|
23361
23321
|
channelApiRoutes.get("/status", async (c) => {
|
|
23362
23322
|
const config2 = readGlobalConfig();
|
|
23363
23323
|
const enabled = config2.channelEnabled === true;
|
|
23364
23324
|
const repoRoot = c.get("repoRoot");
|
|
23365
|
-
const dataDir =
|
|
23325
|
+
const dataDir = join12(repoRoot, ".glassbox");
|
|
23366
23326
|
const connected = enabled ? await isChannelAlive(dataDir) : false;
|
|
23367
23327
|
return c.json({ enabled, connected });
|
|
23368
23328
|
});
|
|
@@ -23371,7 +23331,7 @@ channelApiRoutes.post("/enable", (c) => {
|
|
|
23371
23331
|
config2.channelEnabled = true;
|
|
23372
23332
|
});
|
|
23373
23333
|
const repoRoot = c.get("repoRoot");
|
|
23374
|
-
const dataDir =
|
|
23334
|
+
const dataDir = join12(repoRoot, ".glassbox");
|
|
23375
23335
|
mkdirSync8(dataDir, { recursive: true });
|
|
23376
23336
|
registerChannel(dataDir);
|
|
23377
23337
|
return c.json({ ok: true });
|
|
@@ -23381,7 +23341,7 @@ channelApiRoutes.post("/disable", (c) => {
|
|
|
23381
23341
|
config2.channelEnabled = false;
|
|
23382
23342
|
});
|
|
23383
23343
|
const repoRoot = c.get("repoRoot");
|
|
23384
|
-
const dataDir =
|
|
23344
|
+
const dataDir = join12(repoRoot, ".glassbox");
|
|
23385
23345
|
unregisterChannel(dataDir);
|
|
23386
23346
|
return c.json({ ok: true });
|
|
23387
23347
|
});
|
|
@@ -23389,7 +23349,7 @@ channelApiRoutes.post("/trigger", async (c) => {
|
|
|
23389
23349
|
const parsed = await parseBody(c, TriggerChannelReqSchema);
|
|
23390
23350
|
if (!parsed.ok) return parsed.response;
|
|
23391
23351
|
const repoRoot = c.get("repoRoot");
|
|
23392
|
-
const dataDir =
|
|
23352
|
+
const dataDir = join12(repoRoot, ".glassbox");
|
|
23393
23353
|
const sent = await triggerChannel(dataDir, parsed.data.message);
|
|
23394
23354
|
if (!sent) {
|
|
23395
23355
|
return c.json({ error: "Channel not connected" }, 503);
|
|
@@ -24127,9 +24087,9 @@ function AnnotationRows({ annotations }) {
|
|
|
24127
24087
|
}
|
|
24128
24088
|
|
|
24129
24089
|
// src/themes/config.ts
|
|
24130
|
-
import { existsSync as
|
|
24131
|
-
import { join as
|
|
24132
|
-
var THEMES_DIR =
|
|
24090
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync9, readdirSync as readdirSync2, readFileSync as readFileSync13, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
24091
|
+
import { join as join13 } from "path";
|
|
24092
|
+
var THEMES_DIR = join13(GLOBAL_CONFIG_DIR, "themes");
|
|
24133
24093
|
function getActiveThemeId() {
|
|
24134
24094
|
const config2 = readGlobalConfig();
|
|
24135
24095
|
const theme = config2.theme;
|
|
@@ -24143,13 +24103,13 @@ function setActiveThemeId(id) {
|
|
|
24143
24103
|
});
|
|
24144
24104
|
}
|
|
24145
24105
|
function loadCustomThemes() {
|
|
24146
|
-
if (!
|
|
24106
|
+
if (!existsSync10(THEMES_DIR)) return [];
|
|
24147
24107
|
const themes = [];
|
|
24148
24108
|
try {
|
|
24149
24109
|
const files = readdirSync2(THEMES_DIR).filter((f) => f.endsWith(".json"));
|
|
24150
24110
|
for (const file2 of files) {
|
|
24151
24111
|
try {
|
|
24152
|
-
const parsed = StoredCustomThemeSchema.safeParse(JSON.parse(readFileSync13(
|
|
24112
|
+
const parsed = StoredCustomThemeSchema.safeParse(JSON.parse(readFileSync13(join13(THEMES_DIR, file2), "utf-8")));
|
|
24153
24113
|
if (!parsed.success) continue;
|
|
24154
24114
|
const d = parsed.data;
|
|
24155
24115
|
themes.push({ id: d.id, name: d.name, colors: d.colors, builtIn: false, baseTheme: d.baseTheme ?? "" });
|
|
@@ -24162,18 +24122,18 @@ function loadCustomThemes() {
|
|
|
24162
24122
|
}
|
|
24163
24123
|
function saveCustomTheme(theme) {
|
|
24164
24124
|
mkdirSync9(THEMES_DIR, { recursive: true });
|
|
24165
|
-
const filePath =
|
|
24125
|
+
const filePath = join13(THEMES_DIR, `${theme.id}.json`);
|
|
24166
24126
|
writeFileSync9(filePath, JSON.stringify(theme, null, 2), "utf-8");
|
|
24167
24127
|
}
|
|
24168
24128
|
function deleteCustomTheme(id) {
|
|
24169
|
-
const filePath =
|
|
24170
|
-
if (
|
|
24129
|
+
const filePath = join13(THEMES_DIR, `${id}.json`);
|
|
24130
|
+
if (existsSync10(filePath)) {
|
|
24171
24131
|
unlinkSync3(filePath);
|
|
24172
24132
|
}
|
|
24173
24133
|
}
|
|
24174
24134
|
function getCustomTheme(id) {
|
|
24175
|
-
const filePath =
|
|
24176
|
-
if (!
|
|
24135
|
+
const filePath = join13(THEMES_DIR, `${id}.json`);
|
|
24136
|
+
if (!existsSync10(filePath)) return void 0;
|
|
24177
24137
|
try {
|
|
24178
24138
|
const parsed = StoredCustomThemeSchema.safeParse(JSON.parse(readFileSync13(filePath, "utf-8")));
|
|
24179
24139
|
if (!parsed.success) return void 0;
|
|
@@ -24788,17 +24748,17 @@ async function startServer(port, reviewId, repoRoot, options) {
|
|
|
24788
24748
|
await next();
|
|
24789
24749
|
});
|
|
24790
24750
|
const selfDir = dirname4(fileURLToPath2(import.meta.url));
|
|
24791
|
-
const distDir =
|
|
24751
|
+
const distDir = existsSync11(join14(selfDir, "client", "styles.css")) ? join14(selfDir, "client") : join14(selfDir, "..", "dist", "client");
|
|
24792
24752
|
app.get("/static/styles.css", (c) => {
|
|
24793
|
-
const css = readFileSync15(
|
|
24753
|
+
const css = readFileSync15(join14(distDir, "styles.css"), "utf-8");
|
|
24794
24754
|
return c.text(css, 200, { "Content-Type": "text/css", "Cache-Control": "no-cache" });
|
|
24795
24755
|
});
|
|
24796
24756
|
app.get("/static/app.js", (c) => {
|
|
24797
|
-
const js = readFileSync15(
|
|
24757
|
+
const js = readFileSync15(join14(distDir, "app.global.js"), "utf-8");
|
|
24798
24758
|
return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
|
|
24799
24759
|
});
|
|
24800
24760
|
app.get("/static/history.js", (c) => {
|
|
24801
|
-
const js = readFileSync15(
|
|
24761
|
+
const js = readFileSync15(join14(distDir, "history.global.js"), "utf-8");
|
|
24802
24762
|
return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
|
|
24803
24763
|
});
|
|
24804
24764
|
app.get("/favicon.ico", (c) => c.body(null, 204));
|
|
@@ -24836,7 +24796,7 @@ async function startServer(port, reviewId, repoRoot, options) {
|
|
|
24836
24796
|
try {
|
|
24837
24797
|
const globalConfig2 = readGlobalConfig();
|
|
24838
24798
|
if (globalConfig2.channelEnabled === true) {
|
|
24839
|
-
const dataDir =
|
|
24799
|
+
const dataDir = join14(repoRoot, ".glassbox");
|
|
24840
24800
|
registerChannel(dataDir);
|
|
24841
24801
|
}
|
|
24842
24802
|
} catch {
|
|
@@ -24851,8 +24811,8 @@ async function startServer(port, reviewId, repoRoot, options) {
|
|
|
24851
24811
|
}
|
|
24852
24812
|
|
|
24853
24813
|
// src/skills.ts
|
|
24854
|
-
import { existsSync as
|
|
24855
|
-
import { join as
|
|
24814
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
|
|
24815
|
+
import { join as join15 } from "path";
|
|
24856
24816
|
var SKILL_VERSION = 1;
|
|
24857
24817
|
function versionHeader() {
|
|
24858
24818
|
return `<!-- glassbox-skill-version: ${SKILL_VERSION} -->`;
|
|
@@ -24863,7 +24823,7 @@ function parseVersionHeader(content) {
|
|
|
24863
24823
|
return parseInt(match[1], 10);
|
|
24864
24824
|
}
|
|
24865
24825
|
function updateFile(path, content) {
|
|
24866
|
-
if (
|
|
24826
|
+
if (existsSync12(path)) {
|
|
24867
24827
|
const existing = readFileSync16(path, "utf-8");
|
|
24868
24828
|
const version2 = parseVersionHeader(existing);
|
|
24869
24829
|
if (version2 !== null && version2 >= SKILL_VERSION) {
|
|
@@ -24890,7 +24850,7 @@ function skillBody() {
|
|
|
24890
24850
|
].join("\n");
|
|
24891
24851
|
}
|
|
24892
24852
|
function ensureClaudeSkills(cwd) {
|
|
24893
|
-
const dir =
|
|
24853
|
+
const dir = join15(cwd, ".claude", "skills", "glassbox");
|
|
24894
24854
|
mkdirSync10(dir, { recursive: true });
|
|
24895
24855
|
const content = [
|
|
24896
24856
|
"---",
|
|
@@ -24903,10 +24863,10 @@ function ensureClaudeSkills(cwd) {
|
|
|
24903
24863
|
skillBody(),
|
|
24904
24864
|
""
|
|
24905
24865
|
].join("\n");
|
|
24906
|
-
return updateFile(
|
|
24866
|
+
return updateFile(join15(dir, "SKILL.md"), content);
|
|
24907
24867
|
}
|
|
24908
24868
|
function ensureCursorRules(cwd) {
|
|
24909
|
-
const rulesDir =
|
|
24869
|
+
const rulesDir = join15(cwd, ".cursor", "rules");
|
|
24910
24870
|
mkdirSync10(rulesDir, { recursive: true });
|
|
24911
24871
|
const content = [
|
|
24912
24872
|
"---",
|
|
@@ -24918,10 +24878,10 @@ function ensureCursorRules(cwd) {
|
|
|
24918
24878
|
skillBody(),
|
|
24919
24879
|
""
|
|
24920
24880
|
].join("\n");
|
|
24921
|
-
return updateFile(
|
|
24881
|
+
return updateFile(join15(rulesDir, "glassbox.mdc"), content);
|
|
24922
24882
|
}
|
|
24923
24883
|
function ensureCopilotPrompts(cwd) {
|
|
24924
|
-
const promptsDir =
|
|
24884
|
+
const promptsDir = join15(cwd, ".github", "prompts");
|
|
24925
24885
|
mkdirSync10(promptsDir, { recursive: true });
|
|
24926
24886
|
const content = [
|
|
24927
24887
|
"---",
|
|
@@ -24932,10 +24892,10 @@ function ensureCopilotPrompts(cwd) {
|
|
|
24932
24892
|
skillBody(),
|
|
24933
24893
|
""
|
|
24934
24894
|
].join("\n");
|
|
24935
|
-
return updateFile(
|
|
24895
|
+
return updateFile(join15(promptsDir, "glassbox.prompt.md"), content);
|
|
24936
24896
|
}
|
|
24937
24897
|
function ensureWindsurfRules(cwd) {
|
|
24938
|
-
const rulesDir =
|
|
24898
|
+
const rulesDir = join15(cwd, ".windsurf", "rules");
|
|
24939
24899
|
mkdirSync10(rulesDir, { recursive: true });
|
|
24940
24900
|
const content = [
|
|
24941
24901
|
"---",
|
|
@@ -24947,21 +24907,21 @@ function ensureWindsurfRules(cwd) {
|
|
|
24947
24907
|
skillBody(),
|
|
24948
24908
|
""
|
|
24949
24909
|
].join("\n");
|
|
24950
|
-
return updateFile(
|
|
24910
|
+
return updateFile(join15(rulesDir, "glassbox.md"), content);
|
|
24951
24911
|
}
|
|
24952
24912
|
function ensureSkills() {
|
|
24953
24913
|
const cwd = process.cwd();
|
|
24954
24914
|
const platforms = [];
|
|
24955
|
-
if (
|
|
24915
|
+
if (existsSync12(join15(cwd, ".claude"))) {
|
|
24956
24916
|
if (ensureClaudeSkills(cwd)) platforms.push("Claude Code");
|
|
24957
24917
|
}
|
|
24958
|
-
if (
|
|
24918
|
+
if (existsSync12(join15(cwd, ".cursor"))) {
|
|
24959
24919
|
if (ensureCursorRules(cwd)) platforms.push("Cursor");
|
|
24960
24920
|
}
|
|
24961
|
-
if (
|
|
24921
|
+
if (existsSync12(join15(cwd, ".github", "prompts")) || existsSync12(join15(cwd, ".github", "copilot-instructions.md"))) {
|
|
24962
24922
|
if (ensureCopilotPrompts(cwd)) platforms.push("GitHub Copilot");
|
|
24963
24923
|
}
|
|
24964
|
-
if (
|
|
24924
|
+
if (existsSync12(join15(cwd, ".windsurf"))) {
|
|
24965
24925
|
if (ensureWindsurfRules(cwd)) platforms.push("Windsurf");
|
|
24966
24926
|
}
|
|
24967
24927
|
return platforms;
|
|
@@ -24969,19 +24929,19 @@ function ensureSkills() {
|
|
|
24969
24929
|
|
|
24970
24930
|
// src/update-check.ts
|
|
24971
24931
|
init_zod();
|
|
24972
|
-
import { existsSync as
|
|
24932
|
+
import { existsSync as existsSync13, mkdirSync as mkdirSync11, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "fs";
|
|
24973
24933
|
import { get } from "https";
|
|
24974
24934
|
import { homedir as homedir3 } from "os";
|
|
24975
|
-
import { dirname as dirname5, join as
|
|
24935
|
+
import { dirname as dirname5, join as join16 } from "path";
|
|
24976
24936
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
24977
|
-
var DATA_DIR =
|
|
24978
|
-
var CHECK_FILE =
|
|
24937
|
+
var DATA_DIR = join16(homedir3(), ".glassbox");
|
|
24938
|
+
var CHECK_FILE = join16(DATA_DIR, "last-update-check");
|
|
24979
24939
|
var PACKAGE_NAME = "glassbox";
|
|
24980
24940
|
var VersionPayloadSchema = external_exports.object({ version: external_exports.string() });
|
|
24981
24941
|
function getCurrentVersion() {
|
|
24982
24942
|
try {
|
|
24983
24943
|
const dir = dirname5(fileURLToPath3(import.meta.url));
|
|
24984
|
-
const raw2 = JSON.parse(readFileSync17(
|
|
24944
|
+
const raw2 = JSON.parse(readFileSync17(join16(dir, "..", "package.json"), "utf-8"));
|
|
24985
24945
|
return VersionPayloadSchema.parse(raw2).version;
|
|
24986
24946
|
} catch {
|
|
24987
24947
|
return "0.0.0";
|
|
@@ -24989,7 +24949,7 @@ function getCurrentVersion() {
|
|
|
24989
24949
|
}
|
|
24990
24950
|
function getLastCheckDate() {
|
|
24991
24951
|
try {
|
|
24992
|
-
if (
|
|
24952
|
+
if (existsSync13(CHECK_FILE)) {
|
|
24993
24953
|
return readFileSync17(CHECK_FILE, "utf-8").trim();
|
|
24994
24954
|
}
|
|
24995
24955
|
} catch {
|
|
@@ -25298,13 +25258,13 @@ async function main() {
|
|
|
25298
25258
|
console.log("AI service test mode enabled \u2014 using mock AI responses");
|
|
25299
25259
|
}
|
|
25300
25260
|
if (debug) {
|
|
25301
|
-
console.log(`[debug] Build timestamp: ${"2026-06-
|
|
25261
|
+
console.log(`[debug] Build timestamp: ${"2026-06-20T03:35:27.947Z"}`);
|
|
25302
25262
|
}
|
|
25303
25263
|
if (projectDir !== null) {
|
|
25304
25264
|
process.chdir(projectDir);
|
|
25305
25265
|
}
|
|
25306
25266
|
if (dataDir === null) {
|
|
25307
|
-
dataDir =
|
|
25267
|
+
dataDir = join18(process.cwd(), ".glassbox");
|
|
25308
25268
|
}
|
|
25309
25269
|
if (difftoolServe) {
|
|
25310
25270
|
const { initDifftoolSession: initDifftoolSession2 } = await Promise.resolve().then(() => (init_session(), session_exports));
|
|
@@ -25345,7 +25305,7 @@ async function main() {
|
|
|
25345
25305
|
}
|
|
25346
25306
|
process.exit(1);
|
|
25347
25307
|
}
|
|
25348
|
-
dataDir =
|
|
25308
|
+
dataDir = join18(tmpdir2(), `glassbox-demo-${demo}-${Date.now()}`);
|
|
25349
25309
|
setDemoMode(demo);
|
|
25350
25310
|
console.log(`
|
|
25351
25311
|
DEMO MODE: ${scenario.label}
|
|
@@ -25373,7 +25333,7 @@ async function main() {
|
|
|
25373
25333
|
if (mode.type === "diff") {
|
|
25374
25334
|
const { pathA, pathB } = mode;
|
|
25375
25335
|
for (const p of [pathA, pathB]) {
|
|
25376
|
-
if (!
|
|
25336
|
+
if (!existsSync15(p)) {
|
|
25377
25337
|
console.error(`Error: path does not exist: ${p}`);
|
|
25378
25338
|
process.exit(1);
|
|
25379
25339
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "glassbox",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0-beta.1",
|
|
4
4
|
"description": "A local code review tool for AI-generated code. Review diffs, annotate lines, and export structured feedback that AI tools can act on.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"@hono/node-server": "^2.0.5",
|
|
66
66
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
67
67
|
"@resvg/resvg-wasm": "^2.6.2",
|
|
68
|
+
"apple-fm": "^1.0.0",
|
|
68
69
|
"hono": "^4.12.25",
|
|
69
70
|
"kerfjs": "^0.14.0",
|
|
70
71
|
"zod": "^4.4.3"
|
|
@@ -83,7 +84,7 @@
|
|
|
83
84
|
"eslint-plugin-kerfjs": "^0.14.0",
|
|
84
85
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
85
86
|
"eslint-plugin-tsdoc": "^0.5.2",
|
|
86
|
-
"gitgist": "^
|
|
87
|
+
"gitgist": "^1.0.0",
|
|
87
88
|
"highlight.js": "^11.11.1",
|
|
88
89
|
"sass": "^1.97.3",
|
|
89
90
|
"tsup": "^8.5.1",
|