getgloss 0.3.0 → 0.4.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.
@@ -16,7 +16,7 @@ import path from "path";
16
16
  // package.json
17
17
  var package_default = {
18
18
  name: "getgloss",
19
- version: "0.3.0",
19
+ version: "0.4.1",
20
20
  description: "Local browser-based diff review for coding-agent loops.",
21
21
  type: "module",
22
22
  packageManager: "pnpm@10.33.2",
@@ -47,7 +47,6 @@ var package_default = {
47
47
  },
48
48
  dependencies: {
49
49
  "@hono/node-server": "^1.14.4",
50
- "@modelcontextprotocol/sdk": "^1.29.0",
51
50
  "@pierre/diffs": "^1.2.1",
52
51
  "@tailwindcss/vite": "^4.1.7",
53
52
  commander: "^14.0.0",
@@ -78,8 +77,7 @@ var package_default = {
78
77
  keywords: [
79
78
  "diff",
80
79
  "review",
81
- "coding-agents",
82
- "mcp"
80
+ "coding-agents"
83
81
  ],
84
82
  author: "Raj Joshi",
85
83
  license: "MIT",
@@ -263,6 +261,9 @@ var ReviewStore = class {
263
261
  if (!record) {
264
262
  throw new Error(`Review ${id} not found`);
265
263
  }
264
+ if (record.meta.status !== "pending") {
265
+ throw new Error(`Review ${id} is ${record.meta.status} and cannot be submitted`);
266
+ }
266
267
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
267
268
  const feedback = {
268
269
  version: 1,
@@ -275,7 +276,7 @@ var ReviewStore = class {
275
276
  )
276
277
  };
277
278
  record.feedback = feedback;
278
- record.meta = { ...record.meta, status: "completed", completedAt: timestamp };
279
+ record.meta = { ...record.meta, status: "submitted", submittedAt: timestamp };
279
280
  this.reviews.set(id, record);
280
281
  const artifactDir = globalReviewDir(id);
281
282
  const feedbackPath = globalReviewFeedbackFile(id);
@@ -295,7 +296,7 @@ var ReviewStore = class {
295
296
  writeFile2(markdownPath, serializeFeedbackMarkdown(feedback))
296
297
  ]);
297
298
  this.emit({
298
- type: "review.completed",
299
+ type: "review.submitted",
299
300
  reviewId: id,
300
301
  counts: {
301
302
  files: new Set(feedback.comments.map((comment) => comment.filePath)).size,
@@ -313,19 +314,88 @@ var ReviewStore = class {
313
314
  if (!record) {
314
315
  throw new Error(`Review ${id} not found`);
315
316
  }
317
+ this.assertResolvable(record, id);
316
318
  const resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
317
- const resolvedPath = globalReviewResolvedFile(id);
319
+ const existingById = new Map(
320
+ (record.resolution?.comments ?? []).map((comment) => [comment.commentId, comment])
321
+ );
322
+ const comments = this.sortResolvedComments(
323
+ (record.feedback?.comments ?? []).map((comment) => ({
324
+ ...existingById.get(comment.id),
325
+ commentId: comment.id,
326
+ status: "resolved",
327
+ resolvedAt: existingById.get(comment.id)?.resolvedAt ?? resolvedAt
328
+ })),
329
+ record
330
+ );
331
+ const resolution = {
332
+ reviewId: id,
333
+ status: "resolved",
334
+ summary: summary ?? record.resolution?.summary ?? null,
335
+ resolvedAt,
336
+ comments
337
+ };
318
338
  record.meta = { ...record.meta, status: "resolved", resolvedAt };
319
- this.reviews.set(id, record);
320
- await ensureDir(globalReviewDir(id));
321
- await writeFile2(
322
- resolvedPath,
323
- `${JSON.stringify({ reviewId: id, summary: summary ?? null, resolvedAt }, null, 2)}
324
- `
339
+ return this.persistResolution(record, resolution);
340
+ }
341
+ async resolveComment(id, commentId, summary) {
342
+ const record = await this.get(id);
343
+ if (!record) {
344
+ throw new Error(`Review ${id} not found`);
345
+ }
346
+ this.assertResolvable(record, id);
347
+ this.assertCommentExists(record, commentId);
348
+ const resolvedAt = (/* @__PURE__ */ new Date()).toISOString();
349
+ const previous = record.resolution?.comments.find((comment) => comment.commentId === commentId);
350
+ const nextSummary = summary ?? previous?.summary;
351
+ const nextComment = {
352
+ commentId,
353
+ status: "resolved",
354
+ ...nextSummary ? { summary: nextSummary } : {},
355
+ resolvedAt
356
+ };
357
+ const comments = this.sortResolvedComments(
358
+ [
359
+ ...(record.resolution?.comments ?? []).filter((comment) => comment.commentId !== commentId),
360
+ nextComment
361
+ ],
362
+ record
325
363
  );
326
- await writeFile2(globalReviewMetaFile(id), `${JSON.stringify(record.meta, null, 2)}
327
- `);
328
- return resolvedPath;
364
+ const counts = this.resolutionCounts(record, comments);
365
+ const fullyResolved = counts.total === counts.resolved;
366
+ const resolution = {
367
+ reviewId: id,
368
+ status: fullyResolved ? "resolved" : "partial",
369
+ summary: fullyResolved ? record.resolution?.summary ?? null : null,
370
+ resolvedAt: fullyResolved ? resolvedAt : null,
371
+ comments
372
+ };
373
+ record.meta = fullyResolved ? { ...record.meta, status: "resolved", resolvedAt } : { ...record.meta, status: "submitted", resolvedAt: void 0 };
374
+ return this.persistResolution(record, resolution);
375
+ }
376
+ async reopenComment(id, commentId) {
377
+ const record = await this.get(id);
378
+ if (!record) {
379
+ throw new Error(`Review ${id} not found`);
380
+ }
381
+ this.assertResolvable(record, id);
382
+ this.assertCommentExists(record, commentId);
383
+ const comments = this.sortResolvedComments(
384
+ (record.resolution?.comments ?? []).filter((comment) => comment.commentId !== commentId),
385
+ record
386
+ );
387
+ const counts = this.resolutionCounts(record, comments);
388
+ const fullyResolved = counts.total > 0 && counts.total === counts.resolved;
389
+ const resolvedAt = fullyResolved ? (/* @__PURE__ */ new Date()).toISOString() : null;
390
+ const resolution = {
391
+ reviewId: id,
392
+ status: fullyResolved ? "resolved" : "partial",
393
+ summary: fullyResolved ? record.resolution?.summary ?? null : null,
394
+ resolvedAt,
395
+ comments
396
+ };
397
+ record.meta = fullyResolved ? { ...record.meta, status: "resolved", resolvedAt: resolvedAt ?? void 0 } : { ...record.meta, status: "submitted", resolvedAt: void 0 };
398
+ return this.persistResolution(record, resolution);
329
399
  }
330
400
  subscribe(reviewId, listener) {
331
401
  const listeners = this.listeners.get(reviewId) ?? /* @__PURE__ */ new Set();
@@ -380,6 +450,7 @@ var ReviewStore = class {
380
450
  const meta = JSON.parse(metaRaw);
381
451
  const diff = JSON.parse(diffRaw);
382
452
  let feedback;
453
+ let resolution;
383
454
  try {
384
455
  feedback = JSON.parse(
385
456
  await readFile2(globalReviewFeedbackFile(id), "utf8")
@@ -387,6 +458,13 @@ var ReviewStore = class {
387
458
  } catch {
388
459
  feedback = void 0;
389
460
  }
461
+ try {
462
+ resolution = JSON.parse(
463
+ await readFile2(globalReviewResolvedFile(id), "utf8")
464
+ );
465
+ } catch {
466
+ resolution = void 0;
467
+ }
390
468
  const record = {
391
469
  meta: {
392
470
  ...meta,
@@ -395,7 +473,8 @@ var ReviewStore = class {
395
473
  markdownPath: meta.markdownPath ?? (feedback ? globalReviewMarkdownFile(id) : void 0)
396
474
  },
397
475
  diff,
398
- feedback
476
+ feedback,
477
+ resolution
399
478
  };
400
479
  this.reviews.set(id, record);
401
480
  return record;
@@ -403,11 +482,66 @@ var ReviewStore = class {
403
482
  return null;
404
483
  }
405
484
  }
485
+ assertResolvable(record, id) {
486
+ if (record.meta.status !== "submitted" && record.meta.status !== "resolved") {
487
+ throw new Error(`Review ${id} is ${record.meta.status} and cannot be resolved`);
488
+ }
489
+ if (!record.feedback) {
490
+ throw new Error(`Review ${id} has no submitted feedback`);
491
+ }
492
+ }
493
+ assertCommentExists(record, commentId) {
494
+ if (!record.feedback.comments.some((comment) => comment.id === commentId)) {
495
+ throw new Error(`Comment ${commentId} not found`);
496
+ }
497
+ }
498
+ async persistResolution(record, resolution) {
499
+ record.resolution = resolution;
500
+ this.reviews.set(record.meta.id, record);
501
+ const resolvedPath = globalReviewResolvedFile(record.meta.id);
502
+ await ensureDir(globalReviewDir(record.meta.id));
503
+ await Promise.all([
504
+ writeFile2(resolvedPath, `${JSON.stringify(resolution, null, 2)}
505
+ `),
506
+ writeFile2(globalReviewMetaFile(record.meta.id), `${JSON.stringify(record.meta, null, 2)}
507
+ `)
508
+ ]);
509
+ return {
510
+ ok: true,
511
+ reviewId: record.meta.id,
512
+ status: record.meta.status,
513
+ resolutionStatus: resolution.status,
514
+ comments: this.resolutionCounts(record, resolution.comments),
515
+ path: resolvedPath,
516
+ resolution
517
+ };
518
+ }
519
+ sortResolvedComments(comments, record) {
520
+ const feedbackIndex = new Map(
521
+ record.feedback.comments.map((comment, index) => [comment.id, index])
522
+ );
523
+ return comments.filter((comment) => feedbackIndex.has(comment.commentId)).sort(
524
+ (a, b) => (feedbackIndex.get(a.commentId) ?? Number.MAX_SAFE_INTEGER) - (feedbackIndex.get(b.commentId) ?? Number.MAX_SAFE_INTEGER)
525
+ );
526
+ }
527
+ resolutionCounts(record, comments) {
528
+ const total = record.feedback.comments.length;
529
+ const resolvedIds = new Set(comments.map((comment) => comment.commentId));
530
+ const resolved = record.feedback.comments.filter(
531
+ (comment) => resolvedIds.has(comment.id)
532
+ ).length;
533
+ return {
534
+ total,
535
+ resolved,
536
+ open: total - resolved
537
+ };
538
+ }
406
539
  };
407
540
  var reviewStore = new ReviewStore();
408
541
 
409
542
  // src/server/index.ts
410
543
  var webRoot = fileURLToPath2(new URL("../web", import.meta.url));
544
+ var eventStreamHeartbeatMs = 15e3;
411
545
  var mimeTypes = {
412
546
  ".css": "text/css; charset=utf-8",
413
547
  ".html": "text/html; charset=utf-8",
@@ -458,20 +592,48 @@ function createApp(origin2) {
458
592
  let cleanup = null;
459
593
  const stream = new ReadableStream({
460
594
  start(controller) {
595
+ let closed = false;
596
+ let heartbeat = null;
597
+ const write = (chunk) => {
598
+ if (!closed) {
599
+ controller.enqueue(encoder.encode(chunk));
600
+ }
601
+ };
602
+ const close = () => {
603
+ if (closed) {
604
+ return;
605
+ }
606
+ closed = true;
607
+ if (heartbeat) {
608
+ clearInterval(heartbeat);
609
+ }
610
+ cleanup?.();
611
+ };
461
612
  const send = (event) => {
462
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}
613
+ write(`data: ${JSON.stringify(event)}
463
614
 
464
- `));
465
- if (event.type === "review.completed" || event.type === "review.cancelled") {
466
- cleanup?.();
615
+ `);
616
+ if (event.type === "review.submitted" || event.type === "review.cancelled") {
617
+ close();
467
618
  controller.close();
468
619
  }
469
620
  };
470
- cleanup = reviewStore.subscribe(id, send);
621
+ const unsubscribe = reviewStore.subscribe(id, send);
622
+ heartbeat = setInterval(() => {
623
+ write(`: keep-alive ${Date.now()}
624
+
625
+ `);
626
+ }, eventStreamHeartbeatMs);
627
+ cleanup = () => {
628
+ if (heartbeat) {
629
+ clearInterval(heartbeat);
630
+ }
631
+ unsubscribe();
632
+ };
471
633
  send({ type: "review.opened", reviewId: id });
472
- if ((record.meta.status === "completed" || record.meta.status === "resolved") && record.feedback) {
634
+ if ((record.meta.status === "submitted" || record.meta.status === "resolved") && record.feedback) {
473
635
  send({
474
- type: "review.completed",
636
+ type: "review.submitted",
475
637
  reviewId: id,
476
638
  counts: {
477
639
  files: new Set(record.feedback.comments.map((comment) => comment.filePath)).size,
@@ -486,14 +648,22 @@ function createApp(origin2) {
486
648
  });
487
649
  return new Response(stream, {
488
650
  headers: {
489
- "cache-control": "no-cache",
651
+ "cache-control": "no-cache, no-transform",
490
652
  connection: "keep-alive",
491
- "content-type": "text/event-stream"
653
+ "content-type": "text/event-stream",
654
+ "x-accel-buffering": "no"
492
655
  }
493
656
  });
494
657
  });
495
658
  app.post("/api/reviews/:id/submit", async (c) => {
496
659
  const id = c.req.param("id");
660
+ const existing = await reviewStore.get(id);
661
+ if (!existing) {
662
+ return c.json({ error: "review not found" }, 404);
663
+ }
664
+ if (existing.meta.status !== "pending") {
665
+ return c.json({ error: `review is ${existing.meta.status} and cannot be submitted` }, 409);
666
+ }
497
667
  const body = await c.req.json();
498
668
  const { record, feedbackPath, markdownPath } = await reviewStore.submit(
499
669
  id,
@@ -510,9 +680,50 @@ function createApp(origin2) {
510
680
  });
511
681
  });
512
682
  app.post("/api/reviews/:id/resolved", async (c) => {
683
+ const id = c.req.param("id");
684
+ const existing = await reviewStore.get(id);
685
+ if (!existing) {
686
+ return c.json({ error: "review not found" }, 404);
687
+ }
688
+ if (existing.meta.status !== "submitted" && existing.meta.status !== "resolved") {
689
+ return c.json({ error: `review is ${existing.meta.status} and cannot be resolved` }, 409);
690
+ }
691
+ if (!existing.feedback) {
692
+ return c.json({ error: "submitted feedback not found" }, 409);
693
+ }
513
694
  const body = await c.req.json().catch(() => ({}));
514
- const resolvedPath = await reviewStore.markResolved(c.req.param("id"), body.summary);
515
- return c.json({ ok: true, path: resolvedPath });
695
+ return c.json(await reviewStore.markResolved(id, body.summary));
696
+ });
697
+ app.post("/api/reviews/:id/comments/:commentId/resolved", async (c) => {
698
+ const id = c.req.param("id");
699
+ const commentId = c.req.param("commentId");
700
+ const existing = await reviewStore.get(id);
701
+ if (!existing) {
702
+ return c.json({ error: "review not found" }, 404);
703
+ }
704
+ if (existing.meta.status !== "submitted" && existing.meta.status !== "resolved") {
705
+ return c.json({ error: `review is ${existing.meta.status} and cannot be resolved` }, 409);
706
+ }
707
+ if (!existing.feedback?.comments.some((comment) => comment.id === commentId)) {
708
+ return c.json({ error: "comment not found" }, 404);
709
+ }
710
+ const body = await c.req.json().catch(() => ({}));
711
+ return c.json(await reviewStore.resolveComment(id, commentId, body.summary));
712
+ });
713
+ app.delete("/api/reviews/:id/comments/:commentId/resolved", async (c) => {
714
+ const id = c.req.param("id");
715
+ const commentId = c.req.param("commentId");
716
+ const existing = await reviewStore.get(id);
717
+ if (!existing) {
718
+ return c.json({ error: "review not found" }, 404);
719
+ }
720
+ if (existing.meta.status !== "submitted" && existing.meta.status !== "resolved") {
721
+ return c.json({ error: `review is ${existing.meta.status} and cannot be resolved` }, 409);
722
+ }
723
+ if (!existing.feedback?.comments.some((comment) => comment.id === commentId)) {
724
+ return c.json({ error: "comment not found" }, 404);
725
+ }
726
+ return c.json(await reviewStore.reopenComment(id, commentId));
516
727
  });
517
728
  app.get("/logo.svg", serveRootFile("logo.svg", mimeTypes[".svg"]));
518
729
  app.get("/logo-mark.svg", serveRootFile("logo-mark.svg", mimeTypes[".svg"]));
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/daemon.ts","../../src/cli/lifecycle.ts","../../src/shared/paths.ts","../../package.json","../../src/server/index.ts","../../src/server/store.ts","../../src/shared/markdown.ts"],"sourcesContent":["import { serve } from '@hono/node-server';\nimport { writeServerInfo } from '../cli/lifecycle';\nimport { globalStateDir, packageVersion } from '../shared/paths';\nimport { createApp } from './index';\n\nconst port = Number(process.env.GLOSS_PORT ?? '0');\n\nif (!port) {\n throw new Error('GLOSS_PORT is required');\n}\n\nconst origin = `http://localhost:${port}`;\nconst server = serve({\n fetch: createApp(origin).fetch,\n port\n});\n\nawait writeServerInfo({\n pid: process.pid,\n port,\n version: packageVersion,\n startedAt: new Date().toISOString(),\n stateDir: globalStateDir()\n});\n\nprocess.on('SIGTERM', () => {\n server.close(() => {\n process.exit(0);\n });\n});\n","import { spawn } from 'node:child_process';\nimport { existsSync, openSync } from 'node:fs';\nimport { readFile, rm, writeFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\nimport getPort from 'get-port';\nimport {\n ensureDir,\n globalLogDir,\n globalServerFile,\n globalServerLogFile,\n globalStateDir,\n packageVersion\n} from '../shared/paths';\nimport type { ServerInfo } from '../shared/types';\nimport { ServerClient } from './server-client';\n\nexport async function readServerInfo(): Promise<ServerInfo | null> {\n try {\n return JSON.parse(await readFile(globalServerFile(), 'utf8')) as ServerInfo;\n } catch {\n return null;\n }\n}\n\nexport function serverUrl(info: Pick<ServerInfo, 'port'>): string {\n return `http://localhost:${info.port}`;\n}\n\nexport async function isServerResponsive(info: ServerInfo): Promise<boolean> {\n if (!isPidAlive(info.pid)) {\n return false;\n }\n try {\n const health = await new ServerClient(serverUrl(info)).health();\n return health.ok === true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureServer(options: { port?: number } = {}): Promise<ServerInfo> {\n const existing = await readServerInfo();\n if (existing && (await isServerResponsive(existing))) {\n return existing;\n }\n return startServer(options);\n}\n\nexport async function startServer(options: { port?: number } = {}): Promise<ServerInfo> {\n const existing = await readServerInfo();\n if (existing && (await isServerResponsive(existing))) {\n return existing;\n }\n\n await ensureDir(globalStateDir());\n await ensureDir(globalLogDir());\n const port = options.port ?? (await getPort());\n const daemonPath = fileURLToPath(new URL('../server/daemon.js', import.meta.url));\n if (!existsSync(daemonPath)) {\n throw new Error(`Cannot find server daemon at ${daemonPath}. Run pnpm build first.`);\n }\n\n const logFd = openSync(globalServerLogFile(), 'a');\n const child = spawn(process.execPath, [daemonPath], {\n detached: true,\n env: {\n ...process.env,\n GLOSS_PORT: String(port),\n GLOSS_STATE_DIR: globalStateDir()\n },\n stdio: ['ignore', logFd, logFd]\n });\n child.unref();\n\n const info: ServerInfo = {\n pid: child.pid ?? -1,\n port,\n version: packageVersion,\n startedAt: new Date().toISOString(),\n stateDir: globalStateDir()\n };\n await writeFile(globalServerFile(), `${JSON.stringify(info, null, 2)}\\n`);\n\n const deadline = Date.now() + 8000;\n while (Date.now() < deadline) {\n if (await isServerResponsive(info)) {\n return info;\n }\n await new Promise((resolve) => setTimeout(resolve, 150));\n }\n\n throw new Error(`Server did not become responsive. See ${globalServerLogFile()}`);\n}\n\nexport async function stopServer(): Promise<{ stopped: boolean; info: ServerInfo | null }> {\n const info = await readServerInfo();\n if (!info) {\n return { stopped: false, info: null };\n }\n\n if (isPidAlive(info.pid)) {\n process.kill(info.pid, 'SIGTERM');\n }\n await rm(globalServerFile(), { force: true });\n return { stopped: true, info };\n}\n\nexport async function writeServerInfo(info: ServerInfo): Promise<void> {\n await ensureDir(globalStateDir());\n await writeFile(globalServerFile(), `${JSON.stringify(info, null, 2)}\\n`);\n}\n\nexport function isPidAlive(pid: number): boolean {\n if (pid <= 0) {\n return false;\n }\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n","import { mkdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport path from 'node:path';\nimport packageJson from '../../package.json';\n\nexport const packageVersion = packageJson.version;\n\nexport function expandHome(input: string): string {\n if (input === '~') {\n return homedir();\n }\n if (input.startsWith('~/')) {\n return path.join(homedir(), input.slice(2));\n }\n return input;\n}\n\nexport function globalStateDir(): string {\n return expandHome(process.env.GLOSS_STATE_DIR ?? '~/.gloss');\n}\n\nexport function globalServerFile(): string {\n return path.join(globalStateDir(), 'server.json');\n}\n\nexport function globalLogDir(): string {\n return path.join(globalStateDir(), 'logs');\n}\n\nexport function globalServerLogFile(): string {\n return path.join(globalLogDir(), 'server.log');\n}\n\nexport function globalReviewsDir(): string {\n return path.join(globalStateDir(), 'reviews');\n}\n\nexport function globalReviewDir(reviewId: string): string {\n return path.join(globalReviewsDir(), reviewId);\n}\n\nexport function globalReviewMetaFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'meta.json');\n}\n\nexport function globalReviewDiffFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'diff.json');\n}\n\nexport function globalReviewFeedbackFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'feedback.json');\n}\n\nexport function globalReviewMarkdownFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'feedback.md');\n}\n\nexport function globalReviewResolvedFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'resolved.json');\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true });\n}\n","{\n \"name\": \"getgloss\",\n \"version\": \"0.3.0\",\n \"description\": \"Local browser-based diff review for coding-agent loops.\",\n \"type\": \"module\",\n \"packageManager\": \"pnpm@10.33.2\",\n \"bin\": {\n \"getgloss\": \"./dist/cli/index.js\",\n \"gloss\": \"./dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"skill\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"pnpm build:web && pnpm build:node\",\n \"build:web\": \"vite build\",\n \"build:node\": \"tsup\",\n \"check\": \"biome check .\",\n \"format\": \"biome format --write .\",\n \"prepack\": \"pnpm build\",\n \"dev:web\": \"vite --host 127.0.0.1\",\n \"setup\": \"tsx scripts/dev-cli.ts\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"engines\": {\n \"node\": \">=20\"\n },\n \"dependencies\": {\n \"@hono/node-server\": \"^1.14.4\",\n \"@modelcontextprotocol/sdk\": \"^1.29.0\",\n \"@pierre/diffs\": \"^1.2.1\",\n \"@tailwindcss/vite\": \"^4.1.7\",\n \"commander\": \"^14.0.0\",\n \"execa\": \"^9.5.3\",\n \"get-port\": \"^7.1.0\",\n \"hono\": \"^4.7.10\",\n \"lucide-react\": \"^1.16.0\",\n \"open\": \"^10.1.2\",\n \"react\": \"^19.1.0\",\n \"react-dom\": \"^19.1.0\",\n \"ulid\": \"^3.0.0\",\n \"zod\": \"^4.4.3\",\n \"zustand\": \"^5.0.5\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.0.6\",\n \"@types/node\": \"^24.0.1\",\n \"@types/react\": \"^19.1.6\",\n \"@types/react-dom\": \"^19.1.5\",\n \"@vitejs/plugin-react\": \"^4.5.2\",\n \"playwright\": \"^1.52.0\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"vite\": \"^6.3.5\",\n \"vitest\": \"^3.2.3\"\n },\n \"keywords\": [\n \"diff\",\n \"review\",\n \"coding-agents\",\n \"mcp\"\n ],\n \"author\": \"Raj Joshi\",\n \"license\": \"MIT\",\n \"homepage\": \"https://getgloss.dev\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/iamrajjoshi/gloss.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/iamrajjoshi/gloss/issues\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Context } from 'hono';\nimport { Hono } from 'hono';\nimport { globalReviewDir, packageVersion } from '../shared/paths';\nimport type { Comment, DiffPayload, ReviewEvent } from '../shared/types';\nimport { reviewStore } from './store';\n\nconst webRoot = fileURLToPath(new URL('../web', import.meta.url));\n\nconst mimeTypes: Record<string, string> = {\n '.css': 'text/css; charset=utf-8',\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.map': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.sh': 'text/x-shellscript; charset=utf-8',\n '.svg': 'image/svg+xml'\n};\n\nexport function createApp(origin: string): Hono {\n const app = new Hono();\n\n app.get('/api/health', async (c) => {\n const reviews = await reviewStore.list();\n return c.json({\n ok: true,\n version: packageVersion,\n activeReviews: reviews.filter((review) => review.status === 'pending').length\n });\n });\n\n app.get('/api/reviews', async (c) => c.json({ reviews: await reviewStore.list() }));\n\n app.post('/api/reviews', async (c) => {\n const diff = (await c.req.json()) as DiffPayload;\n const record = await reviewStore.create(diff);\n return c.json({ meta: record.meta, url: `${origin}/review/${record.meta.id}` }, 201);\n });\n\n app.get('/api/reviews/:id', async (c) => {\n const record = await reviewStore.get(c.req.param('id'));\n if (!record) {\n return c.json({ error: 'review not found' }, 404);\n }\n return c.json(record);\n });\n\n app.get('/api/reviews/:id/feedback', async (c) => {\n const feedback = await reviewStore.feedback(c.req.param('id'));\n if (!feedback) {\n return c.json({ error: 'feedback not found' }, 404);\n }\n return c.json(feedback);\n });\n\n app.get('/api/reviews/:id/events', async (c) => {\n const id = c.req.param('id');\n const record = await reviewStore.get(id);\n if (!record) {\n return c.json({ error: 'review not found' }, 404);\n }\n\n const encoder = new TextEncoder();\n let cleanup: (() => void) | null = null;\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n const send = (event: ReviewEvent) => {\n controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\\n\\n`));\n if (event.type === 'review.completed' || event.type === 'review.cancelled') {\n cleanup?.();\n controller.close();\n }\n };\n cleanup = reviewStore.subscribe(id, send);\n send({ type: 'review.opened', reviewId: id });\n if (\n (record.meta.status === 'completed' || record.meta.status === 'resolved') &&\n record.feedback\n ) {\n send({\n type: 'review.completed',\n reviewId: id,\n counts: {\n files: new Set(record.feedback.comments.map((comment) => comment.filePath)).size,\n comments: record.feedback.comments.length\n }\n });\n }\n },\n cancel() {\n cleanup?.();\n }\n });\n\n return new Response(stream, {\n headers: {\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n 'content-type': 'text/event-stream'\n }\n });\n });\n\n app.post('/api/reviews/:id/submit', async (c) => {\n const id = c.req.param('id');\n const body = (await c.req.json()) as { comments: Comment[] };\n const { record, feedbackPath, markdownPath } = await reviewStore.submit(\n id,\n body.comments ?? []\n );\n return c.json({\n reviewId: id,\n url: `${origin}/review/${id}`,\n files: record.diff.files.length,\n comments: body.comments?.length ?? 0,\n artifactDir: record.meta.artifactDir,\n feedbackPath,\n markdownPath\n });\n });\n\n app.post('/api/reviews/:id/resolved', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as { summary?: string };\n const resolvedPath = await reviewStore.markResolved(c.req.param('id'), body.summary);\n return c.json({ ok: true, path: resolvedPath });\n });\n\n app.get('/logo.svg', serveRootFile('logo.svg', mimeTypes['.svg']));\n app.get('/logo-mark.svg', serveRootFile('logo-mark.svg', mimeTypes['.svg']));\n app.get('/og.png', serveRootFile('og.png', mimeTypes['.png']));\n app.get('/install.sh', serveRootFile('install.sh', mimeTypes['.sh']));\n app.get('/setup.md', serveRootFile('setup.md', 'text/markdown; charset=utf-8'));\n app.get('/prompt.md', serveRootFile('prompt.md', 'text/markdown; charset=utf-8'));\n app.get('/assets/*', serveAsset);\n app.get('/setup', serveIndex);\n app.get('/setup/', serveIndex);\n app.get('/review/:id', serveIndex);\n app.get('/', serveIndex);\n\n return app;\n}\n\nasync function serveAsset(c: Context) {\n const requestPath = new URL(c.req.url).pathname.replace(/^\\/assets\\//, '');\n const normalized = path.normalize(requestPath).replace(/^(\\.\\.(\\/|\\\\|$))+/, '');\n const assetPath = path.join(webRoot, 'assets', normalized);\n try {\n const body = await readFile(assetPath);\n return new Response(body, {\n headers: {\n 'content-type': mimeTypes[path.extname(assetPath)] ?? 'application/octet-stream'\n }\n });\n } catch {\n return new Response('Not found', { status: 404 });\n }\n}\n\nasync function serveIndex() {\n try {\n const body = await readFile(path.join(webRoot, 'index.html'));\n return new Response(body, {\n headers: { 'content-type': 'text/html; charset=utf-8' }\n });\n } catch {\n return new Response('Gloss web assets are missing. Run pnpm build.', { status: 500 });\n }\n}\n\nfunction serveRootFile(fileName: string, contentType: string) {\n return async () => {\n try {\n const body = await readFile(path.join(webRoot, fileName));\n return new Response(body, {\n headers: { 'content-type': contentType }\n });\n } catch {\n return new Response(`${fileName} is missing. Run pnpm build.`, { status: 404 });\n }\n };\n}\n\nexport function getReviewArtifactDir(_cwd: string, reviewId: string): string {\n return globalReviewDir(reviewId);\n}\n","import type { Dirent } from 'node:fs';\nimport { readdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { ulid } from 'ulid';\nimport { serializeFeedbackMarkdown } from '../shared/markdown';\nimport {\n ensureDir,\n globalReviewDiffFile,\n globalReviewDir,\n globalReviewFeedbackFile,\n globalReviewMarkdownFile,\n globalReviewMetaFile,\n globalReviewResolvedFile,\n globalReviewsDir\n} from '../shared/paths';\nimport type {\n Comment,\n DiffPayload,\n FeedbackBundle,\n ReviewEvent,\n ReviewMeta,\n ReviewRecord\n} from '../shared/types';\n\ntype Listener = (event: ReviewEvent) => void;\n\nexport class ReviewStore {\n private readonly reviews = new Map<string, ReviewRecord>();\n private readonly listeners = new Map<string, Set<Listener>>();\n\n async create(diff: DiffPayload): Promise<ReviewRecord> {\n const id = ulid();\n const createdAt = new Date().toISOString();\n const meta: ReviewMeta = {\n id,\n cwd: diff.cwd,\n base: diff.base,\n branch: diff.branch,\n status: 'pending',\n createdAt,\n artifactDir: globalReviewDir(id)\n };\n const record: ReviewRecord = { meta, diff };\n this.reviews.set(id, record);\n await this.persistInitial(record);\n this.emit({ type: 'review.opened', reviewId: id });\n return record;\n }\n\n async list(): Promise<ReviewMeta[]> {\n await this.loadAllReviews();\n return [...this.reviews.values()]\n .map((record) => record.meta)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n }\n\n async get(id: string): Promise<ReviewRecord | null> {\n return this.reviews.get(id) ?? (await this.loadKnownReview(id));\n }\n\n async submit(\n id: string,\n comments: Comment[]\n ): Promise<{ record: ReviewRecord; feedbackPath: string; markdownPath: string }> {\n const record = await this.get(id);\n if (!record) {\n throw new Error(`Review ${id} not found`);\n }\n const timestamp = new Date().toISOString();\n const feedback: FeedbackBundle = {\n version: 1,\n reviewId: id,\n timestamp,\n base: record.diff.base,\n branch: record.diff.branch,\n comments: [...comments].sort(\n (a, b) =>\n a.filePath.localeCompare(b.filePath) ||\n a.startLine - b.startLine ||\n a.endLine - b.endLine ||\n a.side.localeCompare(b.side)\n )\n };\n record.feedback = feedback;\n record.meta = { ...record.meta, status: 'completed', completedAt: timestamp };\n this.reviews.set(id, record);\n\n const artifactDir = globalReviewDir(id);\n const feedbackPath = globalReviewFeedbackFile(id);\n const markdownPath = globalReviewMarkdownFile(id);\n record.meta = {\n ...record.meta,\n artifactDir,\n feedbackPath,\n markdownPath\n };\n await ensureDir(artifactDir);\n await Promise.all([\n writeFile(globalReviewMetaFile(id), `${JSON.stringify(record.meta, null, 2)}\\n`),\n writeFile(feedbackPath, `${JSON.stringify(feedback, null, 2)}\\n`),\n writeFile(markdownPath, serializeFeedbackMarkdown(feedback))\n ]);\n\n this.emit({\n type: 'review.completed',\n reviewId: id,\n counts: {\n files: new Set(feedback.comments.map((comment) => comment.filePath)).size,\n comments: feedback.comments.length\n }\n });\n return { record, feedbackPath, markdownPath };\n }\n\n async feedback(id: string): Promise<FeedbackBundle | null> {\n const record = await this.get(id);\n return record?.feedback ?? null;\n }\n\n async markResolved(id: string, summary?: string): Promise<string> {\n const record = await this.get(id);\n if (!record) {\n throw new Error(`Review ${id} not found`);\n }\n const resolvedAt = new Date().toISOString();\n const resolvedPath = globalReviewResolvedFile(id);\n record.meta = { ...record.meta, status: 'resolved', resolvedAt };\n this.reviews.set(id, record);\n await ensureDir(globalReviewDir(id));\n await writeFile(\n resolvedPath,\n `${JSON.stringify({ reviewId: id, summary: summary ?? null, resolvedAt }, null, 2)}\\n`\n );\n await writeFile(globalReviewMetaFile(id), `${JSON.stringify(record.meta, null, 2)}\\n`);\n return resolvedPath;\n }\n\n subscribe(reviewId: string, listener: Listener): () => void {\n const listeners = this.listeners.get(reviewId) ?? new Set<Listener>();\n listeners.add(listener);\n this.listeners.set(reviewId, listeners);\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) {\n this.listeners.delete(reviewId);\n }\n };\n }\n\n private emit(event: ReviewEvent): void {\n for (const listener of this.listeners.get(event.reviewId) ?? []) {\n listener(event);\n }\n }\n\n private async persistInitial(record: ReviewRecord): Promise<void> {\n const dir = globalReviewDir(record.meta.id);\n await ensureDir(dir);\n await Promise.all([\n writeFile(globalReviewMetaFile(record.meta.id), `${JSON.stringify(record.meta, null, 2)}\\n`),\n writeFile(globalReviewDiffFile(record.meta.id), `${JSON.stringify(record.diff, null, 2)}\\n`)\n ]);\n }\n\n private async loadKnownReview(id: string): Promise<ReviewRecord | null> {\n const existing = this.reviews.get(id);\n if (existing) {\n return existing;\n }\n\n return this.loadReview(id);\n }\n\n private async loadAllReviews(): Promise<void> {\n let entries: Dirent[];\n try {\n entries = await readdir(globalReviewsDir(), { withFileTypes: true });\n } catch {\n return;\n }\n\n await Promise.all(\n entries.filter((entry) => entry.isDirectory()).map((entry) => this.loadReview(entry.name))\n );\n }\n\n private async loadReview(id: string): Promise<ReviewRecord | null> {\n try {\n const [metaRaw, diffRaw] = await Promise.all([\n readFile(globalReviewMetaFile(id), 'utf8'),\n readFile(globalReviewDiffFile(id), 'utf8')\n ]);\n const meta = JSON.parse(metaRaw) as ReviewMeta;\n const diff = JSON.parse(diffRaw) as DiffPayload;\n let feedback: FeedbackBundle | undefined;\n try {\n feedback = JSON.parse(\n await readFile(globalReviewFeedbackFile(id), 'utf8')\n ) as FeedbackBundle;\n } catch {\n feedback = undefined;\n }\n\n const record: ReviewRecord = {\n meta: {\n ...meta,\n artifactDir: meta.artifactDir ?? globalReviewDir(id),\n feedbackPath: meta.feedbackPath ?? (feedback ? globalReviewFeedbackFile(id) : undefined),\n markdownPath: meta.markdownPath ?? (feedback ? globalReviewMarkdownFile(id) : undefined)\n },\n diff,\n feedback\n };\n this.reviews.set(id, record);\n return record;\n } catch {\n return null;\n }\n }\n}\n\nexport const reviewStore = new ReviewStore();\n\nexport async function removeReviewArtifacts(_cwd: string, id: string): Promise<void> {\n await rm(globalReviewDir(id), { force: true, recursive: true });\n}\n","import type { Comment, FeedbackBundle } from './types';\n\nfunction formatLineRange(comment: Comment): string {\n const prefix = comment.side;\n if (comment.startLine === comment.endLine) {\n return `${prefix}${comment.startLine}`;\n }\n return `${prefix}${comment.startLine}-${prefix}${comment.endLine}`;\n}\n\nfunction fenceFor(snippet: string): string {\n let fence = '```';\n while (snippet.includes(fence)) {\n fence += '`';\n }\n return fence;\n}\n\nfunction languageForPath(filePath: string): string {\n const ext = filePath.split('.').pop()?.toLowerCase();\n const map: Record<string, string> = {\n cjs: 'js',\n css: 'css',\n go: 'go',\n html: 'html',\n js: 'js',\n json: 'json',\n jsx: 'jsx',\n md: 'markdown',\n mjs: 'js',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n sh: 'bash',\n swift: 'swift',\n ts: 'ts',\n tsx: 'tsx',\n yaml: 'yaml',\n yml: 'yaml'\n };\n return ext ? (map[ext] ?? ext) : '';\n}\n\nfunction languageForSnippet(filePath: string, snippet: string): string {\n const lines = snippet.split('\\n').filter((line) => line.length > 0);\n const looksLikeUnifiedDiff =\n lines.length > 0 &&\n lines.some((line) => line.startsWith('+') || line.startsWith('-')) &&\n lines.every((line) => line.startsWith('+') || line.startsWith('-') || line.startsWith(' '));\n return looksLikeUnifiedDiff ? 'diff' : languageForPath(filePath);\n}\n\nfunction byFileThenLine(a: Comment, b: Comment): number {\n return (\n a.filePath.localeCompare(b.filePath) ||\n a.startLine - b.startLine ||\n a.endLine - b.endLine ||\n a.side.localeCompare(b.side)\n );\n}\n\nexport function serializeFeedbackMarkdown(bundle: FeedbackBundle): string {\n const comments = [...bundle.comments].sort(byFileThenLine);\n const files = [...new Set(comments.map((comment) => comment.filePath))];\n const lines: string[] = [\n `# Gloss feedback - ${bundle.timestamp}`,\n `Review: ${bundle.reviewId}`,\n `Base: ${bundle.base.ref} (${bundle.base.sha.slice(0, 7)}) Branch: ${bundle.branch ?? '(detached)'}`,\n `Files: ${files.length} Comments: ${comments.length}`,\n ''\n ];\n\n for (const filePath of files) {\n lines.push(`## ${filePath}`, '');\n for (const comment of comments.filter((item) => item.filePath === filePath)) {\n const snippet = comment.originalSnippet.trimEnd();\n const firstSnippetLine = snippet.split('\\n').find((line) => line.trim().length > 0);\n const heading =\n comment.startLine === comment.endLine && firstSnippetLine\n ? `### ${formatLineRange(comment)} - \\`${firstSnippetLine.trim().slice(0, 80)}\\``\n : `### ${formatLineRange(comment)}`;\n lines.push(heading, comment.body.trim(), '');\n if (snippet) {\n const fence = fenceFor(snippet);\n lines.push(`${fence}${languageForSnippet(comment.filePath, snippet)}`, snippet, fence, '');\n }\n }\n }\n\n return `${lines.join('\\n').trimEnd()}\\n`;\n}\n"],"mappings":"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","names":["readFile","path","fileURLToPath","readFile","rm","writeFile","writeFile","readFile","fileURLToPath","origin","path","readFile"]}
1
+ {"version":3,"sources":["../../src/server/daemon.ts","../../src/cli/lifecycle.ts","../../src/shared/paths.ts","../../package.json","../../src/server/index.ts","../../src/server/store.ts","../../src/shared/markdown.ts"],"sourcesContent":["import { serve } from '@hono/node-server';\nimport { writeServerInfo } from '../cli/lifecycle';\nimport { globalStateDir, packageVersion } from '../shared/paths';\nimport { createApp } from './index';\n\nconst port = Number(process.env.GLOSS_PORT ?? '0');\n\nif (!port) {\n throw new Error('GLOSS_PORT is required');\n}\n\nconst origin = `http://localhost:${port}`;\nconst server = serve({\n fetch: createApp(origin).fetch,\n port\n});\n\nawait writeServerInfo({\n pid: process.pid,\n port,\n version: packageVersion,\n startedAt: new Date().toISOString(),\n stateDir: globalStateDir()\n});\n\nprocess.on('SIGTERM', () => {\n server.close(() => {\n process.exit(0);\n });\n});\n","import { spawn } from 'node:child_process';\nimport { existsSync, openSync } from 'node:fs';\nimport { readFile, rm, writeFile } from 'node:fs/promises';\nimport { fileURLToPath } from 'node:url';\nimport getPort from 'get-port';\nimport {\n ensureDir,\n globalLogDir,\n globalServerFile,\n globalServerLogFile,\n globalStateDir,\n packageVersion\n} from '../shared/paths';\nimport type { ServerInfo } from '../shared/types';\nimport { ServerClient } from './server-client';\n\nexport async function readServerInfo(): Promise<ServerInfo | null> {\n try {\n return JSON.parse(await readFile(globalServerFile(), 'utf8')) as ServerInfo;\n } catch {\n return null;\n }\n}\n\nexport function serverUrl(info: Pick<ServerInfo, 'port'>): string {\n return `http://localhost:${info.port}`;\n}\n\nexport async function isServerResponsive(info: ServerInfo): Promise<boolean> {\n if (!isPidAlive(info.pid)) {\n return false;\n }\n try {\n const health = await new ServerClient(serverUrl(info)).health();\n return health.ok === true;\n } catch {\n return false;\n }\n}\n\nexport async function ensureServer(options: { port?: number } = {}): Promise<ServerInfo> {\n const existing = await readServerInfo();\n if (existing && (await isServerResponsive(existing))) {\n return existing;\n }\n return startServer(options);\n}\n\nexport async function startServer(options: { port?: number } = {}): Promise<ServerInfo> {\n const existing = await readServerInfo();\n if (existing && (await isServerResponsive(existing))) {\n return existing;\n }\n\n await ensureDir(globalStateDir());\n await ensureDir(globalLogDir());\n const port = options.port ?? (await getPort());\n const daemonPath = fileURLToPath(new URL('../server/daemon.js', import.meta.url));\n if (!existsSync(daemonPath)) {\n throw new Error(`Cannot find server daemon at ${daemonPath}. Run pnpm build first.`);\n }\n\n const logFd = openSync(globalServerLogFile(), 'a');\n const child = spawn(process.execPath, [daemonPath], {\n detached: true,\n env: {\n ...process.env,\n GLOSS_PORT: String(port),\n GLOSS_STATE_DIR: globalStateDir()\n },\n stdio: ['ignore', logFd, logFd]\n });\n child.unref();\n\n const info: ServerInfo = {\n pid: child.pid ?? -1,\n port,\n version: packageVersion,\n startedAt: new Date().toISOString(),\n stateDir: globalStateDir()\n };\n await writeFile(globalServerFile(), `${JSON.stringify(info, null, 2)}\\n`);\n\n const deadline = Date.now() + 8000;\n while (Date.now() < deadline) {\n if (await isServerResponsive(info)) {\n return info;\n }\n await new Promise((resolve) => setTimeout(resolve, 150));\n }\n\n throw new Error(`Server did not become responsive. See ${globalServerLogFile()}`);\n}\n\nexport async function stopServer(): Promise<{ stopped: boolean; info: ServerInfo | null }> {\n const info = await readServerInfo();\n if (!info) {\n return { stopped: false, info: null };\n }\n\n if (isPidAlive(info.pid)) {\n process.kill(info.pid, 'SIGTERM');\n }\n await rm(globalServerFile(), { force: true });\n return { stopped: true, info };\n}\n\nexport async function writeServerInfo(info: ServerInfo): Promise<void> {\n await ensureDir(globalStateDir());\n await writeFile(globalServerFile(), `${JSON.stringify(info, null, 2)}\\n`);\n}\n\nexport function isPidAlive(pid: number): boolean {\n if (pid <= 0) {\n return false;\n }\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n","import { mkdir } from 'node:fs/promises';\nimport { homedir } from 'node:os';\nimport path from 'node:path';\nimport packageJson from '../../package.json';\n\nexport const packageVersion = packageJson.version;\n\nexport function expandHome(input: string): string {\n if (input === '~') {\n return homedir();\n }\n if (input.startsWith('~/')) {\n return path.join(homedir(), input.slice(2));\n }\n return input;\n}\n\nexport function globalStateDir(): string {\n return expandHome(process.env.GLOSS_STATE_DIR ?? '~/.gloss');\n}\n\nexport function globalServerFile(): string {\n return path.join(globalStateDir(), 'server.json');\n}\n\nexport function globalLogDir(): string {\n return path.join(globalStateDir(), 'logs');\n}\n\nexport function globalServerLogFile(): string {\n return path.join(globalLogDir(), 'server.log');\n}\n\nexport function globalReviewsDir(): string {\n return path.join(globalStateDir(), 'reviews');\n}\n\nexport function globalReviewDir(reviewId: string): string {\n return path.join(globalReviewsDir(), reviewId);\n}\n\nexport function globalReviewMetaFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'meta.json');\n}\n\nexport function globalReviewDiffFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'diff.json');\n}\n\nexport function globalReviewFeedbackFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'feedback.json');\n}\n\nexport function globalReviewMarkdownFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'feedback.md');\n}\n\nexport function globalReviewResolvedFile(reviewId: string): string {\n return path.join(globalReviewDir(reviewId), 'resolved.json');\n}\n\nexport async function ensureDir(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true });\n}\n","{\n \"name\": \"getgloss\",\n \"version\": \"0.4.1\",\n \"description\": \"Local browser-based diff review for coding-agent loops.\",\n \"type\": \"module\",\n \"packageManager\": \"pnpm@10.33.2\",\n \"bin\": {\n \"getgloss\": \"./dist/cli/index.js\",\n \"gloss\": \"./dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"skill\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"pnpm build:web && pnpm build:node\",\n \"build:web\": \"vite build\",\n \"build:node\": \"tsup\",\n \"check\": \"biome check .\",\n \"format\": \"biome format --write .\",\n \"prepack\": \"pnpm build\",\n \"dev:web\": \"vite --host 127.0.0.1\",\n \"setup\": \"tsx scripts/dev-cli.ts\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"engines\": {\n \"node\": \">=20\"\n },\n \"dependencies\": {\n \"@hono/node-server\": \"^1.14.4\",\n \"@pierre/diffs\": \"^1.2.1\",\n \"@tailwindcss/vite\": \"^4.1.7\",\n \"commander\": \"^14.0.0\",\n \"execa\": \"^9.5.3\",\n \"get-port\": \"^7.1.0\",\n \"hono\": \"^4.7.10\",\n \"lucide-react\": \"^1.16.0\",\n \"open\": \"^10.1.2\",\n \"react\": \"^19.1.0\",\n \"react-dom\": \"^19.1.0\",\n \"ulid\": \"^3.0.0\",\n \"zod\": \"^4.4.3\",\n \"zustand\": \"^5.0.5\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.0.6\",\n \"@types/node\": \"^24.0.1\",\n \"@types/react\": \"^19.1.6\",\n \"@types/react-dom\": \"^19.1.5\",\n \"@vitejs/plugin-react\": \"^4.5.2\",\n \"playwright\": \"^1.52.0\",\n \"tsup\": \"^8.5.0\",\n \"tsx\": \"^4.20.3\",\n \"typescript\": \"^5.8.3\",\n \"vite\": \"^6.3.5\",\n \"vitest\": \"^3.2.3\"\n },\n \"keywords\": [\n \"diff\",\n \"review\",\n \"coding-agents\"\n ],\n \"author\": \"Raj Joshi\",\n \"license\": \"MIT\",\n \"homepage\": \"https://getgloss.dev\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/iamrajjoshi/gloss.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/iamrajjoshi/gloss/issues\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n }\n}\n","import { readFile } from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { Context } from 'hono';\nimport { Hono } from 'hono';\nimport { globalReviewDir, packageVersion } from '../shared/paths';\nimport type { Comment, DiffPayload, ReviewEvent } from '../shared/types';\nimport { reviewStore } from './store';\n\nconst webRoot = fileURLToPath(new URL('../web', import.meta.url));\nconst eventStreamHeartbeatMs = 15_000;\n\nconst mimeTypes: Record<string, string> = {\n '.css': 'text/css; charset=utf-8',\n '.html': 'text/html; charset=utf-8',\n '.js': 'application/javascript; charset=utf-8',\n '.json': 'application/json; charset=utf-8',\n '.map': 'application/json; charset=utf-8',\n '.png': 'image/png',\n '.sh': 'text/x-shellscript; charset=utf-8',\n '.svg': 'image/svg+xml'\n};\n\nexport function createApp(origin: string): Hono {\n const app = new Hono();\n\n app.get('/api/health', async (c) => {\n const reviews = await reviewStore.list();\n return c.json({\n ok: true,\n version: packageVersion,\n activeReviews: reviews.filter((review) => review.status === 'pending').length\n });\n });\n\n app.get('/api/reviews', async (c) => c.json({ reviews: await reviewStore.list() }));\n\n app.post('/api/reviews', async (c) => {\n const diff = (await c.req.json()) as DiffPayload;\n const record = await reviewStore.create(diff);\n return c.json({ meta: record.meta, url: `${origin}/review/${record.meta.id}` }, 201);\n });\n\n app.get('/api/reviews/:id', async (c) => {\n const record = await reviewStore.get(c.req.param('id'));\n if (!record) {\n return c.json({ error: 'review not found' }, 404);\n }\n return c.json(record);\n });\n\n app.get('/api/reviews/:id/feedback', async (c) => {\n const feedback = await reviewStore.feedback(c.req.param('id'));\n if (!feedback) {\n return c.json({ error: 'feedback not found' }, 404);\n }\n return c.json(feedback);\n });\n\n app.get('/api/reviews/:id/events', async (c) => {\n const id = c.req.param('id');\n const record = await reviewStore.get(id);\n if (!record) {\n return c.json({ error: 'review not found' }, 404);\n }\n\n const encoder = new TextEncoder();\n let cleanup: (() => void) | null = null;\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n let closed = false;\n let heartbeat: ReturnType<typeof setInterval> | null = null;\n const write = (chunk: string) => {\n if (!closed) {\n controller.enqueue(encoder.encode(chunk));\n }\n };\n const close = () => {\n if (closed) {\n return;\n }\n closed = true;\n if (heartbeat) {\n clearInterval(heartbeat);\n }\n cleanup?.();\n };\n const send = (event: ReviewEvent) => {\n write(`data: ${JSON.stringify(event)}\\n\\n`);\n if (event.type === 'review.submitted' || event.type === 'review.cancelled') {\n close();\n controller.close();\n }\n };\n const unsubscribe = reviewStore.subscribe(id, send);\n heartbeat = setInterval(() => {\n write(`: keep-alive ${Date.now()}\\n\\n`);\n }, eventStreamHeartbeatMs);\n cleanup = () => {\n if (heartbeat) {\n clearInterval(heartbeat);\n }\n unsubscribe();\n };\n send({ type: 'review.opened', reviewId: id });\n if (\n (record.meta.status === 'submitted' || record.meta.status === 'resolved') &&\n record.feedback\n ) {\n send({\n type: 'review.submitted',\n reviewId: id,\n counts: {\n files: new Set(record.feedback.comments.map((comment) => comment.filePath)).size,\n comments: record.feedback.comments.length\n }\n });\n }\n },\n cancel() {\n cleanup?.();\n }\n });\n\n return new Response(stream, {\n headers: {\n 'cache-control': 'no-cache, no-transform',\n connection: 'keep-alive',\n 'content-type': 'text/event-stream',\n 'x-accel-buffering': 'no'\n }\n });\n });\n\n app.post('/api/reviews/:id/submit', async (c) => {\n const id = c.req.param('id');\n const existing = await reviewStore.get(id);\n if (!existing) {\n return c.json({ error: 'review not found' }, 404);\n }\n if (existing.meta.status !== 'pending') {\n return c.json({ error: `review is ${existing.meta.status} and cannot be submitted` }, 409);\n }\n const body = (await c.req.json()) as { comments: Comment[] };\n const { record, feedbackPath, markdownPath } = await reviewStore.submit(\n id,\n body.comments ?? []\n );\n return c.json({\n reviewId: id,\n url: `${origin}/review/${id}`,\n files: record.diff.files.length,\n comments: body.comments?.length ?? 0,\n artifactDir: record.meta.artifactDir,\n feedbackPath,\n markdownPath\n });\n });\n\n app.post('/api/reviews/:id/resolved', async (c) => {\n const id = c.req.param('id');\n const existing = await reviewStore.get(id);\n if (!existing) {\n return c.json({ error: 'review not found' }, 404);\n }\n if (existing.meta.status !== 'submitted' && existing.meta.status !== 'resolved') {\n return c.json({ error: `review is ${existing.meta.status} and cannot be resolved` }, 409);\n }\n if (!existing.feedback) {\n return c.json({ error: 'submitted feedback not found' }, 409);\n }\n const body = (await c.req.json().catch(() => ({}))) as { summary?: string };\n return c.json(await reviewStore.markResolved(id, body.summary));\n });\n\n app.post('/api/reviews/:id/comments/:commentId/resolved', async (c) => {\n const id = c.req.param('id');\n const commentId = c.req.param('commentId');\n const existing = await reviewStore.get(id);\n if (!existing) {\n return c.json({ error: 'review not found' }, 404);\n }\n if (existing.meta.status !== 'submitted' && existing.meta.status !== 'resolved') {\n return c.json({ error: `review is ${existing.meta.status} and cannot be resolved` }, 409);\n }\n if (!existing.feedback?.comments.some((comment) => comment.id === commentId)) {\n return c.json({ error: 'comment not found' }, 404);\n }\n const body = (await c.req.json().catch(() => ({}))) as { summary?: string };\n return c.json(await reviewStore.resolveComment(id, commentId, body.summary));\n });\n\n app.delete('/api/reviews/:id/comments/:commentId/resolved', async (c) => {\n const id = c.req.param('id');\n const commentId = c.req.param('commentId');\n const existing = await reviewStore.get(id);\n if (!existing) {\n return c.json({ error: 'review not found' }, 404);\n }\n if (existing.meta.status !== 'submitted' && existing.meta.status !== 'resolved') {\n return c.json({ error: `review is ${existing.meta.status} and cannot be resolved` }, 409);\n }\n if (!existing.feedback?.comments.some((comment) => comment.id === commentId)) {\n return c.json({ error: 'comment not found' }, 404);\n }\n return c.json(await reviewStore.reopenComment(id, commentId));\n });\n\n app.get('/logo.svg', serveRootFile('logo.svg', mimeTypes['.svg']));\n app.get('/logo-mark.svg', serveRootFile('logo-mark.svg', mimeTypes['.svg']));\n app.get('/og.png', serveRootFile('og.png', mimeTypes['.png']));\n app.get('/install.sh', serveRootFile('install.sh', mimeTypes['.sh']));\n app.get('/setup.md', serveRootFile('setup.md', 'text/markdown; charset=utf-8'));\n app.get('/prompt.md', serveRootFile('prompt.md', 'text/markdown; charset=utf-8'));\n app.get('/assets/*', serveAsset);\n app.get('/setup', serveIndex);\n app.get('/setup/', serveIndex);\n app.get('/review/:id', serveIndex);\n app.get('/', serveIndex);\n\n return app;\n}\n\nasync function serveAsset(c: Context) {\n const requestPath = new URL(c.req.url).pathname.replace(/^\\/assets\\//, '');\n const normalized = path.normalize(requestPath).replace(/^(\\.\\.(\\/|\\\\|$))+/, '');\n const assetPath = path.join(webRoot, 'assets', normalized);\n try {\n const body = await readFile(assetPath);\n return new Response(body, {\n headers: {\n 'content-type': mimeTypes[path.extname(assetPath)] ?? 'application/octet-stream'\n }\n });\n } catch {\n return new Response('Not found', { status: 404 });\n }\n}\n\nasync function serveIndex() {\n try {\n const body = await readFile(path.join(webRoot, 'index.html'));\n return new Response(body, {\n headers: { 'content-type': 'text/html; charset=utf-8' }\n });\n } catch {\n return new Response('Gloss web assets are missing. Run pnpm build.', { status: 500 });\n }\n}\n\nfunction serveRootFile(fileName: string, contentType: string) {\n return async () => {\n try {\n const body = await readFile(path.join(webRoot, fileName));\n return new Response(body, {\n headers: { 'content-type': contentType }\n });\n } catch {\n return new Response(`${fileName} is missing. Run pnpm build.`, { status: 404 });\n }\n };\n}\n\nexport function getReviewArtifactDir(_cwd: string, reviewId: string): string {\n return globalReviewDir(reviewId);\n}\n","import type { Dirent } from 'node:fs';\nimport { readdir, readFile, rm, writeFile } from 'node:fs/promises';\nimport { ulid } from 'ulid';\nimport { serializeFeedbackMarkdown } from '../shared/markdown';\nimport {\n ensureDir,\n globalReviewDiffFile,\n globalReviewDir,\n globalReviewFeedbackFile,\n globalReviewMarkdownFile,\n globalReviewMetaFile,\n globalReviewResolvedFile,\n globalReviewsDir\n} from '../shared/paths';\nimport type {\n Comment,\n DiffPayload,\n FeedbackBundle,\n ResolutionBundle,\n ResolvedComment,\n ResolveResult,\n ReviewEvent,\n ReviewMeta,\n ReviewRecord\n} from '../shared/types';\n\ntype Listener = (event: ReviewEvent) => void;\n\nexport class ReviewStore {\n private readonly reviews = new Map<string, ReviewRecord>();\n private readonly listeners = new Map<string, Set<Listener>>();\n\n async create(diff: DiffPayload): Promise<ReviewRecord> {\n const id = ulid();\n const createdAt = new Date().toISOString();\n const meta: ReviewMeta = {\n id,\n cwd: diff.cwd,\n base: diff.base,\n branch: diff.branch,\n status: 'pending',\n createdAt,\n artifactDir: globalReviewDir(id)\n };\n const record: ReviewRecord = { meta, diff };\n this.reviews.set(id, record);\n await this.persistInitial(record);\n this.emit({ type: 'review.opened', reviewId: id });\n return record;\n }\n\n async list(): Promise<ReviewMeta[]> {\n await this.loadAllReviews();\n return [...this.reviews.values()]\n .map((record) => record.meta)\n .sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n }\n\n async get(id: string): Promise<ReviewRecord | null> {\n return this.reviews.get(id) ?? (await this.loadKnownReview(id));\n }\n\n async submit(\n id: string,\n comments: Comment[]\n ): Promise<{ record: ReviewRecord; feedbackPath: string; markdownPath: string }> {\n const record = await this.get(id);\n if (!record) {\n throw new Error(`Review ${id} not found`);\n }\n if (record.meta.status !== 'pending') {\n throw new Error(`Review ${id} is ${record.meta.status} and cannot be submitted`);\n }\n const timestamp = new Date().toISOString();\n const feedback: FeedbackBundle = {\n version: 1,\n reviewId: id,\n timestamp,\n base: record.diff.base,\n branch: record.diff.branch,\n comments: [...comments].sort(\n (a, b) =>\n a.filePath.localeCompare(b.filePath) ||\n a.startLine - b.startLine ||\n a.endLine - b.endLine ||\n a.side.localeCompare(b.side)\n )\n };\n record.feedback = feedback;\n record.meta = { ...record.meta, status: 'submitted', submittedAt: timestamp };\n this.reviews.set(id, record);\n\n const artifactDir = globalReviewDir(id);\n const feedbackPath = globalReviewFeedbackFile(id);\n const markdownPath = globalReviewMarkdownFile(id);\n record.meta = {\n ...record.meta,\n artifactDir,\n feedbackPath,\n markdownPath\n };\n await ensureDir(artifactDir);\n await Promise.all([\n writeFile(globalReviewMetaFile(id), `${JSON.stringify(record.meta, null, 2)}\\n`),\n writeFile(feedbackPath, `${JSON.stringify(feedback, null, 2)}\\n`),\n writeFile(markdownPath, serializeFeedbackMarkdown(feedback))\n ]);\n\n this.emit({\n type: 'review.submitted',\n reviewId: id,\n counts: {\n files: new Set(feedback.comments.map((comment) => comment.filePath)).size,\n comments: feedback.comments.length\n }\n });\n return { record, feedbackPath, markdownPath };\n }\n\n async feedback(id: string): Promise<FeedbackBundle | null> {\n const record = await this.get(id);\n return record?.feedback ?? null;\n }\n\n async markResolved(id: string, summary?: string): Promise<ResolveResult> {\n const record = await this.get(id);\n if (!record) {\n throw new Error(`Review ${id} not found`);\n }\n this.assertResolvable(record, id);\n const resolvedAt = new Date().toISOString();\n const existingById = new Map(\n (record.resolution?.comments ?? []).map((comment) => [comment.commentId, comment])\n );\n const comments = this.sortResolvedComments(\n (record.feedback?.comments ?? []).map((comment) => ({\n ...existingById.get(comment.id),\n commentId: comment.id,\n status: 'resolved' as const,\n resolvedAt: existingById.get(comment.id)?.resolvedAt ?? resolvedAt\n })),\n record\n );\n const resolution: ResolutionBundle = {\n reviewId: id,\n status: 'resolved',\n summary: summary ?? record.resolution?.summary ?? null,\n resolvedAt,\n comments\n };\n record.meta = { ...record.meta, status: 'resolved', resolvedAt };\n return this.persistResolution(record, resolution);\n }\n\n async resolveComment(id: string, commentId: string, summary?: string): Promise<ResolveResult> {\n const record = await this.get(id);\n if (!record) {\n throw new Error(`Review ${id} not found`);\n }\n this.assertResolvable(record, id);\n this.assertCommentExists(record, commentId);\n\n const resolvedAt = new Date().toISOString();\n const previous = record.resolution?.comments.find((comment) => comment.commentId === commentId);\n const nextSummary = summary ?? previous?.summary;\n const nextComment: ResolvedComment = {\n commentId,\n status: 'resolved',\n ...(nextSummary ? { summary: nextSummary } : {}),\n resolvedAt\n };\n const comments = this.sortResolvedComments(\n [\n ...(record.resolution?.comments ?? []).filter((comment) => comment.commentId !== commentId),\n nextComment\n ],\n record\n );\n const counts = this.resolutionCounts(record, comments);\n const fullyResolved = counts.total === counts.resolved;\n const resolution: ResolutionBundle = {\n reviewId: id,\n status: fullyResolved ? 'resolved' : 'partial',\n summary: fullyResolved ? (record.resolution?.summary ?? null) : null,\n resolvedAt: fullyResolved ? resolvedAt : null,\n comments\n };\n record.meta = fullyResolved\n ? { ...record.meta, status: 'resolved', resolvedAt }\n : { ...record.meta, status: 'submitted', resolvedAt: undefined };\n return this.persistResolution(record, resolution);\n }\n\n async reopenComment(id: string, commentId: string): Promise<ResolveResult> {\n const record = await this.get(id);\n if (!record) {\n throw new Error(`Review ${id} not found`);\n }\n this.assertResolvable(record, id);\n this.assertCommentExists(record, commentId);\n\n const comments = this.sortResolvedComments(\n (record.resolution?.comments ?? []).filter((comment) => comment.commentId !== commentId),\n record\n );\n const counts = this.resolutionCounts(record, comments);\n const fullyResolved = counts.total > 0 && counts.total === counts.resolved;\n const resolvedAt = fullyResolved ? new Date().toISOString() : null;\n const resolution: ResolutionBundle = {\n reviewId: id,\n status: fullyResolved ? 'resolved' : 'partial',\n summary: fullyResolved ? (record.resolution?.summary ?? null) : null,\n resolvedAt,\n comments\n };\n record.meta = fullyResolved\n ? { ...record.meta, status: 'resolved', resolvedAt: resolvedAt ?? undefined }\n : { ...record.meta, status: 'submitted', resolvedAt: undefined };\n return this.persistResolution(record, resolution);\n }\n\n subscribe(reviewId: string, listener: Listener): () => void {\n const listeners = this.listeners.get(reviewId) ?? new Set<Listener>();\n listeners.add(listener);\n this.listeners.set(reviewId, listeners);\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0) {\n this.listeners.delete(reviewId);\n }\n };\n }\n\n private emit(event: ReviewEvent): void {\n for (const listener of this.listeners.get(event.reviewId) ?? []) {\n listener(event);\n }\n }\n\n private async persistInitial(record: ReviewRecord): Promise<void> {\n const dir = globalReviewDir(record.meta.id);\n await ensureDir(dir);\n await Promise.all([\n writeFile(globalReviewMetaFile(record.meta.id), `${JSON.stringify(record.meta, null, 2)}\\n`),\n writeFile(globalReviewDiffFile(record.meta.id), `${JSON.stringify(record.diff, null, 2)}\\n`)\n ]);\n }\n\n private async loadKnownReview(id: string): Promise<ReviewRecord | null> {\n const existing = this.reviews.get(id);\n if (existing) {\n return existing;\n }\n\n return this.loadReview(id);\n }\n\n private async loadAllReviews(): Promise<void> {\n let entries: Dirent[];\n try {\n entries = await readdir(globalReviewsDir(), { withFileTypes: true });\n } catch {\n return;\n }\n\n await Promise.all(\n entries.filter((entry) => entry.isDirectory()).map((entry) => this.loadReview(entry.name))\n );\n }\n\n private async loadReview(id: string): Promise<ReviewRecord | null> {\n try {\n const [metaRaw, diffRaw] = await Promise.all([\n readFile(globalReviewMetaFile(id), 'utf8'),\n readFile(globalReviewDiffFile(id), 'utf8')\n ]);\n const meta = JSON.parse(metaRaw) as ReviewMeta;\n const diff = JSON.parse(diffRaw) as DiffPayload;\n let feedback: FeedbackBundle | undefined;\n let resolution: ResolutionBundle | undefined;\n try {\n feedback = JSON.parse(\n await readFile(globalReviewFeedbackFile(id), 'utf8')\n ) as FeedbackBundle;\n } catch {\n feedback = undefined;\n }\n try {\n resolution = JSON.parse(\n await readFile(globalReviewResolvedFile(id), 'utf8')\n ) as ResolutionBundle;\n } catch {\n resolution = undefined;\n }\n\n const record: ReviewRecord = {\n meta: {\n ...meta,\n artifactDir: meta.artifactDir ?? globalReviewDir(id),\n feedbackPath: meta.feedbackPath ?? (feedback ? globalReviewFeedbackFile(id) : undefined),\n markdownPath: meta.markdownPath ?? (feedback ? globalReviewMarkdownFile(id) : undefined)\n },\n diff,\n feedback,\n resolution\n };\n this.reviews.set(id, record);\n return record;\n } catch {\n return null;\n }\n }\n\n private assertResolvable(\n record: ReviewRecord,\n id: string\n ): asserts record is ReviewRecord & {\n feedback: FeedbackBundle;\n } {\n if (record.meta.status !== 'submitted' && record.meta.status !== 'resolved') {\n throw new Error(`Review ${id} is ${record.meta.status} and cannot be resolved`);\n }\n if (!record.feedback) {\n throw new Error(`Review ${id} has no submitted feedback`);\n }\n }\n\n private assertCommentExists(\n record: ReviewRecord & { feedback: FeedbackBundle },\n commentId: string\n ): void {\n if (!record.feedback.comments.some((comment) => comment.id === commentId)) {\n throw new Error(`Comment ${commentId} not found`);\n }\n }\n\n private async persistResolution(\n record: ReviewRecord & { feedback: FeedbackBundle },\n resolution: ResolutionBundle\n ): Promise<ResolveResult> {\n record.resolution = resolution;\n this.reviews.set(record.meta.id, record);\n const resolvedPath = globalReviewResolvedFile(record.meta.id);\n await ensureDir(globalReviewDir(record.meta.id));\n await Promise.all([\n writeFile(resolvedPath, `${JSON.stringify(resolution, null, 2)}\\n`),\n writeFile(globalReviewMetaFile(record.meta.id), `${JSON.stringify(record.meta, null, 2)}\\n`)\n ]);\n return {\n ok: true,\n reviewId: record.meta.id,\n status: record.meta.status,\n resolutionStatus: resolution.status,\n comments: this.resolutionCounts(record, resolution.comments),\n path: resolvedPath,\n resolution\n };\n }\n\n private sortResolvedComments(\n comments: ResolvedComment[],\n record: ReviewRecord & { feedback: FeedbackBundle }\n ): ResolvedComment[] {\n const feedbackIndex = new Map(\n record.feedback.comments.map((comment, index) => [comment.id, index] as const)\n );\n return comments\n .filter((comment) => feedbackIndex.has(comment.commentId))\n .sort(\n (a, b) =>\n (feedbackIndex.get(a.commentId) ?? Number.MAX_SAFE_INTEGER) -\n (feedbackIndex.get(b.commentId) ?? Number.MAX_SAFE_INTEGER)\n );\n }\n\n private resolutionCounts(\n record: ReviewRecord & { feedback: FeedbackBundle },\n comments: ResolvedComment[]\n ): { total: number; resolved: number; open: number } {\n const total = record.feedback.comments.length;\n const resolvedIds = new Set(comments.map((comment) => comment.commentId));\n const resolved = record.feedback.comments.filter((comment) =>\n resolvedIds.has(comment.id)\n ).length;\n return {\n total,\n resolved,\n open: total - resolved\n };\n }\n}\n\nexport const reviewStore = new ReviewStore();\n\nexport async function removeReviewArtifacts(_cwd: string, id: string): Promise<void> {\n await rm(globalReviewDir(id), { force: true, recursive: true });\n}\n","import type { Comment, FeedbackBundle } from './types';\n\nfunction formatLineRange(comment: Comment): string {\n const prefix = comment.side;\n if (comment.startLine === comment.endLine) {\n return `${prefix}${comment.startLine}`;\n }\n return `${prefix}${comment.startLine}-${prefix}${comment.endLine}`;\n}\n\nfunction fenceFor(snippet: string): string {\n let fence = '```';\n while (snippet.includes(fence)) {\n fence += '`';\n }\n return fence;\n}\n\nfunction languageForPath(filePath: string): string {\n const ext = filePath.split('.').pop()?.toLowerCase();\n const map: Record<string, string> = {\n cjs: 'js',\n css: 'css',\n go: 'go',\n html: 'html',\n js: 'js',\n json: 'json',\n jsx: 'jsx',\n md: 'markdown',\n mjs: 'js',\n py: 'python',\n rb: 'ruby',\n rs: 'rust',\n sh: 'bash',\n swift: 'swift',\n ts: 'ts',\n tsx: 'tsx',\n yaml: 'yaml',\n yml: 'yaml'\n };\n return ext ? (map[ext] ?? ext) : '';\n}\n\nfunction languageForSnippet(filePath: string, snippet: string): string {\n const lines = snippet.split('\\n').filter((line) => line.length > 0);\n const looksLikeUnifiedDiff =\n lines.length > 0 &&\n lines.some((line) => line.startsWith('+') || line.startsWith('-')) &&\n lines.every((line) => line.startsWith('+') || line.startsWith('-') || line.startsWith(' '));\n return looksLikeUnifiedDiff ? 'diff' : languageForPath(filePath);\n}\n\nfunction byFileThenLine(a: Comment, b: Comment): number {\n return (\n a.filePath.localeCompare(b.filePath) ||\n a.startLine - b.startLine ||\n a.endLine - b.endLine ||\n a.side.localeCompare(b.side)\n );\n}\n\nexport function serializeFeedbackMarkdown(bundle: FeedbackBundle): string {\n const comments = [...bundle.comments].sort(byFileThenLine);\n const files = [...new Set(comments.map((comment) => comment.filePath))];\n const lines: string[] = [\n `# Gloss feedback - ${bundle.timestamp}`,\n `Review: ${bundle.reviewId}`,\n `Base: ${bundle.base.ref} (${bundle.base.sha.slice(0, 7)}) Branch: ${bundle.branch ?? '(detached)'}`,\n `Files: ${files.length} Comments: ${comments.length}`,\n ''\n ];\n\n for (const filePath of files) {\n lines.push(`## ${filePath}`, '');\n for (const comment of comments.filter((item) => item.filePath === filePath)) {\n const snippet = comment.originalSnippet.trimEnd();\n const firstSnippetLine = snippet.split('\\n').find((line) => line.trim().length > 0);\n const heading =\n comment.startLine === comment.endLine && firstSnippetLine\n ? `### ${formatLineRange(comment)} - \\`${firstSnippetLine.trim().slice(0, 80)}\\``\n : `### ${formatLineRange(comment)}`;\n lines.push(heading, comment.body.trim(), '');\n if (snippet) {\n const fence = fenceFor(snippet);\n lines.push(`${fence}${languageForSnippet(comment.filePath, snippet)}`, snippet, fence, '');\n }\n }\n }\n\n return `${lines.join('\\n').trimEnd()}\\n`;\n}\n"],"mappings":"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","names":["readFile","path","fileURLToPath","readFile","rm","writeFile","writeFile","readFile","fileURLToPath","origin","path","readFile"]}