glassbox 0.7.9 → 0.8.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 CHANGED
@@ -393,9 +393,9 @@ var init_queries = __esm({
393
393
  // src/cli.ts
394
394
  init_connection();
395
395
  init_queries();
396
- import { mkdirSync as mkdirSync8, realpathSync } from "fs";
396
+ import { mkdirSync as mkdirSync9, realpathSync } from "fs";
397
397
  import { tmpdir } from "os";
398
- import { join as join11, resolve as resolve5 } from "path";
398
+ import { join as join13, resolve as resolve6 } from "path";
399
399
 
400
400
  // src/debug.ts
401
401
  var debugEnabled = false;
@@ -1725,10 +1725,10 @@ async function updateReviewDiffs(reviewId, newDiffs, headCommit) {
1725
1725
  // src/server.ts
1726
1726
  import { serve } from "@hono/node-server";
1727
1727
  import { exec } from "child_process";
1728
- import { existsSync as existsSync7, readFileSync as readFileSync10 } from "fs";
1729
- import { Hono as Hono7 } from "hono";
1730
- import { dirname, join as join8 } from "path";
1731
- import { fileURLToPath } from "url";
1728
+ import { existsSync as existsSync9, readFileSync as readFileSync12 } from "fs";
1729
+ import { Hono as Hono8 } from "hono";
1730
+ import { dirname as dirname2, join as join10 } from "path";
1731
+ import { fileURLToPath as fileURLToPath2 } from "url";
1732
1732
 
1733
1733
  // src/routes/ai-api.ts
1734
1734
  import { Hono as Hono3 } from "hono";
@@ -2450,8 +2450,8 @@ function isRetriable(err) {
2450
2450
  return msg.includes("429") || msg.includes("500") || msg.includes("502") || msg.includes("503") || msg.includes("504") || msg.includes("rate_limit");
2451
2451
  }
2452
2452
  function sleep(ms) {
2453
- return new Promise((resolve6) => {
2454
- setTimeout(resolve6, ms);
2453
+ return new Promise((resolve7) => {
2454
+ setTimeout(resolve7, ms);
2455
2455
  });
2456
2456
  }
2457
2457
 
@@ -2495,8 +2495,8 @@ function randomLines(count) {
2495
2495
  return lines.sort((a, b) => a.line - b.line);
2496
2496
  }
2497
2497
  function sleep2(ms) {
2498
- return new Promise((resolve6) => {
2499
- setTimeout(resolve6, ms);
2498
+ return new Promise((resolve7) => {
2499
+ setTimeout(resolve7, ms);
2500
2500
  });
2501
2501
  }
2502
2502
  async function mockRiskAnalysisBatch(files) {
@@ -4370,10 +4370,178 @@ apiRoutes.post("/share-prompt/tick", async (c) => {
4370
4370
  return c.json({ totalOpenMs: sp.totalOpenMs });
4371
4371
  });
4372
4372
 
4373
- // src/routes/pages.tsx
4374
- import { readFileSync as readFileSync9 } from "fs";
4373
+ // src/routes/channel-api.ts
4374
+ import { spawnSync as spawnSync8 } from "child_process";
4375
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync9, writeFileSync as writeFileSync6 } from "fs";
4375
4376
  import { Hono as Hono5 } from "hono";
4376
- import { resolve as resolve4 } from "path";
4377
+ import { homedir as homedir4 } from "os";
4378
+ import { join as join8 } from "path";
4379
+
4380
+ // src/channel-config.ts
4381
+ import { existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
4382
+ import { dirname, join as join7, resolve as resolve4 } from "path";
4383
+ import { fileURLToPath } from "url";
4384
+ var MCP_SERVER_KEY = "glassbox-channel";
4385
+ function getChannelServerPath() {
4386
+ const thisDir = dirname(fileURLToPath(import.meta.url));
4387
+ const distPath = resolve4(thisDir, "channel.js");
4388
+ if (existsSync6(distPath)) {
4389
+ return { command: process.execPath, args: [distPath] };
4390
+ }
4391
+ const srcPath = resolve4(thisDir, "channel.ts");
4392
+ if (existsSync6(srcPath)) {
4393
+ return { command: "npx", args: ["tsx", srcPath] };
4394
+ }
4395
+ return { command: process.execPath, args: [distPath] };
4396
+ }
4397
+ function projectRoot(dataDir) {
4398
+ return dataDir.replace(/\/.glassbox\/?$/, "");
4399
+ }
4400
+ function registerChannel(dataDir) {
4401
+ const root = projectRoot(dataDir);
4402
+ const mcpPath = join7(root, ".mcp.json");
4403
+ const { command, args } = getChannelServerPath();
4404
+ let config = {};
4405
+ if (existsSync6(mcpPath)) {
4406
+ try {
4407
+ config = JSON.parse(readFileSync8(mcpPath, "utf-8"));
4408
+ } catch {
4409
+ }
4410
+ }
4411
+ if (config.mcpServers === void 0) config.mcpServers = {};
4412
+ config.mcpServers[MCP_SERVER_KEY] = {
4413
+ command,
4414
+ args: [...args, "--data-dir", dataDir]
4415
+ };
4416
+ writeFileSync5(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
4417
+ }
4418
+ function unregisterChannel(dataDir) {
4419
+ const root = projectRoot(dataDir);
4420
+ const mcpPath = join7(root, ".mcp.json");
4421
+ if (!existsSync6(mcpPath)) return;
4422
+ try {
4423
+ const config = JSON.parse(readFileSync8(mcpPath, "utf-8"));
4424
+ if (config.mcpServers?.[MCP_SERVER_KEY] !== void 0) {
4425
+ const servers = { ...config.mcpServers };
4426
+ delete servers[MCP_SERVER_KEY];
4427
+ config.mcpServers = servers;
4428
+ writeFileSync5(mcpPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
4429
+ }
4430
+ } catch {
4431
+ }
4432
+ }
4433
+ function getChannelPort(dataDir) {
4434
+ try {
4435
+ const portStr = readFileSync8(join7(dataDir, "channel-port"), "utf-8").trim();
4436
+ const port = parseInt(portStr, 10);
4437
+ return isNaN(port) ? null : port;
4438
+ } catch {
4439
+ return null;
4440
+ }
4441
+ }
4442
+ async function isChannelAlive(dataDir) {
4443
+ const port = getChannelPort(dataDir);
4444
+ if (port === null) return false;
4445
+ try {
4446
+ const res = await fetch(`http://127.0.0.1:${port}/health`);
4447
+ const data = await res.json();
4448
+ return data.ok;
4449
+ } catch {
4450
+ return false;
4451
+ }
4452
+ }
4453
+ async function triggerChannel(dataDir, message) {
4454
+ const port = getChannelPort(dataDir);
4455
+ if (port === null) return false;
4456
+ try {
4457
+ const res = await fetch(`http://127.0.0.1:${port}/trigger`, {
4458
+ method: "POST",
4459
+ body: message
4460
+ });
4461
+ return res.ok;
4462
+ } catch {
4463
+ return false;
4464
+ }
4465
+ }
4466
+
4467
+ // src/routes/channel-api.ts
4468
+ var channelApiRoutes = new Hono5();
4469
+ var CONFIG_DIR2 = join8(homedir4(), ".glassbox");
4470
+ var CONFIG_PATH2 = join8(CONFIG_DIR2, "config.json");
4471
+ function readGlobalConfig2() {
4472
+ try {
4473
+ if (existsSync7(CONFIG_PATH2)) {
4474
+ return JSON.parse(readFileSync9(CONFIG_PATH2, "utf-8"));
4475
+ }
4476
+ } catch {
4477
+ }
4478
+ return {};
4479
+ }
4480
+ function writeGlobalConfig2(config) {
4481
+ mkdirSync5(CONFIG_DIR2, { recursive: true });
4482
+ writeFileSync6(CONFIG_PATH2, JSON.stringify(config, null, 2), "utf-8");
4483
+ }
4484
+ channelApiRoutes.get("/status", async (c) => {
4485
+ const config = readGlobalConfig2();
4486
+ const enabled = config.channelEnabled === true;
4487
+ const repoRoot = c.get("repoRoot");
4488
+ const dataDir = join8(repoRoot, ".glassbox");
4489
+ const connected = enabled ? await isChannelAlive(dataDir) : false;
4490
+ return c.json({ enabled, connected });
4491
+ });
4492
+ channelApiRoutes.post("/enable", (c) => {
4493
+ const config = readGlobalConfig2();
4494
+ config.channelEnabled = true;
4495
+ writeGlobalConfig2(config);
4496
+ const repoRoot = c.get("repoRoot");
4497
+ const dataDir = join8(repoRoot, ".glassbox");
4498
+ mkdirSync5(dataDir, { recursive: true });
4499
+ registerChannel(dataDir);
4500
+ return c.json({ ok: true });
4501
+ });
4502
+ channelApiRoutes.post("/disable", (c) => {
4503
+ const config = readGlobalConfig2();
4504
+ config.channelEnabled = false;
4505
+ writeGlobalConfig2(config);
4506
+ const repoRoot = c.get("repoRoot");
4507
+ const dataDir = join8(repoRoot, ".glassbox");
4508
+ unregisterChannel(dataDir);
4509
+ return c.json({ ok: true });
4510
+ });
4511
+ channelApiRoutes.post("/trigger", async (c) => {
4512
+ const body = await c.req.json();
4513
+ const repoRoot = c.get("repoRoot");
4514
+ const dataDir = join8(repoRoot, ".glassbox");
4515
+ const sent = await triggerChannel(dataDir, body.message);
4516
+ if (!sent) {
4517
+ return c.json({ error: "Channel not connected" }, 503);
4518
+ }
4519
+ return c.json({ ok: true });
4520
+ });
4521
+ channelApiRoutes.get("/claude-check", (c) => {
4522
+ try {
4523
+ const result = spawnSync8("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
4524
+ if (result.status !== 0) {
4525
+ return c.json({ installed: false, version: null, meetsMinimum: false });
4526
+ }
4527
+ const version = result.stdout.trim();
4528
+ const match = version.match(/(\d+\.\d+\.\d+)/);
4529
+ const ver = match !== null ? match[1] : null;
4530
+ let meetsMinimum = false;
4531
+ if (ver !== null) {
4532
+ const parts = ver.split(".").map(Number);
4533
+ meetsMinimum = parts[0] > 2 || parts[0] === 2 && parts[1] > 1 || parts[0] === 2 && parts[1] === 1 && parts[2] >= 80;
4534
+ }
4535
+ return c.json({ installed: true, version: ver, meetsMinimum });
4536
+ } catch {
4537
+ return c.json({ installed: false, version: null, meetsMinimum: false });
4538
+ }
4539
+ });
4540
+
4541
+ // src/routes/pages.tsx
4542
+ import { readFileSync as readFileSync11 } from "fs";
4543
+ import { Hono as Hono6 } from "hono";
4544
+ import { resolve as resolve5 } from "path";
4377
4545
 
4378
4546
  // src/utils/escapeHtml.ts
4379
4547
  function escapeHtml(str) {
@@ -5619,24 +5787,24 @@ function themeToInlineStyle(colors) {
5619
5787
  }
5620
5788
 
5621
5789
  // src/themes/config.ts
5622
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readdirSync, readFileSync as readFileSync8, unlinkSync as unlinkSync2, writeFileSync as writeFileSync5 } from "fs";
5623
- import { homedir as homedir4 } from "os";
5624
- import { join as join7 } from "path";
5625
- var CONFIG_DIR2 = join7(homedir4(), ".glassbox");
5626
- var CONFIG_PATH2 = join7(CONFIG_DIR2, "config.json");
5627
- var THEMES_DIR = join7(CONFIG_DIR2, "themes");
5790
+ import { existsSync as existsSync8, mkdirSync as mkdirSync6, readdirSync, readFileSync as readFileSync10, unlinkSync as unlinkSync2, writeFileSync as writeFileSync7 } from "fs";
5791
+ import { homedir as homedir5 } from "os";
5792
+ import { join as join9 } from "path";
5793
+ var CONFIG_DIR3 = join9(homedir5(), ".glassbox");
5794
+ var CONFIG_PATH3 = join9(CONFIG_DIR3, "config.json");
5795
+ var THEMES_DIR = join9(CONFIG_DIR3, "themes");
5628
5796
  function readConfigFile2() {
5629
5797
  try {
5630
- if (existsSync6(CONFIG_PATH2)) {
5631
- return JSON.parse(readFileSync8(CONFIG_PATH2, "utf-8"));
5798
+ if (existsSync8(CONFIG_PATH3)) {
5799
+ return JSON.parse(readFileSync10(CONFIG_PATH3, "utf-8"));
5632
5800
  }
5633
5801
  } catch {
5634
5802
  }
5635
5803
  return {};
5636
5804
  }
5637
5805
  function writeConfigFile2(config) {
5638
- mkdirSync5(CONFIG_DIR2, { recursive: true });
5639
- writeFileSync5(CONFIG_PATH2, JSON.stringify(config, null, 2), "utf-8");
5806
+ mkdirSync6(CONFIG_DIR3, { recursive: true });
5807
+ writeFileSync7(CONFIG_PATH3, JSON.stringify(config, null, 2), "utf-8");
5640
5808
  }
5641
5809
  function getActiveThemeId() {
5642
5810
  const config = readConfigFile2();
@@ -5651,13 +5819,13 @@ function setActiveThemeId(id) {
5651
5819
  writeConfigFile2(config);
5652
5820
  }
5653
5821
  function loadCustomThemes() {
5654
- if (!existsSync6(THEMES_DIR)) return [];
5822
+ if (!existsSync8(THEMES_DIR)) return [];
5655
5823
  const themes = [];
5656
5824
  try {
5657
5825
  const files = readdirSync(THEMES_DIR).filter((f) => f.endsWith(".json"));
5658
5826
  for (const file of files) {
5659
5827
  try {
5660
- const data = JSON.parse(readFileSync8(join7(THEMES_DIR, file), "utf-8"));
5828
+ const data = JSON.parse(readFileSync10(join9(THEMES_DIR, file), "utf-8"));
5661
5829
  if (data.id !== void 0 && data.id !== "" && data.name !== void 0 && data.name !== "" && data.colors !== void 0) {
5662
5830
  themes.push({ id: data.id, name: data.name, colors: data.colors, builtIn: false, baseTheme: data.baseTheme ?? "" });
5663
5831
  }
@@ -5669,21 +5837,21 @@ function loadCustomThemes() {
5669
5837
  return themes;
5670
5838
  }
5671
5839
  function saveCustomTheme(theme) {
5672
- mkdirSync5(THEMES_DIR, { recursive: true });
5673
- const filePath = join7(THEMES_DIR, `${theme.id}.json`);
5674
- writeFileSync5(filePath, JSON.stringify(theme, null, 2), "utf-8");
5840
+ mkdirSync6(THEMES_DIR, { recursive: true });
5841
+ const filePath = join9(THEMES_DIR, `${theme.id}.json`);
5842
+ writeFileSync7(filePath, JSON.stringify(theme, null, 2), "utf-8");
5675
5843
  }
5676
5844
  function deleteCustomTheme(id) {
5677
- const filePath = join7(THEMES_DIR, `${id}.json`);
5678
- if (existsSync6(filePath)) {
5845
+ const filePath = join9(THEMES_DIR, `${id}.json`);
5846
+ if (existsSync8(filePath)) {
5679
5847
  unlinkSync2(filePath);
5680
5848
  }
5681
5849
  }
5682
5850
  function getCustomTheme(id) {
5683
- const filePath = join7(THEMES_DIR, `${id}.json`);
5684
- if (!existsSync6(filePath)) return void 0;
5851
+ const filePath = join9(THEMES_DIR, `${id}.json`);
5852
+ if (!existsSync8(filePath)) return void 0;
5685
5853
  try {
5686
- const data = JSON.parse(readFileSync8(filePath, "utf-8"));
5854
+ const data = JSON.parse(readFileSync10(filePath, "utf-8"));
5687
5855
  return { ...data, builtIn: false };
5688
5856
  } catch {
5689
5857
  return void 0;
@@ -5793,7 +5961,7 @@ function ReviewHistory({ reviews, currentReviewId }) {
5793
5961
 
5794
5962
  // src/routes/pages.tsx
5795
5963
  init_queries();
5796
- var pageRoutes = new Hono5();
5964
+ var pageRoutes = new Hono6();
5797
5965
  pageRoutes.get("/", async (c) => {
5798
5966
  const reviewId = c.get("reviewId");
5799
5967
  const review = await getReview(reviewId);
@@ -5952,7 +6120,7 @@ pageRoutes.get("/file-raw", (c) => {
5952
6120
  const repoRoot = c.get("repoRoot");
5953
6121
  let content;
5954
6122
  try {
5955
- content = readFileSync9(resolve4(repoRoot, filePath), "utf-8");
6123
+ content = readFileSync11(resolve5(repoRoot, filePath), "utf-8");
5956
6124
  } catch {
5957
6125
  return c.text("File not found", 404);
5958
6126
  }
@@ -6080,8 +6248,8 @@ pageRoutes.get("/history", async (c) => {
6080
6248
  });
6081
6249
 
6082
6250
  // src/routes/theme-api.ts
6083
- import { Hono as Hono6 } from "hono";
6084
- var themeApiRoutes = new Hono6();
6251
+ import { Hono as Hono7 } from "hono";
6252
+ var themeApiRoutes = new Hono7();
6085
6253
  function validateColors(colors) {
6086
6254
  if (typeof colors !== "object" || colors === null || Array.isArray(colors)) {
6087
6255
  return "colors must be an object";
@@ -6215,10 +6383,10 @@ themeApiRoutes.delete("/:id", (c) => {
6215
6383
 
6216
6384
  // src/server.ts
6217
6385
  function tryServe(appFetch, port) {
6218
- return new Promise((resolve6, reject) => {
6386
+ return new Promise((resolve7, reject) => {
6219
6387
  const server = serve({ fetch: appFetch, port, hostname: "127.0.0.1" });
6220
6388
  server.on("listening", () => {
6221
- resolve6(port);
6389
+ resolve7(port);
6222
6390
  });
6223
6391
  server.on("error", (err) => {
6224
6392
  if (err.code === "EADDRINUSE") {
@@ -6230,30 +6398,31 @@ function tryServe(appFetch, port) {
6230
6398
  });
6231
6399
  }
6232
6400
  async function startServer(port, reviewId, repoRoot, options) {
6233
- const app = new Hono7();
6401
+ const app = new Hono8();
6234
6402
  app.use("*", async (c, next) => {
6235
6403
  c.set("reviewId", reviewId);
6236
6404
  c.set("currentReviewId", reviewId);
6237
6405
  c.set("repoRoot", repoRoot);
6238
6406
  await next();
6239
6407
  });
6240
- const selfDir = dirname(fileURLToPath(import.meta.url));
6241
- const distDir = existsSync7(join8(selfDir, "client", "styles.css")) ? join8(selfDir, "client") : join8(selfDir, "..", "dist", "client");
6408
+ const selfDir = dirname2(fileURLToPath2(import.meta.url));
6409
+ const distDir = existsSync9(join10(selfDir, "client", "styles.css")) ? join10(selfDir, "client") : join10(selfDir, "..", "dist", "client");
6242
6410
  app.get("/static/styles.css", (c) => {
6243
- const css = readFileSync10(join8(distDir, "styles.css"), "utf-8");
6411
+ const css = readFileSync12(join10(distDir, "styles.css"), "utf-8");
6244
6412
  return c.text(css, 200, { "Content-Type": "text/css", "Cache-Control": "no-cache" });
6245
6413
  });
6246
6414
  app.get("/static/app.js", (c) => {
6247
- const js = readFileSync10(join8(distDir, "app.global.js"), "utf-8");
6415
+ const js = readFileSync12(join10(distDir, "app.global.js"), "utf-8");
6248
6416
  return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
6249
6417
  });
6250
6418
  app.get("/static/history.js", (c) => {
6251
- const js = readFileSync10(join8(distDir, "history.global.js"), "utf-8");
6419
+ const js = readFileSync12(join10(distDir, "history.global.js"), "utf-8");
6252
6420
  return c.text(js, 200, { "Content-Type": "application/javascript", "Cache-Control": "no-cache" });
6253
6421
  });
6254
6422
  app.route("/api", apiRoutes);
6255
6423
  app.route("/api/ai", aiApiRoutes);
6256
6424
  app.route("/api/themes", themeApiRoutes);
6425
+ app.route("/api/channel", channelApiRoutes);
6257
6426
  app.route("/", pageRoutes);
6258
6427
  let actualPort = port;
6259
6428
  if (options?.strictPort === true) {
@@ -6285,8 +6454,8 @@ async function startServer(port, reviewId, repoRoot, options) {
6285
6454
  }
6286
6455
 
6287
6456
  // src/skills.ts
6288
- import { existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
6289
- import { join as join9 } from "path";
6457
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "fs";
6458
+ import { join as join11 } from "path";
6290
6459
  var SKILL_VERSION = 1;
6291
6460
  function versionHeader() {
6292
6461
  return `<!-- glassbox-skill-version: ${SKILL_VERSION} -->`;
@@ -6297,14 +6466,14 @@ function parseVersionHeader(content) {
6297
6466
  return parseInt(match[1], 10);
6298
6467
  }
6299
6468
  function updateFile(path, content) {
6300
- if (existsSync8(path)) {
6301
- const existing = readFileSync11(path, "utf-8");
6469
+ if (existsSync10(path)) {
6470
+ const existing = readFileSync13(path, "utf-8");
6302
6471
  const version = parseVersionHeader(existing);
6303
6472
  if (version !== null && version >= SKILL_VERSION) {
6304
6473
  return false;
6305
6474
  }
6306
6475
  }
6307
- writeFileSync6(path, content, "utf-8");
6476
+ writeFileSync8(path, content, "utf-8");
6308
6477
  return true;
6309
6478
  }
6310
6479
  function skillBody() {
@@ -6324,8 +6493,8 @@ function skillBody() {
6324
6493
  ].join("\n");
6325
6494
  }
6326
6495
  function ensureClaudeSkills(cwd) {
6327
- const dir = join9(cwd, ".claude", "skills", "glassbox");
6328
- mkdirSync6(dir, { recursive: true });
6496
+ const dir = join11(cwd, ".claude", "skills", "glassbox");
6497
+ mkdirSync7(dir, { recursive: true });
6329
6498
  const content = [
6330
6499
  "---",
6331
6500
  "name: glassbox",
@@ -6337,11 +6506,11 @@ function ensureClaudeSkills(cwd) {
6337
6506
  skillBody(),
6338
6507
  ""
6339
6508
  ].join("\n");
6340
- return updateFile(join9(dir, "SKILL.md"), content);
6509
+ return updateFile(join11(dir, "SKILL.md"), content);
6341
6510
  }
6342
6511
  function ensureCursorRules(cwd) {
6343
- const rulesDir = join9(cwd, ".cursor", "rules");
6344
- mkdirSync6(rulesDir, { recursive: true });
6512
+ const rulesDir = join11(cwd, ".cursor", "rules");
6513
+ mkdirSync7(rulesDir, { recursive: true });
6345
6514
  const content = [
6346
6515
  "---",
6347
6516
  "description: Read the latest Glassbox code review and apply all feedback annotations",
@@ -6352,11 +6521,11 @@ function ensureCursorRules(cwd) {
6352
6521
  skillBody(),
6353
6522
  ""
6354
6523
  ].join("\n");
6355
- return updateFile(join9(rulesDir, "glassbox.mdc"), content);
6524
+ return updateFile(join11(rulesDir, "glassbox.mdc"), content);
6356
6525
  }
6357
6526
  function ensureCopilotPrompts(cwd) {
6358
- const promptsDir = join9(cwd, ".github", "prompts");
6359
- mkdirSync6(promptsDir, { recursive: true });
6527
+ const promptsDir = join11(cwd, ".github", "prompts");
6528
+ mkdirSync7(promptsDir, { recursive: true });
6360
6529
  const content = [
6361
6530
  "---",
6362
6531
  "description: Read the latest Glassbox code review and apply all feedback annotations",
@@ -6366,11 +6535,11 @@ function ensureCopilotPrompts(cwd) {
6366
6535
  skillBody(),
6367
6536
  ""
6368
6537
  ].join("\n");
6369
- return updateFile(join9(promptsDir, "glassbox.prompt.md"), content);
6538
+ return updateFile(join11(promptsDir, "glassbox.prompt.md"), content);
6370
6539
  }
6371
6540
  function ensureWindsurfRules(cwd) {
6372
- const rulesDir = join9(cwd, ".windsurf", "rules");
6373
- mkdirSync6(rulesDir, { recursive: true });
6541
+ const rulesDir = join11(cwd, ".windsurf", "rules");
6542
+ mkdirSync7(rulesDir, { recursive: true });
6374
6543
  const content = [
6375
6544
  "---",
6376
6545
  "trigger: manual",
@@ -6381,39 +6550,39 @@ function ensureWindsurfRules(cwd) {
6381
6550
  skillBody(),
6382
6551
  ""
6383
6552
  ].join("\n");
6384
- return updateFile(join9(rulesDir, "glassbox.md"), content);
6553
+ return updateFile(join11(rulesDir, "glassbox.md"), content);
6385
6554
  }
6386
6555
  function ensureSkills() {
6387
6556
  const cwd = process.cwd();
6388
6557
  const platforms = [];
6389
- if (existsSync8(join9(cwd, ".claude"))) {
6558
+ if (existsSync10(join11(cwd, ".claude"))) {
6390
6559
  if (ensureClaudeSkills(cwd)) platforms.push("Claude Code");
6391
6560
  }
6392
- if (existsSync8(join9(cwd, ".cursor"))) {
6561
+ if (existsSync10(join11(cwd, ".cursor"))) {
6393
6562
  if (ensureCursorRules(cwd)) platforms.push("Cursor");
6394
6563
  }
6395
- if (existsSync8(join9(cwd, ".github", "prompts")) || existsSync8(join9(cwd, ".github", "copilot-instructions.md"))) {
6564
+ if (existsSync10(join11(cwd, ".github", "prompts")) || existsSync10(join11(cwd, ".github", "copilot-instructions.md"))) {
6396
6565
  if (ensureCopilotPrompts(cwd)) platforms.push("GitHub Copilot");
6397
6566
  }
6398
- if (existsSync8(join9(cwd, ".windsurf"))) {
6567
+ if (existsSync10(join11(cwd, ".windsurf"))) {
6399
6568
  if (ensureWindsurfRules(cwd)) platforms.push("Windsurf");
6400
6569
  }
6401
6570
  return platforms;
6402
6571
  }
6403
6572
 
6404
6573
  // src/update-check.ts
6405
- import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
6574
+ import { existsSync as existsSync11, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
6406
6575
  import { get } from "https";
6407
- import { homedir as homedir5 } from "os";
6408
- import { dirname as dirname2, join as join10 } from "path";
6409
- import { fileURLToPath as fileURLToPath2 } from "url";
6410
- var DATA_DIR = join10(homedir5(), ".glassbox");
6411
- var CHECK_FILE = join10(DATA_DIR, "last-update-check");
6576
+ import { homedir as homedir6 } from "os";
6577
+ import { dirname as dirname3, join as join12 } from "path";
6578
+ import { fileURLToPath as fileURLToPath3 } from "url";
6579
+ var DATA_DIR = join12(homedir6(), ".glassbox");
6580
+ var CHECK_FILE = join12(DATA_DIR, "last-update-check");
6412
6581
  var PACKAGE_NAME = "glassbox";
6413
6582
  function getCurrentVersion() {
6414
6583
  try {
6415
- const dir = dirname2(fileURLToPath2(import.meta.url));
6416
- const pkg = JSON.parse(readFileSync12(join10(dir, "..", "package.json"), "utf-8"));
6584
+ const dir = dirname3(fileURLToPath3(import.meta.url));
6585
+ const pkg = JSON.parse(readFileSync14(join12(dir, "..", "package.json"), "utf-8"));
6417
6586
  return pkg.version;
6418
6587
  } catch {
6419
6588
  return "0.0.0";
@@ -6421,16 +6590,16 @@ function getCurrentVersion() {
6421
6590
  }
6422
6591
  function getLastCheckDate() {
6423
6592
  try {
6424
- if (existsSync9(CHECK_FILE)) {
6425
- return readFileSync12(CHECK_FILE, "utf-8").trim();
6593
+ if (existsSync11(CHECK_FILE)) {
6594
+ return readFileSync14(CHECK_FILE, "utf-8").trim();
6426
6595
  }
6427
6596
  } catch {
6428
6597
  }
6429
6598
  return null;
6430
6599
  }
6431
6600
  function saveCheckDate() {
6432
- mkdirSync7(DATA_DIR, { recursive: true });
6433
- writeFileSync7(CHECK_FILE, (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), "utf-8");
6601
+ mkdirSync8(DATA_DIR, { recursive: true });
6602
+ writeFileSync9(CHECK_FILE, (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), "utf-8");
6434
6603
  }
6435
6604
  function isFirstUseToday() {
6436
6605
  const last = getLastCheckDate();
@@ -6439,10 +6608,10 @@ function isFirstUseToday() {
6439
6608
  return last !== today;
6440
6609
  }
6441
6610
  function fetchLatestVersion() {
6442
- return new Promise((resolve6) => {
6611
+ return new Promise((resolve7) => {
6443
6612
  const req = get(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, { timeout: 5e3 }, (res) => {
6444
6613
  if (res.statusCode !== 200) {
6445
- resolve6(null);
6614
+ resolve7(null);
6446
6615
  return;
6447
6616
  }
6448
6617
  let data = "";
@@ -6451,18 +6620,18 @@ function fetchLatestVersion() {
6451
6620
  });
6452
6621
  res.on("end", () => {
6453
6622
  try {
6454
- resolve6(JSON.parse(data).version);
6623
+ resolve7(JSON.parse(data).version);
6455
6624
  } catch {
6456
- resolve6(null);
6625
+ resolve7(null);
6457
6626
  }
6458
6627
  });
6459
6628
  });
6460
6629
  req.on("error", () => {
6461
- resolve6(null);
6630
+ resolve7(null);
6462
6631
  });
6463
6632
  req.on("timeout", () => {
6464
6633
  req.destroy();
6465
- resolve6(null);
6634
+ resolve7(null);
6466
6635
  });
6467
6636
  });
6468
6637
  }
@@ -6600,7 +6769,7 @@ function parseArgs(argv) {
6600
6769
  port = parseInt(args[++i], 10);
6601
6770
  break;
6602
6771
  case "--data-dir":
6603
- dataDir = resolve5(args[++i]);
6772
+ dataDir = resolve6(args[++i]);
6604
6773
  break;
6605
6774
  case "--resume":
6606
6775
  resume = true;
@@ -6656,13 +6825,13 @@ async function main() {
6656
6825
  console.log("AI service test mode enabled \u2014 using mock AI responses");
6657
6826
  }
6658
6827
  if (debug) {
6659
- console.log(`[debug] Build timestamp: ${"2026-04-07T23:55:50.436Z"}`);
6828
+ console.log(`[debug] Build timestamp: ${"2026-04-08T00:38:37.701Z"}`);
6660
6829
  }
6661
6830
  if (projectDir !== null) {
6662
6831
  process.chdir(projectDir);
6663
6832
  }
6664
6833
  if (dataDir === null) {
6665
- dataDir = join11(process.cwd(), ".glassbox");
6834
+ dataDir = join13(process.cwd(), ".glassbox");
6666
6835
  }
6667
6836
  if (demo !== null) {
6668
6837
  const scenario = DEMO_SCENARIOS.find((s) => s.id === demo);
@@ -6674,13 +6843,13 @@ async function main() {
6674
6843
  }
6675
6844
  process.exit(1);
6676
6845
  }
6677
- dataDir = join11(tmpdir(), `glassbox-demo-${demo}-${Date.now()}`);
6846
+ dataDir = join13(tmpdir(), `glassbox-demo-${demo}-${Date.now()}`);
6678
6847
  setDemoMode(demo);
6679
6848
  console.log(`
6680
6849
  DEMO MODE: ${scenario.label}
6681
6850
  `);
6682
6851
  }
6683
- mkdirSync8(dataDir, { recursive: true });
6852
+ mkdirSync9(dataDir, { recursive: true });
6684
6853
  if (demo === null) {
6685
6854
  acquireLock(dataDir);
6686
6855
  }