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.
Files changed (2) hide show
  1. package/dist/cli.js +119 -159
  2. 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 existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync7, rmSync as rmSync4, writeFileSync as writeFileSync7 } from "fs";
16180
- import { join as join9 } from "path";
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 join9(dataDir, "difftool-blobs");
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(join9(dir, blobName(fileId, side)), bytes);
16191
+ writeFileSync7(join8(dir, blobName(fileId, side)), bytes);
16192
16192
  }
16193
16193
  function readDifftoolBlob(dataDir, fileId, side) {
16194
- const path = join9(blobDir(dataDir), blobName(fileId, side));
16195
- if (!existsSync8(path)) return null;
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 existsSync15, mkdirSync as mkdirSync12, readFileSync as readFileSync18, rmSync as rmSync5, statSync as statSync4, writeFileSync as writeFileSync12 } from "fs";
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 join18 } from "path";
16720
+ import { join as join17 } from "path";
16721
16721
  function difftoolHome() {
16722
- return join18(homedir4(), ".glassbox");
16722
+ return join17(homedir4(), ".glassbox");
16723
16723
  }
16724
16724
  function discoveryPath(home = difftoolHome()) {
16725
- return join18(home, "difftool.lock");
16725
+ return join17(home, "difftool.lock");
16726
16726
  }
16727
16727
  function startingLockPath(home = difftoolHome()) {
16728
- return join18(home, "difftool-starting.lock");
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 (!existsSync15(path)) return null;
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 existsSync16, mkdirSync as mkdirSync13, realpathSync, statSync as statSync5 } from "fs";
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 join19, resolve as resolve10 } from "path";
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 existsSync12, readFileSync as readFileSync15 } from "fs";
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 join15 } from "path";
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
- init_zod();
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 (!isDarwin) return false;
18734
- const bin = appleFmBinPath();
18735
- if (bin === null) return false;
18708
+ if (!isPlatformSupported()) return false;
18736
18709
  try {
18737
- const { stdout, code } = await runner(bin, ["--probe"], "");
18738
- return code === 0 && stdout.trim().toLowerCase().startsWith("available");
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
- const bin = appleFmBinPath();
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 existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync6, unlinkSync as unlinkSync2, writeFileSync as writeFileSync6 } from "fs";
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 join8 } from "path";
21713
- var DISMISS_FILE = join8(homedir2(), ".glassbox", "gitignore-dismissed.json");
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 = join8(homedir2(), ".glassbox");
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 = join8(repoRoot, ".gitignore");
21746
- if (existsSync7(gitignorePath)) {
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 = join8(repoRoot, ".glassbox");
21764
- const archivePath = join8(exportDir, `review-${reviewId}.md`);
21765
- if (existsSync7(archivePath)) unlinkSync2(archivePath);
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 = join8(repoRoot, ".glassbox");
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 = join8(exportDir, `review-${review.id}.md`);
21800
+ const archivePath = join7(exportDir, `review-${review.id}.md`);
21841
21801
  writeFileSync6(archivePath, content, "utf-8");
21842
21802
  if (isCurrent) {
21843
- const latestPath = join8(exportDir, "latest-review.md");
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 as spawn2 } from "child_process";
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 = spawn2(command, args, { detached: true, stdio: "ignore" });
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 join10, resolve as resolve5 } from "path";
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(join10(directComparisonRoots(mode).rootA, oldPath ?? filePath));
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(join10(directComparisonRoots(mode).rootB, filePath));
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 existsSync9, readFileSync as readFileSync9 } from "fs";
22362
+ import { existsSync as existsSync8, readFileSync as readFileSync9 } from "fs";
22403
22363
  import { createRequire } from "module";
22404
- import { join as join11 } from "path";
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 (!existsSync9(path)) continue;
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
- join11(sys, "Helvetica.ttc"),
22440
- join11(sys, "Times.ttc"),
22441
- join11(sys, "Courier.ttc"),
22442
- join11(sys, "Menlo.ttc"),
22443
- join11(sys, "SFPro.ttf"),
22444
- join11(sys, "SFNS.ttf"),
22445
- join11(sys, "SFNSMono.ttf"),
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
- join11(sup, "Arial.ttf"),
22448
- join11(sup, "Arial Bold.ttf"),
22449
- join11(sup, "Georgia.ttf"),
22450
- join11(sup, "Verdana.ttf"),
22451
- join11(sup, "Tahoma.ttf"),
22452
- join11(sup, "Trebuchet MS.ttf"),
22453
- join11(sup, "Impact.ttf"),
22454
- join11(sup, "Comic Sans MS.ttf"),
22455
- join11(sup, "Courier New.ttf"),
22456
- join11(sup, "Times New Roman.ttf")
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 = join11(process.env.WINDIR ?? "C:\\Windows", "Fonts");
22435
+ const winFonts = join10(process.env.WINDIR ?? "C:\\Windows", "Fonts");
22476
22436
  return [
22477
- join11(winFonts, "arial.ttf"),
22478
- join11(winFonts, "arialbd.ttf"),
22479
- join11(winFonts, "times.ttf"),
22480
- join11(winFonts, "cour.ttf"),
22481
- join11(winFonts, "verdana.ttf"),
22482
- join11(winFonts, "tahoma.ttf"),
22483
- join11(winFonts, "georgia.ttf"),
22484
- join11(winFonts, "consola.ttf"),
22485
- join11(winFonts, "segoeui.ttf")
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 existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
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 join12 } from "path";
23080
+ import { join as join11 } from "path";
23121
23081
  var projectSettingsRoutes = new Hono9();
23122
23082
  function readProjectSettings(repoRoot) {
23123
- const settingsPath = join12(repoRoot, ".glassbox", "settings.json");
23083
+ const settingsPath = join11(repoRoot, ".glassbox", "settings.json");
23124
23084
  try {
23125
- if (existsSync10(settingsPath)) {
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 = join12(repoRoot, ".glassbox");
23095
+ const dir = join11(repoRoot, ".glassbox");
23136
23096
  mkdirSync7(dir, { recursive: true });
23137
- writeFileSync8(join12(dir, "settings.json"), JSON.stringify(settings, null, 2), "utf-8");
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 join13 } from "path";
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 = join13(repoRoot, ".glassbox");
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 = join13(repoRoot, ".glassbox");
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 = join13(repoRoot, ".glassbox");
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 = join13(repoRoot, ".glassbox");
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 existsSync11, mkdirSync as mkdirSync9, readdirSync as readdirSync2, readFileSync as readFileSync13, unlinkSync as unlinkSync3, writeFileSync as writeFileSync9 } from "fs";
24131
- import { join as join14 } from "path";
24132
- var THEMES_DIR = join14(GLOBAL_CONFIG_DIR, "themes");
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 (!existsSync11(THEMES_DIR)) return [];
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(join14(THEMES_DIR, file2), "utf-8")));
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 = join14(THEMES_DIR, `${theme.id}.json`);
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 = join14(THEMES_DIR, `${id}.json`);
24170
- if (existsSync11(filePath)) {
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 = join14(THEMES_DIR, `${id}.json`);
24176
- if (!existsSync11(filePath)) return void 0;
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 = existsSync12(join15(selfDir, "client", "styles.css")) ? join15(selfDir, "client") : join15(selfDir, "..", "dist", "client");
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(join15(distDir, "styles.css"), "utf-8");
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(join15(distDir, "app.global.js"), "utf-8");
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(join15(distDir, "history.global.js"), "utf-8");
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 = join15(repoRoot, ".glassbox");
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 existsSync13, mkdirSync as mkdirSync10, readFileSync as readFileSync16, writeFileSync as writeFileSync10 } from "fs";
24855
- import { join as join16 } from "path";
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 (existsSync13(path)) {
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 = join16(cwd, ".claude", "skills", "glassbox");
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(join16(dir, "SKILL.md"), content);
24866
+ return updateFile(join15(dir, "SKILL.md"), content);
24907
24867
  }
24908
24868
  function ensureCursorRules(cwd) {
24909
- const rulesDir = join16(cwd, ".cursor", "rules");
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(join16(rulesDir, "glassbox.mdc"), content);
24881
+ return updateFile(join15(rulesDir, "glassbox.mdc"), content);
24922
24882
  }
24923
24883
  function ensureCopilotPrompts(cwd) {
24924
- const promptsDir = join16(cwd, ".github", "prompts");
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(join16(promptsDir, "glassbox.prompt.md"), content);
24895
+ return updateFile(join15(promptsDir, "glassbox.prompt.md"), content);
24936
24896
  }
24937
24897
  function ensureWindsurfRules(cwd) {
24938
- const rulesDir = join16(cwd, ".windsurf", "rules");
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(join16(rulesDir, "glassbox.md"), content);
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 (existsSync13(join16(cwd, ".claude"))) {
24915
+ if (existsSync12(join15(cwd, ".claude"))) {
24956
24916
  if (ensureClaudeSkills(cwd)) platforms.push("Claude Code");
24957
24917
  }
24958
- if (existsSync13(join16(cwd, ".cursor"))) {
24918
+ if (existsSync12(join15(cwd, ".cursor"))) {
24959
24919
  if (ensureCursorRules(cwd)) platforms.push("Cursor");
24960
24920
  }
24961
- if (existsSync13(join16(cwd, ".github", "prompts")) || existsSync13(join16(cwd, ".github", "copilot-instructions.md"))) {
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 (existsSync13(join16(cwd, ".windsurf"))) {
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 existsSync14, mkdirSync as mkdirSync11, readFileSync as readFileSync17, writeFileSync as writeFileSync11 } from "fs";
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 join17 } from "path";
24935
+ import { dirname as dirname5, join as join16 } from "path";
24976
24936
  import { fileURLToPath as fileURLToPath3 } from "url";
24977
- var DATA_DIR = join17(homedir3(), ".glassbox");
24978
- var CHECK_FILE = join17(DATA_DIR, "last-update-check");
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(join17(dir, "..", "package.json"), "utf-8"));
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 (existsSync14(CHECK_FILE)) {
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-20T00:24:24.185Z"}`);
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 = join19(process.cwd(), ".glassbox");
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 = join19(tmpdir2(), `glassbox-demo-${demo}-${Date.now()}`);
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 (!existsSync16(p)) {
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.15.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": "^0.1.0",
87
+ "gitgist": "^1.0.0",
87
88
  "highlight.js": "^11.11.1",
88
89
  "sass": "^1.97.3",
89
90
  "tsup": "^8.5.1",