getgloss 0.4.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.
package/dist/cli/index.js CHANGED
@@ -12,7 +12,7 @@ import path from "path";
12
12
  // package.json
13
13
  var package_default = {
14
14
  name: "getgloss",
15
- version: "0.4.0",
15
+ version: "0.4.1",
16
16
  description: "Local browser-based diff review for coding-agent loops.",
17
17
  type: "module",
18
18
  packageManager: "pnpm@10.33.2",
@@ -506,40 +506,58 @@ var ServerClient = class {
506
506
  return this.post(`/api/reviews/${reviewId}/submit`, { comments });
507
507
  }
508
508
  async watchReview(reviewId, timeoutSeconds) {
509
- const controller = new AbortController();
510
- const timeout = timeoutSeconds && timeoutSeconds > 0 ? setTimeout(() => controller.abort(), timeoutSeconds * 1e3) : null;
511
- try {
512
- const response = await fetch(`${this.baseUrl}/api/reviews/${reviewId}/events`, {
513
- signal: controller.signal
514
- });
515
- if (!response.ok || !response.body) {
516
- throw new Error(`watch failed: ${response.status} ${await response.text()}`);
509
+ const deadline = timeoutSeconds && timeoutSeconds > 0 ? Date.now() + timeoutSeconds * 1e3 : null;
510
+ while (true) {
511
+ const remainingMs = deadline ? deadline - Date.now() : null;
512
+ if (remainingMs !== null && remainingMs <= 0) {
513
+ throw new Error(`watch timed out after ${timeoutSeconds} seconds`);
517
514
  }
518
- const reader = response.body.getReader();
519
- const decoder = new TextDecoder();
520
- let buffer = "";
521
- while (true) {
522
- const { value, done } = await reader.read();
523
- if (done) {
524
- throw new Error("watch stream ended before completion");
515
+ const controller = new AbortController();
516
+ const timeout = remainingMs ? setTimeout(() => controller.abort(), remainingMs) : null;
517
+ try {
518
+ return await this.readReviewEvents(reviewId, controller.signal);
519
+ } catch (error) {
520
+ if (isAbortError(error)) {
521
+ throw new Error(`watch timed out after ${timeoutSeconds} seconds`);
525
522
  }
526
- buffer += decoder.decode(value, { stream: true });
527
- const events = buffer.split("\n\n");
528
- buffer = events.pop() ?? "";
529
- for (const eventChunk of events) {
530
- const dataLine = eventChunk.split("\n").find((line) => line.startsWith("data:"));
531
- if (!dataLine) {
532
- continue;
533
- }
534
- const event = JSON.parse(dataLine.slice(5).trim());
535
- if (event.type === "review.submitted" || event.type === "review.cancelled") {
536
- return event;
537
- }
523
+ if (!isPrematureWatchEnd(error)) {
524
+ throw error;
525
+ }
526
+ await sleep(500);
527
+ } finally {
528
+ if (timeout) {
529
+ clearTimeout(timeout);
538
530
  }
539
531
  }
540
- } finally {
541
- if (timeout) {
542
- clearTimeout(timeout);
532
+ }
533
+ }
534
+ async readReviewEvents(reviewId, signal) {
535
+ const response = await fetch(`${this.baseUrl}/api/reviews/${reviewId}/events`, {
536
+ signal
537
+ });
538
+ if (!response.ok || !response.body) {
539
+ throw new Error(`watch failed: ${response.status} ${await response.text()}`);
540
+ }
541
+ const reader = response.body.getReader();
542
+ const decoder = new TextDecoder();
543
+ let buffer = "";
544
+ while (true) {
545
+ const { value, done } = await reader.read();
546
+ if (done) {
547
+ throw new Error("watch stream ended before completion");
548
+ }
549
+ buffer += decoder.decode(value, { stream: true });
550
+ const events = buffer.split("\n\n");
551
+ buffer = events.pop() ?? "";
552
+ for (const eventChunk of events) {
553
+ const dataLine = eventChunk.split("\n").find((line) => line.startsWith("data:"));
554
+ if (!dataLine) {
555
+ continue;
556
+ }
557
+ const event = JSON.parse(dataLine.slice(5).trim());
558
+ if (event.type === "review.submitted" || event.type === "review.cancelled") {
559
+ return event;
560
+ }
543
561
  }
544
562
  }
545
563
  }
@@ -566,6 +584,15 @@ async function parseResponse(response) {
566
584
  }
567
585
  return await response.json();
568
586
  }
587
+ function isPrematureWatchEnd(error) {
588
+ return error instanceof Error && error.message === "watch stream ended before completion";
589
+ }
590
+ function isAbortError(error) {
591
+ return typeof error === "object" && error !== null && "name" in error && error.name === "AbortError";
592
+ }
593
+ async function sleep(milliseconds) {
594
+ await new Promise((resolve) => setTimeout(resolve, milliseconds));
595
+ }
569
596
 
570
597
  // src/cli/lifecycle.ts
571
598
  async function readServerInfo() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/index.ts","../../src/shared/paths.ts","../../package.json","../../src/cli/git.ts","../../src/cli/diff-parser.ts","../../src/cli/lifecycle.ts","../../src/cli/server-client.ts","../../src/server/store.ts","../../src/shared/markdown.ts","../../src/cli/status.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport openBrowser from 'open';\nimport {\n globalReviewDir,\n globalReviewFeedbackFile,\n globalReviewMarkdownFile,\n packageVersion\n} from '../shared/paths';\nimport { assertGitAvailable, captureDiff, getRepoRoot } from './git';\nimport {\n ensureServer,\n isServerResponsive,\n readServerInfo,\n serverUrl,\n startServer,\n stopServer\n} from './lifecycle';\nimport { ServerClient } from './server-client';\nimport { listReviewsForStatus } from './status';\n\ninterface GlobalOptions {\n json?: boolean;\n noColor?: boolean;\n}\n\nfunction printJson(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction printPlain(value: string): void {\n process.stdout.write(`${value}\\n`);\n}\n\nconst program = new Command();\n\nprogram\n .name('gloss')\n .description('Local browser-based diff review for coding-agent loops.')\n .version(packageVersion)\n .option('--json', 'print JSON for supported commands')\n .option('--no-color', 'disable color output');\n\nprogram\n .command('open')\n .description('Capture local changes and open them for review')\n .option('--base <ref>', 'explicit base git ref')\n .option('--print-url', 'print review URL')\n .option('--no-open', 'do not open a browser')\n .option('--no-watch', 'return immediately after registering the review')\n .option('--timeout <seconds>', 'watch timeout in seconds', Number)\n .action(\n async (options: {\n base?: string;\n printUrl?: boolean;\n open?: boolean;\n watch?: boolean;\n timeout?: number;\n }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await ensureServer();\n const client = new ServerClient(serverUrl(info));\n const diff = await captureDiff(options.base);\n const { meta, url } = await client.createReview(diff);\n\n if (options.printUrl) {\n printPlain(url);\n }\n if (options.open !== false) {\n await openBrowser(url);\n }\n\n if (options.watch === false) {\n const result = {\n reviewId: meta.id,\n url,\n files: diff.files.length,\n scope: diff.scope.mode,\n artifactDir: meta.artifactDir\n };\n globals.json ? printJson(result) : printPlain(`Review ${meta.id}: ${url}`);\n return;\n }\n\n const event = await client.watchReview(meta.id, options.timeout);\n if (event.type === 'review.cancelled') {\n process.exitCode = 2;\n globals.json ? printJson(event) : printPlain(`Review ${meta.id} cancelled`);\n return;\n }\n if (event.type !== 'review.submitted') {\n throw new Error(`Unexpected review event ${event.type}`);\n }\n\n const feedback = await client.getFeedback(meta.id);\n const result = {\n reviewId: meta.id,\n url,\n files: event.counts.files,\n comments: event.counts.comments,\n feedbackPath: globalReviewFeedbackFile(meta.id),\n markdownPath: globalReviewMarkdownFile(meta.id),\n artifactDir: globalReviewDir(meta.id),\n feedback\n };\n globals.json\n ? printJson(result)\n : printPlain(`Review ${meta.id} submitted with ${event.counts.comments} comments`);\n }\n );\n\nprogram\n .command('watch')\n .argument('<reviewId>', 'review id')\n .description('Wait for review.submitted for an existing review')\n .option('--timeout <seconds>', 'watch timeout in seconds', Number)\n .action(async (reviewId: string, options: { timeout?: number }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await ensureServer();\n const client = new ServerClient(serverUrl(info));\n const event = await client.watchReview(reviewId, options.timeout);\n globals.json ? printJson(event) : printPlain(`${event.type} ${event.reviewId}`);\n });\n\nprogram\n .command('start')\n .description('Start or reuse the background server')\n .option('--port <port>', 'port to bind', Number)\n .action(async (options: { port?: number }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await startServer({ port: options.port });\n globals.json\n ? printJson(info)\n : printPlain(`Gloss server running at ${serverUrl(info)} (pid ${info.pid})`);\n });\n\nprogram\n .command('status')\n .description('Show server and active reviews')\n .action(async () => {\n const globals = program.opts<GlobalOptions>();\n const info = await readServerInfo();\n const responsive = info ? await isServerResponsive(info) : false;\n const reviews = await listReviewsForStatus({ responsive, server: info });\n const status = { running: responsive, server: info, reviews };\n globals.json\n ? printJson(status)\n : printPlain(\n responsive && info\n ? `Gloss server running at ${serverUrl(info)} with ${reviews.length} active review(s)`\n : 'Gloss server is not running'\n );\n });\n\nprogram\n .command('stop')\n .description('Stop the managed background server')\n .option('--all', 'reserved for future multi-server cleanup')\n .action(async () => {\n const globals = program.opts<GlobalOptions>();\n const result = await stopServer();\n globals.json\n ? printJson(result)\n : printPlain(result.stopped ? 'Gloss server stopped' : 'Gloss server was not running');\n });\n\nprogram\n .command('resolve')\n .argument('<reviewId>', 'review id')\n .description('Mark a submitted review or one feedback comment as resolved')\n .option('--comment <commentId>', 'resolve one submitted feedback comment')\n .option('--summary <text>', 'brief summary of the fixes applied')\n .action(async (reviewId: string, options: { comment?: string; summary?: string }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await ensureServer();\n const client = new ServerClient(serverUrl(info));\n const result = options.comment\n ? await client.resolveComment(reviewId, options.comment, options.summary)\n : await client.markResolved(reviewId, options.summary);\n if (globals.json) {\n printJson({\n commentId: options.comment ?? null,\n summary: options.summary ?? null,\n ...result\n });\n return;\n }\n printPlain(\n options.comment\n ? `Comment ${options.comment} resolved in review ${reviewId}`\n : `Review ${reviewId} resolved`\n );\n });\n\nprogram\n .command('doctor')\n .description('Diagnose setup and validate git/state')\n .action(async () => {\n const globals = program.opts<GlobalOptions>();\n const checks: Array<{ name: string; ok: boolean; detail?: string }> = [];\n try {\n await assertGitAvailable();\n checks.push({ name: 'git', ok: true });\n } catch (error) {\n checks.push({\n name: 'git',\n ok: false,\n detail: error instanceof Error ? error.message : String(error)\n });\n }\n try {\n const root = await getRepoRoot();\n checks.push({ name: 'repo', ok: true, detail: root });\n } catch (error) {\n checks.push({\n name: 'repo',\n ok: false,\n detail: error instanceof Error ? error.message : String(error)\n });\n }\n const info = await readServerInfo();\n checks.push({\n name: 'server',\n ok: info ? await isServerResponsive(info) : false,\n detail: info ? serverUrl(info) : 'not started'\n });\n checks.push({\n name: '@pierre/diffs license',\n ok: true,\n detail: 'apache-2.0 dependency present'\n });\n\n if (globals.json) {\n printJson({ checks });\n } else {\n for (const check of checks) {\n printPlain(\n `${check.ok ? 'ok' : 'fail'} ${check.name}${check.detail ? ` - ${check.detail}` : ''}`\n );\n }\n }\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\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.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 \"@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 { execa } from 'execa';\nimport type {\n DiffFallbackReason,\n DiffFile,\n DiffPayload,\n DiffScopeMode,\n DiffStats\n} from '../shared/types';\nimport { parseUnifiedDiff } from './diff-parser';\n\nconst DIFF_ARGS = ['diff', '--no-color', '--find-renames', '--find-copies'];\n\nasync function git(args: string[], cwd = process.cwd()): Promise<string> {\n const result = await execa('git', args, { cwd });\n return result.stdout.trimEnd();\n}\n\nasync function gitMaybe(args: string[], cwd: string): Promise<string | null> {\n const result = await execa('git', args, { cwd, reject: false });\n return result.exitCode === 0 ? result.stdout.trimEnd() : null;\n}\n\nasync function gitLenient(args: string[], cwd: string): Promise<string> {\n const result = await execa('git', args, { cwd, reject: false });\n if (result.exitCode !== 0 && result.stdout.length === 0) {\n throw new Error(result.stderr || `git ${args.join(' ')} failed`);\n }\n return result.stdout.trimEnd();\n}\n\nexport async function getRepoRoot(cwd = process.cwd()): Promise<string> {\n return git(['rev-parse', '--show-toplevel'], cwd);\n}\n\ninterface ResolvedBranchBase {\n sourceRef: string;\n mergeBaseSha: string;\n}\n\ninterface PayloadOptions {\n repoRoot: string;\n branch: string | null;\n rawDiff: string;\n base: { ref: string; sha: string };\n mode: DiffScopeMode;\n requestedBase: string | null;\n comparison: { ref: string; sha: string | null };\n fallbackReason: DiffFallbackReason;\n}\n\nfunction summarize(files: DiffFile[]): DiffStats {\n return files.reduce(\n (stats, file) => ({\n files: stats.files + 1,\n additions: stats.additions + file.additions,\n deletions: stats.deletions + file.deletions\n }),\n { files: 0, additions: 0, deletions: 0 }\n );\n}\n\nfunction buildPayload({\n repoRoot,\n branch,\n rawDiff,\n base,\n mode,\n requestedBase,\n comparison,\n fallbackReason\n}: PayloadOptions): DiffPayload {\n const files = parseUnifiedDiff(rawDiff);\n return {\n base,\n branch,\n cwd: repoRoot,\n scope: {\n mode,\n requestedBase,\n base,\n comparison,\n fallbackReason\n },\n stats: summarize(files),\n rawDiff,\n files,\n capturedAt: new Date().toISOString()\n };\n}\n\nasync function currentBranch(repoRoot: string): Promise<string | null> {\n const branch = await gitMaybe(['rev-parse', '--abbrev-ref', 'HEAD'], repoRoot);\n return branch && branch !== 'HEAD' ? branch : null;\n}\n\nasync function captureUntrackedDiff(repoRoot: string): Promise<string[]> {\n const untrackedFilesRaw = await git(\n ['ls-files', '--others', '--exclude-standard', '-z'],\n repoRoot\n );\n const untrackedFiles = untrackedFilesRaw.split('\\0').filter(Boolean);\n return Promise.all(\n untrackedFiles.map((filePath) =>\n gitLenient(['diff', '--no-color', '--no-index', '--', '/dev/null', filePath], repoRoot)\n )\n );\n}\n\nasync function captureWorkingDiff(baseRef: string, repoRoot: string): Promise<string> {\n const [trackedDiff, untrackedDiffs] = await Promise.all([\n git([...DIFF_ARGS, baseRef, '--'], repoRoot),\n captureUntrackedDiff(repoRoot)\n ]);\n return [trackedDiff, ...untrackedDiffs].filter(Boolean).join('\\n');\n}\n\nasync function resolveCommit(ref: string, repoRoot: string): Promise<string | null> {\n return gitMaybe(['rev-parse', '--verify', `${ref}^{commit}`], repoRoot);\n}\n\nasync function resolveBranchBase(repoRoot: string): Promise<ResolvedBranchBase | null> {\n const candidates: string[] = [];\n const upstream = await gitMaybe(\n ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'],\n repoRoot\n );\n const originHead = await gitMaybe(\n ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'],\n repoRoot\n );\n\n for (const ref of [upstream, originHead, 'origin/main', 'origin/master']) {\n if (ref && !candidates.includes(ref)) {\n candidates.push(ref);\n }\n }\n\n for (const sourceRef of candidates) {\n const [sourceSha, mergeBaseSha] = await Promise.all([\n resolveCommit(sourceRef, repoRoot),\n gitMaybe(['merge-base', 'HEAD', sourceRef], repoRoot)\n ]);\n if (sourceSha && mergeBaseSha) {\n return { sourceRef, mergeBaseSha };\n }\n }\n\n return null;\n}\n\nexport async function captureDiff(baseRef?: string, cwd = process.cwd()): Promise<DiffPayload> {\n const repoRoot = await getRepoRoot(cwd);\n const [headSha, branch] = await Promise.all([\n git(['rev-parse', 'HEAD'], repoRoot),\n currentBranch(repoRoot)\n ]);\n\n if (baseRef) {\n const [baseSha, rawDiff] = await Promise.all([\n git(['rev-parse', baseRef], repoRoot),\n captureWorkingDiff(baseRef, repoRoot)\n ]);\n return buildPayload({\n repoRoot,\n branch,\n rawDiff,\n base: { ref: baseRef, sha: baseSha },\n mode: 'explicit',\n requestedBase: baseRef,\n comparison: { ref: 'working tree', sha: null },\n fallbackReason: null\n });\n }\n\n const workingDiff = await captureWorkingDiff('HEAD', repoRoot);\n if (workingDiff.trim().length > 0) {\n return buildPayload({\n repoRoot,\n branch,\n rawDiff: workingDiff,\n base: { ref: 'HEAD', sha: headSha },\n mode: 'working',\n requestedBase: null,\n comparison: { ref: 'working tree', sha: null },\n fallbackReason: null\n });\n }\n\n const branchBase = await resolveBranchBase(repoRoot);\n if (!branchBase) {\n return buildPayload({\n repoRoot,\n branch,\n rawDiff: '',\n base: { ref: 'HEAD', sha: headSha },\n mode: 'working',\n requestedBase: null,\n comparison: { ref: 'working tree', sha: null },\n fallbackReason: 'missing-branch-base'\n });\n }\n\n const rawDiff = await git([...DIFF_ARGS, branchBase.mergeBaseSha, 'HEAD', '--'], repoRoot);\n return buildPayload({\n repoRoot,\n branch,\n rawDiff,\n base: { ref: `merge-base(${branchBase.sourceRef})`, sha: branchBase.mergeBaseSha },\n mode: 'branch',\n requestedBase: null,\n comparison: { ref: 'HEAD', sha: headSha },\n fallbackReason: 'working-tree-clean'\n });\n}\n\nexport async function assertGitAvailable(): Promise<void> {\n await execa('git', ['--version']);\n}\n","import path from 'node:path';\nimport type { DiffFile, DiffHunk, DiffLine } from '../shared/types';\n\nconst hunkHeaderPattern = /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/;\n\nfunction stripGitPath(input: string): string {\n return input.replace(/^[ab]\\//, '');\n}\n\nfunction languageForPath(filePath: string): string | null {\n const ext = path.extname(filePath).slice(1).toLowerCase();\n if (!ext) {\n return null;\n }\n const map: Record<string, string> = {\n cjs: 'js',\n mjs: 'js',\n js: 'js',\n jsx: 'jsx',\n ts: 'ts',\n tsx: 'tsx',\n py: 'python',\n rb: 'ruby',\n sh: 'bash',\n md: 'markdown',\n yml: 'yaml',\n yaml: 'yaml'\n };\n return map[ext] ?? ext;\n}\n\nfunction emptyFile(): DiffFile {\n return {\n path: '',\n oldPath: null,\n additions: 0,\n deletions: 0,\n isBinary: false,\n isDeleted: false,\n isNew: false,\n isRenamed: false,\n language: null,\n hunks: []\n };\n}\n\nexport function parseUnifiedDiff(diffText: string): DiffFile[] {\n const files: DiffFile[] = [];\n let current: DiffFile | null = null;\n let currentHunk: DiffHunk | null = null;\n let oldCursor = 0;\n let newCursor = 0;\n\n const finalizeFile = () => {\n if (current?.path) {\n current.language = languageForPath(current.path);\n files.push(current);\n }\n };\n\n for (const line of diffText.split('\\n')) {\n if (line.startsWith('diff --git ')) {\n finalizeFile();\n current = emptyFile();\n currentHunk = null;\n oldCursor = 0;\n newCursor = 0;\n const match = /^diff --git a\\/(.+) b\\/(.+)$/.exec(line);\n if (match) {\n current.oldPath = match[1];\n current.path = match[2];\n }\n continue;\n }\n\n if (!current) {\n continue;\n }\n\n if (line.startsWith('new file mode')) {\n current.isNew = true;\n continue;\n }\n\n if (line.startsWith('deleted file mode')) {\n current.isDeleted = true;\n continue;\n }\n\n if (line.startsWith('rename from ')) {\n current.oldPath = line.slice('rename from '.length);\n current.isRenamed = true;\n continue;\n }\n\n if (line.startsWith('rename to ')) {\n current.path = line.slice('rename to '.length);\n current.isRenamed = true;\n continue;\n }\n\n if (line.startsWith('Binary files ') || line.startsWith('GIT binary patch')) {\n current.isBinary = true;\n continue;\n }\n\n if (line.startsWith('--- ')) {\n const oldPath = line.slice(4).trim();\n current.oldPath = oldPath === '/dev/null' ? null : stripGitPath(oldPath);\n continue;\n }\n\n if (line.startsWith('+++ ')) {\n const newPath = line.slice(4).trim();\n current.path =\n newPath === '/dev/null' ? (current.oldPath ?? current.path) : stripGitPath(newPath);\n continue;\n }\n\n const hunkMatch = hunkHeaderPattern.exec(line);\n if (hunkMatch) {\n const oldStart = Number(hunkMatch[1]);\n const oldLines = Number(hunkMatch[2] ?? '1');\n const newStart = Number(hunkMatch[3]);\n const newLines = Number(hunkMatch[4] ?? '1');\n currentHunk = {\n oldStart,\n oldLines,\n newStart,\n newLines,\n header: hunkMatch[5]?.trim() ?? '',\n lines: []\n };\n current.hunks.push(currentHunk);\n oldCursor = oldStart;\n newCursor = newStart;\n continue;\n }\n\n if (!currentHunk) {\n continue;\n }\n\n const marker = line[0];\n const content = line.slice(1);\n let diffLine: DiffLine | null = null;\n\n if (marker === '+') {\n diffLine = { type: 'add', oldLine: null, newLine: newCursor, content };\n current.additions += 1;\n newCursor += 1;\n } else if (marker === '-') {\n diffLine = { type: 'delete', oldLine: oldCursor, newLine: null, content };\n current.deletions += 1;\n oldCursor += 1;\n } else if (marker === ' ') {\n diffLine = { type: 'context', oldLine: oldCursor, newLine: newCursor, content };\n oldCursor += 1;\n newCursor += 1;\n } else if (line.startsWith('\\\')) {\n continue;\n }\n\n if (diffLine) {\n currentHunk.lines.push(diffLine);\n }\n }\n\n finalizeFile();\n return files;\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 type {\n Comment,\n DiffPayload,\n FeedbackBundle,\n OpenResult,\n ResolveResult,\n ReviewEvent,\n ReviewMeta,\n ReviewRecord\n} from '../shared/types';\n\nexport class ServerClient {\n constructor(private readonly baseUrl: string) {}\n\n async health(): Promise<{ ok: boolean; version: string; activeReviews: number }> {\n return this.get('/api/health');\n }\n\n async createReview(diff: DiffPayload): Promise<{ meta: ReviewMeta; url: string }> {\n return this.post('/api/reviews', diff);\n }\n\n async getReview(reviewId: string): Promise<ReviewRecord> {\n return this.get(`/api/reviews/${reviewId}`);\n }\n\n async listReviews(): Promise<{ reviews: ReviewMeta[] }> {\n return this.get('/api/reviews');\n }\n\n async getFeedback(reviewId: string): Promise<FeedbackBundle> {\n return this.get(`/api/reviews/${reviewId}/feedback`);\n }\n\n async markResolved(reviewId: string, summary?: string): Promise<ResolveResult> {\n return this.post(`/api/reviews/${reviewId}/resolved`, { summary });\n }\n\n async resolveComment(\n reviewId: string,\n commentId: string,\n summary?: string\n ): Promise<ResolveResult> {\n return this.post(`/api/reviews/${reviewId}/comments/${commentId}/resolved`, { summary });\n }\n\n async reopenComment(reviewId: string, commentId: string): Promise<ResolveResult> {\n return this.delete(`/api/reviews/${reviewId}/comments/${commentId}/resolved`);\n }\n\n async submitReview(reviewId: string, comments: Comment[]): Promise<OpenResult> {\n return this.post(`/api/reviews/${reviewId}/submit`, { comments });\n }\n\n async watchReview(reviewId: string, timeoutSeconds?: number): Promise<ReviewEvent> {\n const controller = new AbortController();\n const timeout =\n timeoutSeconds && timeoutSeconds > 0\n ? setTimeout(() => controller.abort(), timeoutSeconds * 1000)\n : null;\n\n try {\n const response = await fetch(`${this.baseUrl}/api/reviews/${reviewId}/events`, {\n signal: controller.signal\n });\n if (!response.ok || !response.body) {\n throw new Error(`watch failed: ${response.status} ${await response.text()}`);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n throw new Error('watch stream ended before completion');\n }\n buffer += decoder.decode(value, { stream: true });\n const events = buffer.split('\\n\\n');\n buffer = events.pop() ?? '';\n for (const eventChunk of events) {\n const dataLine = eventChunk.split('\\n').find((line) => line.startsWith('data:'));\n if (!dataLine) {\n continue;\n }\n const event = JSON.parse(dataLine.slice(5).trim()) as ReviewEvent;\n if (event.type === 'review.submitted' || event.type === 'review.cancelled') {\n return event;\n }\n }\n }\n } finally {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n }\n\n private async get<T>(path: string): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`);\n return parseResponse<T>(response);\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body)\n });\n return parseResponse<T>(response);\n }\n\n private async delete<T>(path: string): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, { method: 'DELETE' });\n return parseResponse<T>(response);\n }\n}\n\nasync function parseResponse<T>(response: Response): Promise<T> {\n if (!response.ok) {\n throw new Error(`${response.status} ${response.statusText}: ${await response.text()}`);\n }\n return (await response.json()) as T;\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","import { ReviewStore } from '../server/store';\nimport type { ReviewMeta, ServerInfo } from '../shared/types';\nimport { serverUrl } from './lifecycle';\nimport { ServerClient } from './server-client';\n\nexport async function listReviewsForStatus({\n responsive,\n server\n}: {\n responsive: boolean;\n server: ServerInfo | null;\n}): Promise<ReviewMeta[]> {\n if (server && responsive) {\n try {\n return (await new ServerClient(serverUrl(server)).listReviews()).reviews;\n } catch {\n // Fall through to durable state if the daemon disappears between health and list.\n }\n }\n\n return new ReviewStore().list();\n}\n"],"mappings":"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","names":["path","rawDiff","path","readFile","rm","writeFile","languageForPath","writeFile","readFile","result"]}
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/shared/paths.ts","../../package.json","../../src/cli/git.ts","../../src/cli/diff-parser.ts","../../src/cli/lifecycle.ts","../../src/cli/server-client.ts","../../src/server/store.ts","../../src/shared/markdown.ts","../../src/cli/status.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport openBrowser from 'open';\nimport {\n globalReviewDir,\n globalReviewFeedbackFile,\n globalReviewMarkdownFile,\n packageVersion\n} from '../shared/paths';\nimport { assertGitAvailable, captureDiff, getRepoRoot } from './git';\nimport {\n ensureServer,\n isServerResponsive,\n readServerInfo,\n serverUrl,\n startServer,\n stopServer\n} from './lifecycle';\nimport { ServerClient } from './server-client';\nimport { listReviewsForStatus } from './status';\n\ninterface GlobalOptions {\n json?: boolean;\n noColor?: boolean;\n}\n\nfunction printJson(value: unknown): void {\n process.stdout.write(`${JSON.stringify(value, null, 2)}\\n`);\n}\n\nfunction printPlain(value: string): void {\n process.stdout.write(`${value}\\n`);\n}\n\nconst program = new Command();\n\nprogram\n .name('gloss')\n .description('Local browser-based diff review for coding-agent loops.')\n .version(packageVersion)\n .option('--json', 'print JSON for supported commands')\n .option('--no-color', 'disable color output');\n\nprogram\n .command('open')\n .description('Capture local changes and open them for review')\n .option('--base <ref>', 'explicit base git ref')\n .option('--print-url', 'print review URL')\n .option('--no-open', 'do not open a browser')\n .option('--no-watch', 'return immediately after registering the review')\n .option('--timeout <seconds>', 'watch timeout in seconds', Number)\n .action(\n async (options: {\n base?: string;\n printUrl?: boolean;\n open?: boolean;\n watch?: boolean;\n timeout?: number;\n }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await ensureServer();\n const client = new ServerClient(serverUrl(info));\n const diff = await captureDiff(options.base);\n const { meta, url } = await client.createReview(diff);\n\n if (options.printUrl) {\n printPlain(url);\n }\n if (options.open !== false) {\n await openBrowser(url);\n }\n\n if (options.watch === false) {\n const result = {\n reviewId: meta.id,\n url,\n files: diff.files.length,\n scope: diff.scope.mode,\n artifactDir: meta.artifactDir\n };\n globals.json ? printJson(result) : printPlain(`Review ${meta.id}: ${url}`);\n return;\n }\n\n const event = await client.watchReview(meta.id, options.timeout);\n if (event.type === 'review.cancelled') {\n process.exitCode = 2;\n globals.json ? printJson(event) : printPlain(`Review ${meta.id} cancelled`);\n return;\n }\n if (event.type !== 'review.submitted') {\n throw new Error(`Unexpected review event ${event.type}`);\n }\n\n const feedback = await client.getFeedback(meta.id);\n const result = {\n reviewId: meta.id,\n url,\n files: event.counts.files,\n comments: event.counts.comments,\n feedbackPath: globalReviewFeedbackFile(meta.id),\n markdownPath: globalReviewMarkdownFile(meta.id),\n artifactDir: globalReviewDir(meta.id),\n feedback\n };\n globals.json\n ? printJson(result)\n : printPlain(`Review ${meta.id} submitted with ${event.counts.comments} comments`);\n }\n );\n\nprogram\n .command('watch')\n .argument('<reviewId>', 'review id')\n .description('Wait for review.submitted for an existing review')\n .option('--timeout <seconds>', 'watch timeout in seconds', Number)\n .action(async (reviewId: string, options: { timeout?: number }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await ensureServer();\n const client = new ServerClient(serverUrl(info));\n const event = await client.watchReview(reviewId, options.timeout);\n globals.json ? printJson(event) : printPlain(`${event.type} ${event.reviewId}`);\n });\n\nprogram\n .command('start')\n .description('Start or reuse the background server')\n .option('--port <port>', 'port to bind', Number)\n .action(async (options: { port?: number }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await startServer({ port: options.port });\n globals.json\n ? printJson(info)\n : printPlain(`Gloss server running at ${serverUrl(info)} (pid ${info.pid})`);\n });\n\nprogram\n .command('status')\n .description('Show server and active reviews')\n .action(async () => {\n const globals = program.opts<GlobalOptions>();\n const info = await readServerInfo();\n const responsive = info ? await isServerResponsive(info) : false;\n const reviews = await listReviewsForStatus({ responsive, server: info });\n const status = { running: responsive, server: info, reviews };\n globals.json\n ? printJson(status)\n : printPlain(\n responsive && info\n ? `Gloss server running at ${serverUrl(info)} with ${reviews.length} active review(s)`\n : 'Gloss server is not running'\n );\n });\n\nprogram\n .command('stop')\n .description('Stop the managed background server')\n .option('--all', 'reserved for future multi-server cleanup')\n .action(async () => {\n const globals = program.opts<GlobalOptions>();\n const result = await stopServer();\n globals.json\n ? printJson(result)\n : printPlain(result.stopped ? 'Gloss server stopped' : 'Gloss server was not running');\n });\n\nprogram\n .command('resolve')\n .argument('<reviewId>', 'review id')\n .description('Mark a submitted review or one feedback comment as resolved')\n .option('--comment <commentId>', 'resolve one submitted feedback comment')\n .option('--summary <text>', 'brief summary of the fixes applied')\n .action(async (reviewId: string, options: { comment?: string; summary?: string }) => {\n const globals = program.opts<GlobalOptions>();\n const info = await ensureServer();\n const client = new ServerClient(serverUrl(info));\n const result = options.comment\n ? await client.resolveComment(reviewId, options.comment, options.summary)\n : await client.markResolved(reviewId, options.summary);\n if (globals.json) {\n printJson({\n commentId: options.comment ?? null,\n summary: options.summary ?? null,\n ...result\n });\n return;\n }\n printPlain(\n options.comment\n ? `Comment ${options.comment} resolved in review ${reviewId}`\n : `Review ${reviewId} resolved`\n );\n });\n\nprogram\n .command('doctor')\n .description('Diagnose setup and validate git/state')\n .action(async () => {\n const globals = program.opts<GlobalOptions>();\n const checks: Array<{ name: string; ok: boolean; detail?: string }> = [];\n try {\n await assertGitAvailable();\n checks.push({ name: 'git', ok: true });\n } catch (error) {\n checks.push({\n name: 'git',\n ok: false,\n detail: error instanceof Error ? error.message : String(error)\n });\n }\n try {\n const root = await getRepoRoot();\n checks.push({ name: 'repo', ok: true, detail: root });\n } catch (error) {\n checks.push({\n name: 'repo',\n ok: false,\n detail: error instanceof Error ? error.message : String(error)\n });\n }\n const info = await readServerInfo();\n checks.push({\n name: 'server',\n ok: info ? await isServerResponsive(info) : false,\n detail: info ? serverUrl(info) : 'not started'\n });\n checks.push({\n name: '@pierre/diffs license',\n ok: true,\n detail: 'apache-2.0 dependency present'\n });\n\n if (globals.json) {\n printJson({ checks });\n } else {\n for (const check of checks) {\n printPlain(\n `${check.ok ? 'ok' : 'fail'} ${check.name}${check.detail ? ` - ${check.detail}` : ''}`\n );\n }\n }\n });\n\nprogram.parseAsync(process.argv).catch((error: unknown) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\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 { execa } from 'execa';\nimport type {\n DiffFallbackReason,\n DiffFile,\n DiffPayload,\n DiffScopeMode,\n DiffStats\n} from '../shared/types';\nimport { parseUnifiedDiff } from './diff-parser';\n\nconst DIFF_ARGS = ['diff', '--no-color', '--find-renames', '--find-copies'];\n\nasync function git(args: string[], cwd = process.cwd()): Promise<string> {\n const result = await execa('git', args, { cwd });\n return result.stdout.trimEnd();\n}\n\nasync function gitMaybe(args: string[], cwd: string): Promise<string | null> {\n const result = await execa('git', args, { cwd, reject: false });\n return result.exitCode === 0 ? result.stdout.trimEnd() : null;\n}\n\nasync function gitLenient(args: string[], cwd: string): Promise<string> {\n const result = await execa('git', args, { cwd, reject: false });\n if (result.exitCode !== 0 && result.stdout.length === 0) {\n throw new Error(result.stderr || `git ${args.join(' ')} failed`);\n }\n return result.stdout.trimEnd();\n}\n\nexport async function getRepoRoot(cwd = process.cwd()): Promise<string> {\n return git(['rev-parse', '--show-toplevel'], cwd);\n}\n\ninterface ResolvedBranchBase {\n sourceRef: string;\n mergeBaseSha: string;\n}\n\ninterface PayloadOptions {\n repoRoot: string;\n branch: string | null;\n rawDiff: string;\n base: { ref: string; sha: string };\n mode: DiffScopeMode;\n requestedBase: string | null;\n comparison: { ref: string; sha: string | null };\n fallbackReason: DiffFallbackReason;\n}\n\nfunction summarize(files: DiffFile[]): DiffStats {\n return files.reduce(\n (stats, file) => ({\n files: stats.files + 1,\n additions: stats.additions + file.additions,\n deletions: stats.deletions + file.deletions\n }),\n { files: 0, additions: 0, deletions: 0 }\n );\n}\n\nfunction buildPayload({\n repoRoot,\n branch,\n rawDiff,\n base,\n mode,\n requestedBase,\n comparison,\n fallbackReason\n}: PayloadOptions): DiffPayload {\n const files = parseUnifiedDiff(rawDiff);\n return {\n base,\n branch,\n cwd: repoRoot,\n scope: {\n mode,\n requestedBase,\n base,\n comparison,\n fallbackReason\n },\n stats: summarize(files),\n rawDiff,\n files,\n capturedAt: new Date().toISOString()\n };\n}\n\nasync function currentBranch(repoRoot: string): Promise<string | null> {\n const branch = await gitMaybe(['rev-parse', '--abbrev-ref', 'HEAD'], repoRoot);\n return branch && branch !== 'HEAD' ? branch : null;\n}\n\nasync function captureUntrackedDiff(repoRoot: string): Promise<string[]> {\n const untrackedFilesRaw = await git(\n ['ls-files', '--others', '--exclude-standard', '-z'],\n repoRoot\n );\n const untrackedFiles = untrackedFilesRaw.split('\\0').filter(Boolean);\n return Promise.all(\n untrackedFiles.map((filePath) =>\n gitLenient(['diff', '--no-color', '--no-index', '--', '/dev/null', filePath], repoRoot)\n )\n );\n}\n\nasync function captureWorkingDiff(baseRef: string, repoRoot: string): Promise<string> {\n const [trackedDiff, untrackedDiffs] = await Promise.all([\n git([...DIFF_ARGS, baseRef, '--'], repoRoot),\n captureUntrackedDiff(repoRoot)\n ]);\n return [trackedDiff, ...untrackedDiffs].filter(Boolean).join('\\n');\n}\n\nasync function resolveCommit(ref: string, repoRoot: string): Promise<string | null> {\n return gitMaybe(['rev-parse', '--verify', `${ref}^{commit}`], repoRoot);\n}\n\nasync function resolveBranchBase(repoRoot: string): Promise<ResolvedBranchBase | null> {\n const candidates: string[] = [];\n const upstream = await gitMaybe(\n ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{upstream}'],\n repoRoot\n );\n const originHead = await gitMaybe(\n ['symbolic-ref', '--quiet', '--short', 'refs/remotes/origin/HEAD'],\n repoRoot\n );\n\n for (const ref of [upstream, originHead, 'origin/main', 'origin/master']) {\n if (ref && !candidates.includes(ref)) {\n candidates.push(ref);\n }\n }\n\n for (const sourceRef of candidates) {\n const [sourceSha, mergeBaseSha] = await Promise.all([\n resolveCommit(sourceRef, repoRoot),\n gitMaybe(['merge-base', 'HEAD', sourceRef], repoRoot)\n ]);\n if (sourceSha && mergeBaseSha) {\n return { sourceRef, mergeBaseSha };\n }\n }\n\n return null;\n}\n\nexport async function captureDiff(baseRef?: string, cwd = process.cwd()): Promise<DiffPayload> {\n const repoRoot = await getRepoRoot(cwd);\n const [headSha, branch] = await Promise.all([\n git(['rev-parse', 'HEAD'], repoRoot),\n currentBranch(repoRoot)\n ]);\n\n if (baseRef) {\n const [baseSha, rawDiff] = await Promise.all([\n git(['rev-parse', baseRef], repoRoot),\n captureWorkingDiff(baseRef, repoRoot)\n ]);\n return buildPayload({\n repoRoot,\n branch,\n rawDiff,\n base: { ref: baseRef, sha: baseSha },\n mode: 'explicit',\n requestedBase: baseRef,\n comparison: { ref: 'working tree', sha: null },\n fallbackReason: null\n });\n }\n\n const workingDiff = await captureWorkingDiff('HEAD', repoRoot);\n if (workingDiff.trim().length > 0) {\n return buildPayload({\n repoRoot,\n branch,\n rawDiff: workingDiff,\n base: { ref: 'HEAD', sha: headSha },\n mode: 'working',\n requestedBase: null,\n comparison: { ref: 'working tree', sha: null },\n fallbackReason: null\n });\n }\n\n const branchBase = await resolveBranchBase(repoRoot);\n if (!branchBase) {\n return buildPayload({\n repoRoot,\n branch,\n rawDiff: '',\n base: { ref: 'HEAD', sha: headSha },\n mode: 'working',\n requestedBase: null,\n comparison: { ref: 'working tree', sha: null },\n fallbackReason: 'missing-branch-base'\n });\n }\n\n const rawDiff = await git([...DIFF_ARGS, branchBase.mergeBaseSha, 'HEAD', '--'], repoRoot);\n return buildPayload({\n repoRoot,\n branch,\n rawDiff,\n base: { ref: `merge-base(${branchBase.sourceRef})`, sha: branchBase.mergeBaseSha },\n mode: 'branch',\n requestedBase: null,\n comparison: { ref: 'HEAD', sha: headSha },\n fallbackReason: 'working-tree-clean'\n });\n}\n\nexport async function assertGitAvailable(): Promise<void> {\n await execa('git', ['--version']);\n}\n","import path from 'node:path';\nimport type { DiffFile, DiffHunk, DiffLine } from '../shared/types';\n\nconst hunkHeaderPattern = /^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/;\n\nfunction stripGitPath(input: string): string {\n return input.replace(/^[ab]\\//, '');\n}\n\nfunction languageForPath(filePath: string): string | null {\n const ext = path.extname(filePath).slice(1).toLowerCase();\n if (!ext) {\n return null;\n }\n const map: Record<string, string> = {\n cjs: 'js',\n mjs: 'js',\n js: 'js',\n jsx: 'jsx',\n ts: 'ts',\n tsx: 'tsx',\n py: 'python',\n rb: 'ruby',\n sh: 'bash',\n md: 'markdown',\n yml: 'yaml',\n yaml: 'yaml'\n };\n return map[ext] ?? ext;\n}\n\nfunction emptyFile(): DiffFile {\n return {\n path: '',\n oldPath: null,\n additions: 0,\n deletions: 0,\n isBinary: false,\n isDeleted: false,\n isNew: false,\n isRenamed: false,\n language: null,\n hunks: []\n };\n}\n\nexport function parseUnifiedDiff(diffText: string): DiffFile[] {\n const files: DiffFile[] = [];\n let current: DiffFile | null = null;\n let currentHunk: DiffHunk | null = null;\n let oldCursor = 0;\n let newCursor = 0;\n\n const finalizeFile = () => {\n if (current?.path) {\n current.language = languageForPath(current.path);\n files.push(current);\n }\n };\n\n for (const line of diffText.split('\\n')) {\n if (line.startsWith('diff --git ')) {\n finalizeFile();\n current = emptyFile();\n currentHunk = null;\n oldCursor = 0;\n newCursor = 0;\n const match = /^diff --git a\\/(.+) b\\/(.+)$/.exec(line);\n if (match) {\n current.oldPath = match[1];\n current.path = match[2];\n }\n continue;\n }\n\n if (!current) {\n continue;\n }\n\n if (line.startsWith('new file mode')) {\n current.isNew = true;\n continue;\n }\n\n if (line.startsWith('deleted file mode')) {\n current.isDeleted = true;\n continue;\n }\n\n if (line.startsWith('rename from ')) {\n current.oldPath = line.slice('rename from '.length);\n current.isRenamed = true;\n continue;\n }\n\n if (line.startsWith('rename to ')) {\n current.path = line.slice('rename to '.length);\n current.isRenamed = true;\n continue;\n }\n\n if (line.startsWith('Binary files ') || line.startsWith('GIT binary patch')) {\n current.isBinary = true;\n continue;\n }\n\n if (line.startsWith('--- ')) {\n const oldPath = line.slice(4).trim();\n current.oldPath = oldPath === '/dev/null' ? null : stripGitPath(oldPath);\n continue;\n }\n\n if (line.startsWith('+++ ')) {\n const newPath = line.slice(4).trim();\n current.path =\n newPath === '/dev/null' ? (current.oldPath ?? current.path) : stripGitPath(newPath);\n continue;\n }\n\n const hunkMatch = hunkHeaderPattern.exec(line);\n if (hunkMatch) {\n const oldStart = Number(hunkMatch[1]);\n const oldLines = Number(hunkMatch[2] ?? '1');\n const newStart = Number(hunkMatch[3]);\n const newLines = Number(hunkMatch[4] ?? '1');\n currentHunk = {\n oldStart,\n oldLines,\n newStart,\n newLines,\n header: hunkMatch[5]?.trim() ?? '',\n lines: []\n };\n current.hunks.push(currentHunk);\n oldCursor = oldStart;\n newCursor = newStart;\n continue;\n }\n\n if (!currentHunk) {\n continue;\n }\n\n const marker = line[0];\n const content = line.slice(1);\n let diffLine: DiffLine | null = null;\n\n if (marker === '+') {\n diffLine = { type: 'add', oldLine: null, newLine: newCursor, content };\n current.additions += 1;\n newCursor += 1;\n } else if (marker === '-') {\n diffLine = { type: 'delete', oldLine: oldCursor, newLine: null, content };\n current.deletions += 1;\n oldCursor += 1;\n } else if (marker === ' ') {\n diffLine = { type: 'context', oldLine: oldCursor, newLine: newCursor, content };\n oldCursor += 1;\n newCursor += 1;\n } else if (line.startsWith('\\\')) {\n continue;\n }\n\n if (diffLine) {\n currentHunk.lines.push(diffLine);\n }\n }\n\n finalizeFile();\n return files;\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 type {\n Comment,\n DiffPayload,\n FeedbackBundle,\n OpenResult,\n ResolveResult,\n ReviewEvent,\n ReviewMeta,\n ReviewRecord\n} from '../shared/types';\n\nexport class ServerClient {\n constructor(private readonly baseUrl: string) {}\n\n async health(): Promise<{ ok: boolean; version: string; activeReviews: number }> {\n return this.get('/api/health');\n }\n\n async createReview(diff: DiffPayload): Promise<{ meta: ReviewMeta; url: string }> {\n return this.post('/api/reviews', diff);\n }\n\n async getReview(reviewId: string): Promise<ReviewRecord> {\n return this.get(`/api/reviews/${reviewId}`);\n }\n\n async listReviews(): Promise<{ reviews: ReviewMeta[] }> {\n return this.get('/api/reviews');\n }\n\n async getFeedback(reviewId: string): Promise<FeedbackBundle> {\n return this.get(`/api/reviews/${reviewId}/feedback`);\n }\n\n async markResolved(reviewId: string, summary?: string): Promise<ResolveResult> {\n return this.post(`/api/reviews/${reviewId}/resolved`, { summary });\n }\n\n async resolveComment(\n reviewId: string,\n commentId: string,\n summary?: string\n ): Promise<ResolveResult> {\n return this.post(`/api/reviews/${reviewId}/comments/${commentId}/resolved`, { summary });\n }\n\n async reopenComment(reviewId: string, commentId: string): Promise<ResolveResult> {\n return this.delete(`/api/reviews/${reviewId}/comments/${commentId}/resolved`);\n }\n\n async submitReview(reviewId: string, comments: Comment[]): Promise<OpenResult> {\n return this.post(`/api/reviews/${reviewId}/submit`, { comments });\n }\n\n async watchReview(reviewId: string, timeoutSeconds?: number): Promise<ReviewEvent> {\n const deadline =\n timeoutSeconds && timeoutSeconds > 0 ? Date.now() + timeoutSeconds * 1000 : null;\n\n while (true) {\n const remainingMs = deadline ? deadline - Date.now() : null;\n if (remainingMs !== null && remainingMs <= 0) {\n throw new Error(`watch timed out after ${timeoutSeconds} seconds`);\n }\n\n const controller = new AbortController();\n const timeout = remainingMs ? setTimeout(() => controller.abort(), remainingMs) : null;\n try {\n return await this.readReviewEvents(reviewId, controller.signal);\n } catch (error) {\n if (isAbortError(error)) {\n throw new Error(`watch timed out after ${timeoutSeconds} seconds`);\n }\n if (!isPrematureWatchEnd(error)) {\n throw error;\n }\n await sleep(500);\n } finally {\n if (timeout) {\n clearTimeout(timeout);\n }\n }\n }\n }\n\n private async readReviewEvents(reviewId: string, signal: AbortSignal): Promise<ReviewEvent> {\n const response = await fetch(`${this.baseUrl}/api/reviews/${reviewId}/events`, {\n signal\n });\n if (!response.ok || !response.body) {\n throw new Error(`watch failed: ${response.status} ${await response.text()}`);\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n throw new Error('watch stream ended before completion');\n }\n buffer += decoder.decode(value, { stream: true });\n const events = buffer.split('\\n\\n');\n buffer = events.pop() ?? '';\n for (const eventChunk of events) {\n const dataLine = eventChunk.split('\\n').find((line) => line.startsWith('data:'));\n if (!dataLine) {\n continue;\n }\n const event = JSON.parse(dataLine.slice(5).trim()) as ReviewEvent;\n if (event.type === 'review.submitted' || event.type === 'review.cancelled') {\n return event;\n }\n }\n }\n }\n\n private async get<T>(path: string): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`);\n return parseResponse<T>(response);\n }\n\n private async post<T>(path: string, body: unknown): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body)\n });\n return parseResponse<T>(response);\n }\n\n private async delete<T>(path: string): Promise<T> {\n const response = await fetch(`${this.baseUrl}${path}`, { method: 'DELETE' });\n return parseResponse<T>(response);\n }\n}\n\nasync function parseResponse<T>(response: Response): Promise<T> {\n if (!response.ok) {\n throw new Error(`${response.status} ${response.statusText}: ${await response.text()}`);\n }\n return (await response.json()) as T;\n}\n\nfunction isPrematureWatchEnd(error: unknown): boolean {\n return error instanceof Error && error.message === 'watch stream ended before completion';\n}\n\nfunction isAbortError(error: unknown): boolean {\n return (\n typeof error === 'object' && error !== null && 'name' in error && error.name === 'AbortError'\n );\n}\n\nasync function sleep(milliseconds: number): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, milliseconds));\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","import { ReviewStore } from '../server/store';\nimport type { ReviewMeta, ServerInfo } from '../shared/types';\nimport { serverUrl } from './lifecycle';\nimport { ServerClient } from './server-client';\n\nexport async function listReviewsForStatus({\n responsive,\n server\n}: {\n responsive: boolean;\n server: ServerInfo | null;\n}): Promise<ReviewMeta[]> {\n if (server && responsive) {\n try {\n return (await new ServerClient(serverUrl(server)).listReviews()).reviews;\n } catch {\n // Fall through to durable state if the daemon disappears between health and list.\n }\n }\n\n return new ReviewStore().list();\n}\n"],"mappings":";;;AACA,SAAS,eAAe;AACxB,OAAO,iBAAiB;;;ACFxB,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,OAAO,UAAU;;;ACFjB;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,gBAAkB;AAAA,EAClB,KAAO;AAAA,IACL,UAAY;AAAA,IACZ,OAAS;AAAA,EACX;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,aAAa;AAAA,IACb,cAAc;AAAA,IACd,OAAS;AAAA,IACT,QAAU;AAAA,IACV,SAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,cAAc;AAAA,EAChB;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,cAAgB;AAAA,IACd,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,WAAa;AAAA,IACb,OAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,MAAQ;AAAA,IACR,OAAS;AAAA,IACT,aAAa;AAAA,IACb,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,SAAW;AAAA,EACb;AAAA,EACA,iBAAmB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,YAAc;AAAA,IACd,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,YAAc;AAAA,IACd,MAAQ;AAAA,IACR,QAAU;AAAA,EACZ;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAU;AAAA,EACV,SAAW;AAAA,EACX,UAAY;AAAA,EACZ,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AACF;;;ADzEO,IAAM,iBAAiB,gBAAY;AAEnC,SAAS,WAAW,OAAuB;AAChD,MAAI,UAAU,KAAK;AACjB,WAAO,QAAQ;AAAA,EACjB;AACA,MAAI,MAAM,WAAW,IAAI,GAAG;AAC1B,WAAO,KAAK,KAAK,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAEO,SAAS,iBAAyB;AACvC,SAAO,WAAW,QAAQ,IAAI,mBAAmB,UAAU;AAC7D;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,KAAK,eAAe,GAAG,aAAa;AAClD;AAEO,SAAS,eAAuB;AACrC,SAAO,KAAK,KAAK,eAAe,GAAG,MAAM;AAC3C;AAEO,SAAS,sBAA8B;AAC5C,SAAO,KAAK,KAAK,aAAa,GAAG,YAAY;AAC/C;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,KAAK,eAAe,GAAG,SAAS;AAC9C;AAEO,SAAS,gBAAgB,UAA0B;AACxD,SAAO,KAAK,KAAK,iBAAiB,GAAG,QAAQ;AAC/C;AAEO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,WAAW;AACzD;AAEO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,WAAW;AACzD;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,eAAe;AAC7D;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,aAAa;AAC3D;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,eAAe;AAC7D;AAEA,eAAsB,UAAU,KAA4B;AAC1D,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACtC;;;AE/DA,SAAS,aAAa;;;ACAtB,OAAOA,WAAU;AAGjB,IAAM,oBAAoB;AAE1B,SAAS,aAAa,OAAuB;AAC3C,SAAO,MAAM,QAAQ,WAAW,EAAE;AACpC;AAEA,SAAS,gBAAgB,UAAiC;AACxD,QAAM,MAAMA,MAAK,QAAQ,QAAQ,EAAE,MAAM,CAAC,EAAE,YAAY;AACxD,MAAI,CAAC,KAAK;AACR,WAAO;AAAA,EACT;AACA,QAAM,MAA8B;AAAA,IAClC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,MAAM;AAAA,EACR;AACA,SAAO,IAAI,GAAG,KAAK;AACrB;AAEA,SAAS,YAAsB;AAC7B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX,UAAU;AAAA,IACV,WAAW;AAAA,IACX,OAAO;AAAA,IACP,WAAW;AAAA,IACX,UAAU;AAAA,IACV,OAAO,CAAC;AAAA,EACV;AACF;AAEO,SAAS,iBAAiB,UAA8B;AAC7D,QAAM,QAAoB,CAAC;AAC3B,MAAI,UAA2B;AAC/B,MAAI,cAA+B;AACnC,MAAI,YAAY;AAChB,MAAI,YAAY;AAEhB,QAAM,eAAe,MAAM;AACzB,QAAI,SAAS,MAAM;AACjB,cAAQ,WAAW,gBAAgB,QAAQ,IAAI;AAC/C,YAAM,KAAK,OAAO;AAAA,IACpB;AAAA,EACF;AAEA,aAAW,QAAQ,SAAS,MAAM,IAAI,GAAG;AACvC,QAAI,KAAK,WAAW,aAAa,GAAG;AAClC,mBAAa;AACb,gBAAU,UAAU;AACpB,oBAAc;AACd,kBAAY;AACZ,kBAAY;AACZ,YAAM,QAAQ,+BAA+B,KAAK,IAAI;AACtD,UAAI,OAAO;AACT,gBAAQ,UAAU,MAAM,CAAC;AACzB,gBAAQ,OAAO,MAAM,CAAC;AAAA,MACxB;AACA;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,eAAe,GAAG;AACpC,cAAQ,QAAQ;AAChB;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,mBAAmB,GAAG;AACxC,cAAQ,YAAY;AACpB;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,cAAc,GAAG;AACnC,cAAQ,UAAU,KAAK,MAAM,eAAe,MAAM;AAClD,cAAQ,YAAY;AACpB;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,YAAY,GAAG;AACjC,cAAQ,OAAO,KAAK,MAAM,aAAa,MAAM;AAC7C,cAAQ,YAAY;AACpB;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,eAAe,KAAK,KAAK,WAAW,kBAAkB,GAAG;AAC3E,cAAQ,WAAW;AACnB;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,MAAM,GAAG;AAC3B,YAAM,UAAU,KAAK,MAAM,CAAC,EAAE,KAAK;AACnC,cAAQ,UAAU,YAAY,cAAc,OAAO,aAAa,OAAO;AACvE;AAAA,IACF;AAEA,QAAI,KAAK,WAAW,MAAM,GAAG;AAC3B,YAAM,UAAU,KAAK,MAAM,CAAC,EAAE,KAAK;AACnC,cAAQ,OACN,YAAY,cAAe,QAAQ,WAAW,QAAQ,OAAQ,aAAa,OAAO;AACpF;AAAA,IACF;AAEA,UAAM,YAAY,kBAAkB,KAAK,IAAI;AAC7C,QAAI,WAAW;AACb,YAAM,WAAW,OAAO,UAAU,CAAC,CAAC;AACpC,YAAM,WAAW,OAAO,UAAU,CAAC,KAAK,GAAG;AAC3C,YAAM,WAAW,OAAO,UAAU,CAAC,CAAC;AACpC,YAAM,WAAW,OAAO,UAAU,CAAC,KAAK,GAAG;AAC3C,oBAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,QAAQ,UAAU,CAAC,GAAG,KAAK,KAAK;AAAA,QAChC,OAAO,CAAC;AAAA,MACV;AACA,cAAQ,MAAM,KAAK,WAAW;AAC9B,kBAAY;AACZ,kBAAY;AACZ;AAAA,IACF;AAEA,QAAI,CAAC,aAAa;AAChB;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,CAAC;AACrB,UAAM,UAAU,KAAK,MAAM,CAAC;AAC5B,QAAI,WAA4B;AAEhC,QAAI,WAAW,KAAK;AAClB,iBAAW,EAAE,MAAM,OAAO,SAAS,MAAM,SAAS,WAAW,QAAQ;AACrE,cAAQ,aAAa;AACrB,mBAAa;AAAA,IACf,WAAW,WAAW,KAAK;AACzB,iBAAW,EAAE,MAAM,UAAU,SAAS,WAAW,SAAS,MAAM,QAAQ;AACxE,cAAQ,aAAa;AACrB,mBAAa;AAAA,IACf,WAAW,WAAW,KAAK;AACzB,iBAAW,EAAE,MAAM,WAAW,SAAS,WAAW,SAAS,WAAW,QAAQ;AAC9E,mBAAa;AACb,mBAAa;AAAA,IACf,WAAW,KAAK,WAAW,8BAA8B,GAAG;AAC1D;AAAA,IACF;AAEA,QAAI,UAAU;AACZ,kBAAY,MAAM,KAAK,QAAQ;AAAA,IACjC;AAAA,EACF;AAEA,eAAa;AACb,SAAO;AACT;;;ADhKA,IAAM,YAAY,CAAC,QAAQ,cAAc,kBAAkB,eAAe;AAE1E,eAAe,IAAI,MAAgB,MAAM,QAAQ,IAAI,GAAoB;AACvE,QAAM,SAAS,MAAM,MAAM,OAAO,MAAM,EAAE,IAAI,CAAC;AAC/C,SAAO,OAAO,OAAO,QAAQ;AAC/B;AAEA,eAAe,SAAS,MAAgB,KAAqC;AAC3E,QAAM,SAAS,MAAM,MAAM,OAAO,MAAM,EAAE,KAAK,QAAQ,MAAM,CAAC;AAC9D,SAAO,OAAO,aAAa,IAAI,OAAO,OAAO,QAAQ,IAAI;AAC3D;AAEA,eAAe,WAAW,MAAgB,KAA8B;AACtE,QAAM,SAAS,MAAM,MAAM,OAAO,MAAM,EAAE,KAAK,QAAQ,MAAM,CAAC;AAC9D,MAAI,OAAO,aAAa,KAAK,OAAO,OAAO,WAAW,GAAG;AACvD,UAAM,IAAI,MAAM,OAAO,UAAU,OAAO,KAAK,KAAK,GAAG,CAAC,SAAS;AAAA,EACjE;AACA,SAAO,OAAO,OAAO,QAAQ;AAC/B;AAEA,eAAsB,YAAY,MAAM,QAAQ,IAAI,GAAoB;AACtE,SAAO,IAAI,CAAC,aAAa,iBAAiB,GAAG,GAAG;AAClD;AAkBA,SAAS,UAAU,OAA8B;AAC/C,SAAO,MAAM;AAAA,IACX,CAAC,OAAO,UAAU;AAAA,MAChB,OAAO,MAAM,QAAQ;AAAA,MACrB,WAAW,MAAM,YAAY,KAAK;AAAA,MAClC,WAAW,MAAM,YAAY,KAAK;AAAA,IACpC;AAAA,IACA,EAAE,OAAO,GAAG,WAAW,GAAG,WAAW,EAAE;AAAA,EACzC;AACF;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,QAAQ,iBAAiB,OAAO;AACtC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,KAAK;AAAA,IACL,OAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,OAAO,UAAU,KAAK;AAAA,IACtB;AAAA,IACA;AAAA,IACA,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrC;AACF;AAEA,eAAe,cAAc,UAA0C;AACrE,QAAM,SAAS,MAAM,SAAS,CAAC,aAAa,gBAAgB,MAAM,GAAG,QAAQ;AAC7E,SAAO,UAAU,WAAW,SAAS,SAAS;AAChD;AAEA,eAAe,qBAAqB,UAAqC;AACvE,QAAM,oBAAoB,MAAM;AAAA,IAC9B,CAAC,YAAY,YAAY,sBAAsB,IAAI;AAAA,IACnD;AAAA,EACF;AACA,QAAM,iBAAiB,kBAAkB,MAAM,IAAI,EAAE,OAAO,OAAO;AACnE,SAAO,QAAQ;AAAA,IACb,eAAe;AAAA,MAAI,CAAC,aAClB,WAAW,CAAC,QAAQ,cAAc,cAAc,MAAM,aAAa,QAAQ,GAAG,QAAQ;AAAA,IACxF;AAAA,EACF;AACF;AAEA,eAAe,mBAAmB,SAAiB,UAAmC;AACpF,QAAM,CAAC,aAAa,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,IACtD,IAAI,CAAC,GAAG,WAAW,SAAS,IAAI,GAAG,QAAQ;AAAA,IAC3C,qBAAqB,QAAQ;AAAA,EAC/B,CAAC;AACD,SAAO,CAAC,aAAa,GAAG,cAAc,EAAE,OAAO,OAAO,EAAE,KAAK,IAAI;AACnE;AAEA,eAAe,cAAc,KAAa,UAA0C;AAClF,SAAO,SAAS,CAAC,aAAa,YAAY,GAAG,GAAG,WAAW,GAAG,QAAQ;AACxE;AAEA,eAAe,kBAAkB,UAAsD;AACrF,QAAM,aAAuB,CAAC;AAC9B,QAAM,WAAW,MAAM;AAAA,IACrB,CAAC,aAAa,gBAAgB,wBAAwB,aAAa;AAAA,IACnE;AAAA,EACF;AACA,QAAM,aAAa,MAAM;AAAA,IACvB,CAAC,gBAAgB,WAAW,WAAW,0BAA0B;AAAA,IACjE;AAAA,EACF;AAEA,aAAW,OAAO,CAAC,UAAU,YAAY,eAAe,eAAe,GAAG;AACxE,QAAI,OAAO,CAAC,WAAW,SAAS,GAAG,GAAG;AACpC,iBAAW,KAAK,GAAG;AAAA,IACrB;AAAA,EACF;AAEA,aAAW,aAAa,YAAY;AAClC,UAAM,CAAC,WAAW,YAAY,IAAI,MAAM,QAAQ,IAAI;AAAA,MAClD,cAAc,WAAW,QAAQ;AAAA,MACjC,SAAS,CAAC,cAAc,QAAQ,SAAS,GAAG,QAAQ;AAAA,IACtD,CAAC;AACD,QAAI,aAAa,cAAc;AAC7B,aAAO,EAAE,WAAW,aAAa;AAAA,IACnC;AAAA,EACF;AAEA,SAAO;AACT;AAEA,eAAsB,YAAY,SAAkB,MAAM,QAAQ,IAAI,GAAyB;AAC7F,QAAM,WAAW,MAAM,YAAY,GAAG;AACtC,QAAM,CAAC,SAAS,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC1C,IAAI,CAAC,aAAa,MAAM,GAAG,QAAQ;AAAA,IACnC,cAAc,QAAQ;AAAA,EACxB,CAAC;AAED,MAAI,SAAS;AACX,UAAM,CAAC,SAASC,QAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC3C,IAAI,CAAC,aAAa,OAAO,GAAG,QAAQ;AAAA,MACpC,mBAAmB,SAAS,QAAQ;AAAA,IACtC,CAAC;AACD,WAAO,aAAa;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAAA;AAAA,MACA,MAAM,EAAE,KAAK,SAAS,KAAK,QAAQ;AAAA,MACnC,MAAM;AAAA,MACN,eAAe;AAAA,MACf,YAAY,EAAE,KAAK,gBAAgB,KAAK,KAAK;AAAA,MAC7C,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,QAAM,cAAc,MAAM,mBAAmB,QAAQ,QAAQ;AAC7D,MAAI,YAAY,KAAK,EAAE,SAAS,GAAG;AACjC,WAAO,aAAa;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,MAAM,EAAE,KAAK,QAAQ,KAAK,QAAQ;AAAA,MAClC,MAAM;AAAA,MACN,eAAe;AAAA,MACf,YAAY,EAAE,KAAK,gBAAgB,KAAK,KAAK;AAAA,MAC7C,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,QAAM,aAAa,MAAM,kBAAkB,QAAQ;AACnD,MAAI,CAAC,YAAY;AACf,WAAO,aAAa;AAAA,MAClB;AAAA,MACA;AAAA,MACA,SAAS;AAAA,MACT,MAAM,EAAE,KAAK,QAAQ,KAAK,QAAQ;AAAA,MAClC,MAAM;AAAA,MACN,eAAe;AAAA,MACf,YAAY,EAAE,KAAK,gBAAgB,KAAK,KAAK;AAAA,MAC7C,gBAAgB;AAAA,IAClB,CAAC;AAAA,EACH;AAEA,QAAM,UAAU,MAAM,IAAI,CAAC,GAAG,WAAW,WAAW,cAAc,QAAQ,IAAI,GAAG,QAAQ;AACzF,SAAO,aAAa;AAAA,IAClB;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,EAAE,KAAK,cAAc,WAAW,SAAS,KAAK,KAAK,WAAW,aAAa;AAAA,IACjF,MAAM;AAAA,IACN,eAAe;AAAA,IACf,YAAY,EAAE,KAAK,QAAQ,KAAK,QAAQ;AAAA,IACxC,gBAAgB;AAAA,EAClB,CAAC;AACH;AAEA,eAAsB,qBAAoC;AACxD,QAAM,MAAM,OAAO,CAAC,WAAW,CAAC;AAClC;;;AEzNA,SAAS,aAAa;AACtB,SAAS,YAAY,gBAAgB;AACrC,SAAS,UAAU,IAAI,iBAAiB;AACxC,SAAS,qBAAqB;AAC9B,OAAO,aAAa;;;ACOb,IAAM,eAAN,MAAmB;AAAA,EACxB,YAA6B,SAAiB;AAAjB;AAAA,EAAkB;AAAA,EAAlB;AAAA,EAE7B,MAAM,SAA2E;AAC/E,WAAO,KAAK,IAAI,aAAa;AAAA,EAC/B;AAAA,EAEA,MAAM,aAAa,MAA+D;AAChF,WAAO,KAAK,KAAK,gBAAgB,IAAI;AAAA,EACvC;AAAA,EAEA,MAAM,UAAU,UAAyC;AACvD,WAAO,KAAK,IAAI,gBAAgB,QAAQ,EAAE;AAAA,EAC5C;AAAA,EAEA,MAAM,cAAkD;AACtD,WAAO,KAAK,IAAI,cAAc;AAAA,EAChC;AAAA,EAEA,MAAM,YAAY,UAA2C;AAC3D,WAAO,KAAK,IAAI,gBAAgB,QAAQ,WAAW;AAAA,EACrD;AAAA,EAEA,MAAM,aAAa,UAAkB,SAA0C;AAC7E,WAAO,KAAK,KAAK,gBAAgB,QAAQ,aAAa,EAAE,QAAQ,CAAC;AAAA,EACnE;AAAA,EAEA,MAAM,eACJ,UACA,WACA,SACwB;AACxB,WAAO,KAAK,KAAK,gBAAgB,QAAQ,aAAa,SAAS,aAAa,EAAE,QAAQ,CAAC;AAAA,EACzF;AAAA,EAEA,MAAM,cAAc,UAAkB,WAA2C;AAC/E,WAAO,KAAK,OAAO,gBAAgB,QAAQ,aAAa,SAAS,WAAW;AAAA,EAC9E;AAAA,EAEA,MAAM,aAAa,UAAkB,UAA0C;AAC7E,WAAO,KAAK,KAAK,gBAAgB,QAAQ,WAAW,EAAE,SAAS,CAAC;AAAA,EAClE;AAAA,EAEA,MAAM,YAAY,UAAkB,gBAA+C;AACjF,UAAM,WACJ,kBAAkB,iBAAiB,IAAI,KAAK,IAAI,IAAI,iBAAiB,MAAO;AAE9E,WAAO,MAAM;AACX,YAAM,cAAc,WAAW,WAAW,KAAK,IAAI,IAAI;AACvD,UAAI,gBAAgB,QAAQ,eAAe,GAAG;AAC5C,cAAM,IAAI,MAAM,yBAAyB,cAAc,UAAU;AAAA,MACnE;AAEA,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,UAAU,cAAc,WAAW,MAAM,WAAW,MAAM,GAAG,WAAW,IAAI;AAClF,UAAI;AACF,eAAO,MAAM,KAAK,iBAAiB,UAAU,WAAW,MAAM;AAAA,MAChE,SAAS,OAAO;AACd,YAAI,aAAa,KAAK,GAAG;AACvB,gBAAM,IAAI,MAAM,yBAAyB,cAAc,UAAU;AAAA,QACnE;AACA,YAAI,CAAC,oBAAoB,KAAK,GAAG;AAC/B,gBAAM;AAAA,QACR;AACA,cAAM,MAAM,GAAG;AAAA,MACjB,UAAE;AACA,YAAI,SAAS;AACX,uBAAa,OAAO;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,iBAAiB,UAAkB,QAA2C;AAC1F,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,gBAAgB,QAAQ,WAAW;AAAA,MAC7E;AAAA,IACF,CAAC;AACD,QAAI,CAAC,SAAS,MAAM,CAAC,SAAS,MAAM;AAClC,YAAM,IAAI,MAAM,iBAAiB,SAAS,MAAM,IAAI,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,IAC7E;AAEA,UAAM,SAAS,SAAS,KAAK,UAAU;AACvC,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,SAAS;AAEb,WAAO,MAAM;AACX,YAAM,EAAE,OAAO,KAAK,IAAI,MAAM,OAAO,KAAK;AAC1C,UAAI,MAAM;AACR,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,gBAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;AAChD,YAAM,SAAS,OAAO,MAAM,MAAM;AAClC,eAAS,OAAO,IAAI,KAAK;AACzB,iBAAW,cAAc,QAAQ;AAC/B,cAAM,WAAW,WAAW,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,WAAW,OAAO,CAAC;AAC/E,YAAI,CAAC,UAAU;AACb;AAAA,QACF;AACA,cAAM,QAAQ,KAAK,MAAM,SAAS,MAAM,CAAC,EAAE,KAAK,CAAC;AACjD,YAAI,MAAM,SAAS,sBAAsB,MAAM,SAAS,oBAAoB;AAC1E,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,IAAOC,OAA0B;AAC7C,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,GAAGA,KAAI,EAAE;AACrD,WAAO,cAAiB,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAc,KAAQA,OAAc,MAA2B;AAC7D,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,GAAGA,KAAI,IAAI;AAAA,MACrD,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,MAC9C,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AACD,WAAO,cAAiB,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAc,OAAUA,OAA0B;AAChD,UAAM,WAAW,MAAM,MAAM,GAAG,KAAK,OAAO,GAAGA,KAAI,IAAI,EAAE,QAAQ,SAAS,CAAC;AAC3E,WAAO,cAAiB,QAAQ;AAAA,EAClC;AACF;AAEA,eAAe,cAAiB,UAAgC;AAC9D,MAAI,CAAC,SAAS,IAAI;AAChB,UAAM,IAAI,MAAM,GAAG,SAAS,MAAM,IAAI,SAAS,UAAU,KAAK,MAAM,SAAS,KAAK,CAAC,EAAE;AAAA,EACvF;AACA,SAAQ,MAAM,SAAS,KAAK;AAC9B;AAEA,SAAS,oBAAoB,OAAyB;AACpD,SAAO,iBAAiB,SAAS,MAAM,YAAY;AACrD;AAEA,SAAS,aAAa,OAAyB;AAC7C,SACE,OAAO,UAAU,YAAY,UAAU,QAAQ,UAAU,SAAS,MAAM,SAAS;AAErF;AAEA,eAAe,MAAM,cAAqC;AACxD,QAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,YAAY,CAAC;AAClE;;;AD5IA,eAAsB,iBAA6C;AACjE,MAAI;AACF,WAAO,KAAK,MAAM,MAAM,SAAS,iBAAiB,GAAG,MAAM,CAAC;AAAA,EAC9D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,UAAU,MAAwC;AAChE,SAAO,oBAAoB,KAAK,IAAI;AACtC;AAEA,eAAsB,mBAAmB,MAAoC;AAC3E,MAAI,CAAC,WAAW,KAAK,GAAG,GAAG;AACzB,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,SAAS,MAAM,IAAI,aAAa,UAAU,IAAI,CAAC,EAAE,OAAO;AAC9D,WAAO,OAAO,OAAO;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,aAAa,UAA6B,CAAC,GAAwB;AACvF,QAAM,WAAW,MAAM,eAAe;AACtC,MAAI,YAAa,MAAM,mBAAmB,QAAQ,GAAI;AACpD,WAAO;AAAA,EACT;AACA,SAAO,YAAY,OAAO;AAC5B;AAEA,eAAsB,YAAY,UAA6B,CAAC,GAAwB;AACtF,QAAM,WAAW,MAAM,eAAe;AACtC,MAAI,YAAa,MAAM,mBAAmB,QAAQ,GAAI;AACpD,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe,CAAC;AAChC,QAAM,UAAU,aAAa,CAAC;AAC9B,QAAM,OAAO,QAAQ,QAAS,MAAM,QAAQ;AAC5C,QAAM,aAAa,cAAc,IAAI,IAAI,uBAAuB,YAAY,GAAG,CAAC;AAChF,MAAI,CAAC,WAAW,UAAU,GAAG;AAC3B,UAAM,IAAI,MAAM,gCAAgC,UAAU,yBAAyB;AAAA,EACrF;AAEA,QAAM,QAAQ,SAAS,oBAAoB,GAAG,GAAG;AACjD,QAAM,QAAQ,MAAM,QAAQ,UAAU,CAAC,UAAU,GAAG;AAAA,IAClD,UAAU;AAAA,IACV,KAAK;AAAA,MACH,GAAG,QAAQ;AAAA,MACX,YAAY,OAAO,IAAI;AAAA,MACvB,iBAAiB,eAAe;AAAA,IAClC;AAAA,IACA,OAAO,CAAC,UAAU,OAAO,KAAK;AAAA,EAChC,CAAC;AACD,QAAM,MAAM;AAEZ,QAAM,OAAmB;AAAA,IACvB,KAAK,MAAM,OAAO;AAAA,IAClB;AAAA,IACA,SAAS;AAAA,IACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAClC,UAAU,eAAe;AAAA,EAC3B;AACA,QAAM,UAAU,iBAAiB,GAAG,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAExE,QAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,SAAO,KAAK,IAAI,IAAI,UAAU;AAC5B,QAAI,MAAM,mBAAmB,IAAI,GAAG;AAClC,aAAO;AAAA,IACT;AACA,UAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,EACzD;AAEA,QAAM,IAAI,MAAM,yCAAyC,oBAAoB,CAAC,EAAE;AAClF;AAEA,eAAsB,aAAqE;AACzF,QAAM,OAAO,MAAM,eAAe;AAClC,MAAI,CAAC,MAAM;AACT,WAAO,EAAE,SAAS,OAAO,MAAM,KAAK;AAAA,EACtC;AAEA,MAAI,WAAW,KAAK,GAAG,GAAG;AACxB,YAAQ,KAAK,KAAK,KAAK,SAAS;AAAA,EAClC;AACA,QAAM,GAAG,iBAAiB,GAAG,EAAE,OAAO,KAAK,CAAC;AAC5C,SAAO,EAAE,SAAS,MAAM,KAAK;AAC/B;AAOO,SAAS,WAAW,KAAsB;AAC/C,MAAI,OAAO,GAAG;AACZ,WAAO;AAAA,EACT;AACA,MAAI;AACF,YAAQ,KAAK,KAAK,CAAC;AACnB,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AEzHA,SAAS,SAAS,YAAAC,WAAU,MAAAC,KAAI,aAAAC,kBAAiB;AACjD,SAAS,YAAY;;;ACArB,SAAS,gBAAgB,SAA0B;AACjD,QAAM,SAAS,QAAQ;AACvB,MAAI,QAAQ,cAAc,QAAQ,SAAS;AACzC,WAAO,GAAG,MAAM,GAAG,QAAQ,SAAS;AAAA,EACtC;AACA,SAAO,GAAG,MAAM,GAAG,QAAQ,SAAS,IAAI,MAAM,GAAG,QAAQ,OAAO;AAClE;AAEA,SAAS,SAAS,SAAyB;AACzC,MAAI,QAAQ;AACZ,SAAO,QAAQ,SAAS,KAAK,GAAG;AAC9B,aAAS;AAAA,EACX;AACA,SAAO;AACT;AAEA,SAASC,iBAAgB,UAA0B;AACjD,QAAM,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AACnD,QAAM,MAA8B;AAAA,IAClC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AACA,SAAO,MAAO,IAAI,GAAG,KAAK,MAAO;AACnC;AAEA,SAAS,mBAAmB,UAAkB,SAAyB;AACrE,QAAM,QAAQ,QAAQ,MAAM,IAAI,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAClE,QAAM,uBACJ,MAAM,SAAS,KACf,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,CAAC,KACjE,MAAM,MAAM,CAAC,SAAS,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,CAAC;AAC5F,SAAO,uBAAuB,SAASA,iBAAgB,QAAQ;AACjE;AAEA,SAAS,eAAe,GAAY,GAAoB;AACtD,SACE,EAAE,SAAS,cAAc,EAAE,QAAQ,KACnC,EAAE,YAAY,EAAE,aAChB,EAAE,UAAU,EAAE,WACd,EAAE,KAAK,cAAc,EAAE,IAAI;AAE/B;AAEO,SAAS,0BAA0B,QAAgC;AACxE,QAAM,WAAW,CAAC,GAAG,OAAO,QAAQ,EAAE,KAAK,cAAc;AACzD,QAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,QAAQ,CAAC,CAAC;AACtE,QAAM,QAAkB;AAAA,IACtB,sBAAsB,OAAO,SAAS;AAAA,IACtC,WAAW,OAAO,QAAQ;AAAA,IAC1B,SAAS,OAAO,KAAK,GAAG,KAAK,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,cAAc,OAAO,UAAU,YAAY;AAAA,IACnG,UAAU,MAAM,MAAM,gBAAgB,SAAS,MAAM;AAAA,IACrD;AAAA,EACF;AAEA,aAAW,YAAY,OAAO;AAC5B,UAAM,KAAK,MAAM,QAAQ,IAAI,EAAE;AAC/B,eAAW,WAAW,SAAS,OAAO,CAAC,SAAS,KAAK,aAAa,QAAQ,GAAG;AAC3E,YAAM,UAAU,QAAQ,gBAAgB,QAAQ;AAChD,YAAM,mBAAmB,QAAQ,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,EAAE,SAAS,CAAC;AAClF,YAAM,UACJ,QAAQ,cAAc,QAAQ,WAAW,mBACrC,OAAO,gBAAgB,OAAO,CAAC,QAAQ,iBAAiB,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,OAC3E,OAAO,gBAAgB,OAAO,CAAC;AACrC,YAAM,KAAK,SAAS,QAAQ,KAAK,KAAK,GAAG,EAAE;AAC3C,UAAI,SAAS;AACX,cAAM,QAAQ,SAAS,OAAO;AAC9B,cAAM,KAAK,GAAG,KAAK,GAAG,mBAAmB,QAAQ,UAAU,OAAO,CAAC,IAAI,SAAS,OAAO,EAAE;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AAEA,SAAO,GAAG,MAAM,KAAK,IAAI,EAAE,QAAQ,CAAC;AAAA;AACtC;;;AD9DO,IAAM,cAAN,MAAkB;AAAA,EACN,UAAU,oBAAI,IAA0B;AAAA,EACxC,YAAY,oBAAI,IAA2B;AAAA,EAE5D,MAAM,OAAO,MAA0C;AACrD,UAAM,KAAK,KAAK;AAChB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,OAAmB;AAAA,MACvB;AAAA,MACA,KAAK,KAAK;AAAA,MACV,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,QAAQ;AAAA,MACR;AAAA,MACA,aAAa,gBAAgB,EAAE;AAAA,IACjC;AACA,UAAM,SAAuB,EAAE,MAAM,KAAK;AAC1C,SAAK,QAAQ,IAAI,IAAI,MAAM;AAC3B,UAAM,KAAK,eAAe,MAAM;AAChC,SAAK,KAAK,EAAE,MAAM,iBAAiB,UAAU,GAAG,CAAC;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAA8B;AAClC,UAAM,KAAK,eAAe;AAC1B,WAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAC7B,IAAI,CAAC,WAAW,OAAO,IAAI,EAC3B,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAAA,EAC1D;AAAA,EAEA,MAAM,IAAI,IAA0C;AAClD,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAM,MAAM,KAAK,gBAAgB,EAAE;AAAA,EAC/D;AAAA,EAEA,MAAM,OACJ,IACA,UAC+E;AAC/E,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,QAAI,OAAO,KAAK,WAAW,WAAW;AACpC,YAAM,IAAI,MAAM,UAAU,EAAE,OAAO,OAAO,KAAK,MAAM,0BAA0B;AAAA,IACjF;AACA,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,WAA2B;AAAA,MAC/B,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAM,OAAO,KAAK;AAAA,MAClB,QAAQ,OAAO,KAAK;AAAA,MACpB,UAAU,CAAC,GAAG,QAAQ,EAAE;AAAA,QACtB,CAAC,GAAG,MACF,EAAE,SAAS,cAAc,EAAE,QAAQ,KACnC,EAAE,YAAY,EAAE,aAChB,EAAE,UAAU,EAAE,WACd,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,MAC/B;AAAA,IACF;AACA,WAAO,WAAW;AAClB,WAAO,OAAO,EAAE,GAAG,OAAO,MAAM,QAAQ,aAAa,aAAa,UAAU;AAC5E,SAAK,QAAQ,IAAI,IAAI,MAAM;AAE3B,UAAM,cAAc,gBAAgB,EAAE;AACtC,UAAM,eAAe,yBAAyB,EAAE;AAChD,UAAM,eAAe,yBAAyB,EAAE;AAChD,WAAO,OAAO;AAAA,MACZ,GAAG,OAAO;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAU,WAAW;AAC3B,UAAM,QAAQ,IAAI;AAAA,MAChBC,WAAU,qBAAqB,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAC/EA,WAAU,cAAc,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAChEA,WAAU,cAAc,0BAA0B,QAAQ,CAAC;AAAA,IAC7D,CAAC;AAED,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ;AAAA,QACN,OAAO,IAAI,IAAI,SAAS,SAAS,IAAI,CAAC,YAAY,QAAQ,QAAQ,CAAC,EAAE;AAAA,QACrE,UAAU,SAAS,SAAS;AAAA,MAC9B;AAAA,IACF,CAAC;AACD,WAAO,EAAE,QAAQ,cAAc,aAAa;AAAA,EAC9C;AAAA,EAEA,MAAM,SAAS,IAA4C;AACzD,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,WAAO,QAAQ,YAAY;AAAA,EAC7B;AAAA,EAEA,MAAM,aAAa,IAAY,SAA0C;AACvE,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,SAAK,iBAAiB,QAAQ,EAAE;AAChC,UAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,UAAM,eAAe,IAAI;AAAA,OACtB,OAAO,YAAY,YAAY,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,WAAW,OAAO,CAAC;AAAA,IACnF;AACA,UAAM,WAAW,KAAK;AAAA,OACnB,OAAO,UAAU,YAAY,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,QAClD,GAAG,aAAa,IAAI,QAAQ,EAAE;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,QAAQ;AAAA,QACR,YAAY,aAAa,IAAI,QAAQ,EAAE,GAAG,cAAc;AAAA,MAC1D,EAAE;AAAA,MACF;AAAA,IACF;AACA,UAAM,aAA+B;AAAA,MACnC,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS,WAAW,OAAO,YAAY,WAAW;AAAA,MAClD;AAAA,MACA;AAAA,IACF;AACA,WAAO,OAAO,EAAE,GAAG,OAAO,MAAM,QAAQ,YAAY,WAAW;AAC/D,WAAO,KAAK,kBAAkB,QAAQ,UAAU;AAAA,EAClD;AAAA,EAEA,MAAM,eAAe,IAAY,WAAmB,SAA0C;AAC5F,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,SAAK,iBAAiB,QAAQ,EAAE;AAChC,SAAK,oBAAoB,QAAQ,SAAS;AAE1C,UAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,UAAM,WAAW,OAAO,YAAY,SAAS,KAAK,CAAC,YAAY,QAAQ,cAAc,SAAS;AAC9F,UAAM,cAAc,WAAW,UAAU;AACzC,UAAM,cAA+B;AAAA,MACnC;AAAA,MACA,QAAQ;AAAA,MACR,GAAI,cAAc,EAAE,SAAS,YAAY,IAAI,CAAC;AAAA,MAC9C;AAAA,IACF;AACA,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,QACE,IAAI,OAAO,YAAY,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,QAAQ,cAAc,SAAS;AAAA,QAC1F;AAAA,MACF;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,KAAK,iBAAiB,QAAQ,QAAQ;AACrD,UAAM,gBAAgB,OAAO,UAAU,OAAO;AAC9C,UAAM,aAA+B;AAAA,MACnC,UAAU;AAAA,MACV,QAAQ,gBAAgB,aAAa;AAAA,MACrC,SAAS,gBAAiB,OAAO,YAAY,WAAW,OAAQ;AAAA,MAChE,YAAY,gBAAgB,aAAa;AAAA,MACzC;AAAA,IACF;AACA,WAAO,OAAO,gBACV,EAAE,GAAG,OAAO,MAAM,QAAQ,YAAY,WAAW,IACjD,EAAE,GAAG,OAAO,MAAM,QAAQ,aAAa,YAAY,OAAU;AACjE,WAAO,KAAK,kBAAkB,QAAQ,UAAU;AAAA,EAClD;AAAA,EAEA,MAAM,cAAc,IAAY,WAA2C;AACzE,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,SAAK,iBAAiB,QAAQ,EAAE;AAChC,SAAK,oBAAoB,QAAQ,SAAS;AAE1C,UAAM,WAAW,KAAK;AAAA,OACnB,OAAO,YAAY,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,QAAQ,cAAc,SAAS;AAAA,MACvF;AAAA,IACF;AACA,UAAM,SAAS,KAAK,iBAAiB,QAAQ,QAAQ;AACrD,UAAM,gBAAgB,OAAO,QAAQ,KAAK,OAAO,UAAU,OAAO;AAClE,UAAM,aAAa,iBAAgB,oBAAI,KAAK,GAAE,YAAY,IAAI;AAC9D,UAAM,aAA+B;AAAA,MACnC,UAAU;AAAA,MACV,QAAQ,gBAAgB,aAAa;AAAA,MACrC,SAAS,gBAAiB,OAAO,YAAY,WAAW,OAAQ;AAAA,MAChE;AAAA,MACA;AAAA,IACF;AACA,WAAO,OAAO,gBACV,EAAE,GAAG,OAAO,MAAM,QAAQ,YAAY,YAAY,cAAc,OAAU,IAC1E,EAAE,GAAG,OAAO,MAAM,QAAQ,aAAa,YAAY,OAAU;AACjE,WAAO,KAAK,kBAAkB,QAAQ,UAAU;AAAA,EAClD;AAAA,EAEA,UAAU,UAAkB,UAAgC;AAC1D,UAAM,YAAY,KAAK,UAAU,IAAI,QAAQ,KAAK,oBAAI,IAAc;AACpE,cAAU,IAAI,QAAQ;AACtB,SAAK,UAAU,IAAI,UAAU,SAAS;AACtC,WAAO,MAAM;AACX,gBAAU,OAAO,QAAQ;AACzB,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,UAAU,OAAO,QAAQ;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,KAAK,OAA0B;AACrC,eAAW,YAAY,KAAK,UAAU,IAAI,MAAM,QAAQ,KAAK,CAAC,GAAG;AAC/D,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAc,eAAe,QAAqC;AAChE,UAAM,MAAM,gBAAgB,OAAO,KAAK,EAAE;AAC1C,UAAM,UAAU,GAAG;AACnB,UAAM,QAAQ,IAAI;AAAA,MAChBA,WAAU,qBAAqB,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAC3FA,WAAU,qBAAqB,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IAC7F,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,gBAAgB,IAA0C;AACtE,UAAM,WAAW,KAAK,QAAQ,IAAI,EAAE;AACpC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,WAAW,EAAE;AAAA,EAC3B;AAAA,EAEA,MAAc,iBAAgC;AAC5C,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,QAAQ,iBAAiB,GAAG,EAAE,eAAe,KAAK,CAAC;AAAA,IACrE,QAAQ;AACN;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,MACZ,QAAQ,OAAO,CAAC,UAAU,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC,UAAU,KAAK,WAAW,MAAM,IAAI,CAAC;AAAA,IAC3F;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,IAA0C;AACjE,QAAI;AACF,YAAM,CAAC,SAAS,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC3CC,UAAS,qBAAqB,EAAE,GAAG,MAAM;AAAA,QACzCA,UAAS,qBAAqB,EAAE,GAAG,MAAM;AAAA,MAC3C,CAAC;AACD,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,UAAI;AACJ,UAAI;AACJ,UAAI;AACF,mBAAW,KAAK;AAAA,UACd,MAAMA,UAAS,yBAAyB,EAAE,GAAG,MAAM;AAAA,QACrD;AAAA,MACF,QAAQ;AACN,mBAAW;AAAA,MACb;AACA,UAAI;AACF,qBAAa,KAAK;AAAA,UAChB,MAAMA,UAAS,yBAAyB,EAAE,GAAG,MAAM;AAAA,QACrD;AAAA,MACF,QAAQ;AACN,qBAAa;AAAA,MACf;AAEA,YAAM,SAAuB;AAAA,QAC3B,MAAM;AAAA,UACJ,GAAG;AAAA,UACH,aAAa,KAAK,eAAe,gBAAgB,EAAE;AAAA,UACnD,cAAc,KAAK,iBAAiB,WAAW,yBAAyB,EAAE,IAAI;AAAA,UAC9E,cAAc,KAAK,iBAAiB,WAAW,yBAAyB,EAAE,IAAI;AAAA,QAChF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,WAAK,QAAQ,IAAI,IAAI,MAAM;AAC3B,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,iBACN,QACA,IAGA;AACA,QAAI,OAAO,KAAK,WAAW,eAAe,OAAO,KAAK,WAAW,YAAY;AAC3E,YAAM,IAAI,MAAM,UAAU,EAAE,OAAO,OAAO,KAAK,MAAM,yBAAyB;AAAA,IAChF;AACA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,UAAU,EAAE,4BAA4B;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,oBACN,QACA,WACM;AACN,QAAI,CAAC,OAAO,SAAS,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,SAAS,GAAG;AACzE,YAAM,IAAI,MAAM,WAAW,SAAS,YAAY;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,QACA,YACwB;AACxB,WAAO,aAAa;AACpB,SAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,MAAM;AACvC,UAAM,eAAe,yBAAyB,OAAO,KAAK,EAAE;AAC5D,UAAM,UAAU,gBAAgB,OAAO,KAAK,EAAE,CAAC;AAC/C,UAAM,QAAQ,IAAI;AAAA,MAChBD,WAAU,cAAc,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAClEA,WAAU,qBAAqB,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IAC7F,CAAC;AACD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU,OAAO,KAAK;AAAA,MACtB,QAAQ,OAAO,KAAK;AAAA,MACpB,kBAAkB,WAAW;AAAA,MAC7B,UAAU,KAAK,iBAAiB,QAAQ,WAAW,QAAQ;AAAA,MAC3D,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBACN,UACA,QACmB;AACnB,UAAM,gBAAgB,IAAI;AAAA,MACxB,OAAO,SAAS,SAAS,IAAI,CAAC,SAAS,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAU;AAAA,IAC/E;AACA,WAAO,SACJ,OAAO,CAAC,YAAY,cAAc,IAAI,QAAQ,SAAS,CAAC,EACxD;AAAA,MACC,CAAC,GAAG,OACD,cAAc,IAAI,EAAE,SAAS,KAAK,OAAO,qBACzC,cAAc,IAAI,EAAE,SAAS,KAAK,OAAO;AAAA,IAC9C;AAAA,EACJ;AAAA,EAEQ,iBACN,QACA,UACmD;AACnD,UAAM,QAAQ,OAAO,SAAS,SAAS;AACvC,UAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,SAAS,CAAC;AACxE,UAAM,WAAW,OAAO,SAAS,SAAS;AAAA,MAAO,CAAC,YAChD,YAAY,IAAI,QAAQ,EAAE;AAAA,IAC5B,EAAE;AACF,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,MAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AACF;AAEO,IAAM,cAAc,IAAI,YAAY;;;AEnY3C,eAAsB,qBAAqB;AAAA,EACzC;AAAA,EACA;AACF,GAG0B;AACxB,MAAI,UAAU,YAAY;AACxB,QAAI;AACF,cAAQ,MAAM,IAAI,aAAa,UAAU,MAAM,CAAC,EAAE,YAAY,GAAG;AAAA,IACnE,QAAQ;AAAA,IAER;AAAA,EACF;AAEA,SAAO,IAAI,YAAY,EAAE,KAAK;AAChC;;;ATKA,SAAS,UAAU,OAAsB;AACvC,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAAA,CAAI;AAC5D;AAEA,SAAS,WAAW,OAAqB;AACvC,UAAQ,OAAO,MAAM,GAAG,KAAK;AAAA,CAAI;AACnC;AAEA,IAAM,UAAU,IAAI,QAAQ;AAE5B,QACG,KAAK,OAAO,EACZ,YAAY,yDAAyD,EACrE,QAAQ,cAAc,EACtB,OAAO,UAAU,mCAAmC,EACpD,OAAO,cAAc,sBAAsB;AAE9C,QACG,QAAQ,MAAM,EACd,YAAY,gDAAgD,EAC5D,OAAO,gBAAgB,uBAAuB,EAC9C,OAAO,eAAe,kBAAkB,EACxC,OAAO,aAAa,uBAAuB,EAC3C,OAAO,cAAc,iDAAiD,EACtE,OAAO,uBAAuB,4BAA4B,MAAM,EAChE;AAAA,EACC,OAAO,YAMD;AACJ,UAAM,UAAU,QAAQ,KAAoB;AAC5C,UAAM,OAAO,MAAM,aAAa;AAChC,UAAM,SAAS,IAAI,aAAa,UAAU,IAAI,CAAC;AAC/C,UAAM,OAAO,MAAM,YAAY,QAAQ,IAAI;AAC3C,UAAM,EAAE,MAAM,IAAI,IAAI,MAAM,OAAO,aAAa,IAAI;AAEpD,QAAI,QAAQ,UAAU;AACpB,iBAAW,GAAG;AAAA,IAChB;AACA,QAAI,QAAQ,SAAS,OAAO;AAC1B,YAAM,YAAY,GAAG;AAAA,IACvB;AAEA,QAAI,QAAQ,UAAU,OAAO;AAC3B,YAAME,UAAS;AAAA,QACb,UAAU,KAAK;AAAA,QACf;AAAA,QACA,OAAO,KAAK,MAAM;AAAA,QAClB,OAAO,KAAK,MAAM;AAAA,QAClB,aAAa,KAAK;AAAA,MACpB;AACA,cAAQ,OAAO,UAAUA,OAAM,IAAI,WAAW,UAAU,KAAK,EAAE,KAAK,GAAG,EAAE;AACzE;AAAA,IACF;AAEA,UAAM,QAAQ,MAAM,OAAO,YAAY,KAAK,IAAI,QAAQ,OAAO;AAC/D,QAAI,MAAM,SAAS,oBAAoB;AACrC,cAAQ,WAAW;AACnB,cAAQ,OAAO,UAAU,KAAK,IAAI,WAAW,UAAU,KAAK,EAAE,YAAY;AAC1E;AAAA,IACF;AACA,QAAI,MAAM,SAAS,oBAAoB;AACrC,YAAM,IAAI,MAAM,2BAA2B,MAAM,IAAI,EAAE;AAAA,IACzD;AAEA,UAAM,WAAW,MAAM,OAAO,YAAY,KAAK,EAAE;AACjD,UAAM,SAAS;AAAA,MACb,UAAU,KAAK;AAAA,MACf;AAAA,MACA,OAAO,MAAM,OAAO;AAAA,MACpB,UAAU,MAAM,OAAO;AAAA,MACvB,cAAc,yBAAyB,KAAK,EAAE;AAAA,MAC9C,cAAc,yBAAyB,KAAK,EAAE;AAAA,MAC9C,aAAa,gBAAgB,KAAK,EAAE;AAAA,MACpC;AAAA,IACF;AACA,YAAQ,OACJ,UAAU,MAAM,IAChB,WAAW,UAAU,KAAK,EAAE,mBAAmB,MAAM,OAAO,QAAQ,WAAW;AAAA,EACrF;AACF;AAEF,QACG,QAAQ,OAAO,EACf,SAAS,cAAc,WAAW,EAClC,YAAY,kDAAkD,EAC9D,OAAO,uBAAuB,4BAA4B,MAAM,EAChE,OAAO,OAAO,UAAkB,YAAkC;AACjE,QAAM,UAAU,QAAQ,KAAoB;AAC5C,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,SAAS,IAAI,aAAa,UAAU,IAAI,CAAC;AAC/C,QAAM,QAAQ,MAAM,OAAO,YAAY,UAAU,QAAQ,OAAO;AAChE,UAAQ,OAAO,UAAU,KAAK,IAAI,WAAW,GAAG,MAAM,IAAI,IAAI,MAAM,QAAQ,EAAE;AAChF,CAAC;AAEH,QACG,QAAQ,OAAO,EACf,YAAY,sCAAsC,EAClD,OAAO,iBAAiB,gBAAgB,MAAM,EAC9C,OAAO,OAAO,YAA+B;AAC5C,QAAM,UAAU,QAAQ,KAAoB;AAC5C,QAAM,OAAO,MAAM,YAAY,EAAE,MAAM,QAAQ,KAAK,CAAC;AACrD,UAAQ,OACJ,UAAU,IAAI,IACd,WAAW,2BAA2B,UAAU,IAAI,CAAC,SAAS,KAAK,GAAG,GAAG;AAC/E,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,gCAAgC,EAC5C,OAAO,YAAY;AAClB,QAAM,UAAU,QAAQ,KAAoB;AAC5C,QAAM,OAAO,MAAM,eAAe;AAClC,QAAM,aAAa,OAAO,MAAM,mBAAmB,IAAI,IAAI;AAC3D,QAAM,UAAU,MAAM,qBAAqB,EAAE,YAAY,QAAQ,KAAK,CAAC;AACvE,QAAM,SAAS,EAAE,SAAS,YAAY,QAAQ,MAAM,QAAQ;AAC5D,UAAQ,OACJ,UAAU,MAAM,IAChB;AAAA,IACE,cAAc,OACV,2BAA2B,UAAU,IAAI,CAAC,SAAS,QAAQ,MAAM,sBACjE;AAAA,EACN;AACN,CAAC;AAEH,QACG,QAAQ,MAAM,EACd,YAAY,oCAAoC,EAChD,OAAO,SAAS,0CAA0C,EAC1D,OAAO,YAAY;AAClB,QAAM,UAAU,QAAQ,KAAoB;AAC5C,QAAM,SAAS,MAAM,WAAW;AAChC,UAAQ,OACJ,UAAU,MAAM,IAChB,WAAW,OAAO,UAAU,yBAAyB,8BAA8B;AACzF,CAAC;AAEH,QACG,QAAQ,SAAS,EACjB,SAAS,cAAc,WAAW,EAClC,YAAY,6DAA6D,EACzE,OAAO,yBAAyB,wCAAwC,EACxE,OAAO,oBAAoB,oCAAoC,EAC/D,OAAO,OAAO,UAAkB,YAAoD;AACnF,QAAM,UAAU,QAAQ,KAAoB;AAC5C,QAAM,OAAO,MAAM,aAAa;AAChC,QAAM,SAAS,IAAI,aAAa,UAAU,IAAI,CAAC;AAC/C,QAAM,SAAS,QAAQ,UACnB,MAAM,OAAO,eAAe,UAAU,QAAQ,SAAS,QAAQ,OAAO,IACtE,MAAM,OAAO,aAAa,UAAU,QAAQ,OAAO;AACvD,MAAI,QAAQ,MAAM;AAChB,cAAU;AAAA,MACR,WAAW,QAAQ,WAAW;AAAA,MAC9B,SAAS,QAAQ,WAAW;AAAA,MAC5B,GAAG;AAAA,IACL,CAAC;AACD;AAAA,EACF;AACA;AAAA,IACE,QAAQ,UACJ,WAAW,QAAQ,OAAO,uBAAuB,QAAQ,KACzD,UAAU,QAAQ;AAAA,EACxB;AACF,CAAC;AAEH,QACG,QAAQ,QAAQ,EAChB,YAAY,uCAAuC,EACnD,OAAO,YAAY;AAClB,QAAM,UAAU,QAAQ,KAAoB;AAC5C,QAAM,SAAgE,CAAC;AACvE,MAAI;AACF,UAAM,mBAAmB;AACzB,WAAO,KAAK,EAAE,MAAM,OAAO,IAAI,KAAK,CAAC;AAAA,EACvC,SAAS,OAAO;AACd,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC/D,CAAC;AAAA,EACH;AACA,MAAI;AACF,UAAM,OAAO,MAAM,YAAY;AAC/B,WAAO,KAAK,EAAE,MAAM,QAAQ,IAAI,MAAM,QAAQ,KAAK,CAAC;AAAA,EACtD,SAAS,OAAO;AACd,WAAO,KAAK;AAAA,MACV,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,IAC/D,CAAC;AAAA,EACH;AACA,QAAM,OAAO,MAAM,eAAe;AAClC,SAAO,KAAK;AAAA,IACV,MAAM;AAAA,IACN,IAAI,OAAO,MAAM,mBAAmB,IAAI,IAAI;AAAA,IAC5C,QAAQ,OAAO,UAAU,IAAI,IAAI;AAAA,EACnC,CAAC;AACD,SAAO,KAAK;AAAA,IACV,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,QAAQ;AAAA,EACV,CAAC;AAED,MAAI,QAAQ,MAAM;AAChB,cAAU,EAAE,OAAO,CAAC;AAAA,EACtB,OAAO;AACL,eAAW,SAAS,QAAQ;AAC1B;AAAA,QACE,GAAG,MAAM,KAAK,OAAO,MAAM,IAAI,MAAM,IAAI,GAAG,MAAM,SAAS,MAAM,MAAM,MAAM,KAAK,EAAE;AAAA,MACtF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAEH,QAAQ,WAAW,QAAQ,IAAI,EAAE,MAAM,CAAC,UAAmB;AACzD,UAAQ,OAAO,MAAM,GAAG,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,CAAI;AAClF,UAAQ,WAAW;AACrB,CAAC;","names":["path","rawDiff","path","readFile","rm","writeFile","languageForPath","writeFile","readFile","result"]}
@@ -16,7 +16,7 @@ import path from "path";
16
16
  // package.json
17
17
  var package_default = {
18
18
  name: "getgloss",
19
- version: "0.4.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",
@@ -541,6 +541,7 @@ var reviewStore = new ReviewStore();
541
541
 
542
542
  // src/server/index.ts
543
543
  var webRoot = fileURLToPath2(new URL("../web", import.meta.url));
544
+ var eventStreamHeartbeatMs = 15e3;
544
545
  var mimeTypes = {
545
546
  ".css": "text/css; charset=utf-8",
546
547
  ".html": "text/html; charset=utf-8",
@@ -591,16 +592,44 @@ function createApp(origin2) {
591
592
  let cleanup = null;
592
593
  const stream = new ReadableStream({
593
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
+ };
594
612
  const send = (event) => {
595
- controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}
613
+ write(`data: ${JSON.stringify(event)}
596
614
 
597
- `));
615
+ `);
598
616
  if (event.type === "review.submitted" || event.type === "review.cancelled") {
599
- cleanup?.();
617
+ close();
600
618
  controller.close();
601
619
  }
602
620
  };
603
- 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
+ };
604
633
  send({ type: "review.opened", reviewId: id });
605
634
  if ((record.meta.status === "submitted" || record.meta.status === "resolved") && record.feedback) {
606
635
  send({
@@ -619,9 +648,10 @@ function createApp(origin2) {
619
648
  });
620
649
  return new Response(stream, {
621
650
  headers: {
622
- "cache-control": "no-cache",
651
+ "cache-control": "no-cache, no-transform",
623
652
  connection: "keep-alive",
624
- "content-type": "text/event-stream"
653
+ "content-type": "text/event-stream",
654
+ "x-accel-buffering": "no"
625
655
  }
626
656
  });
627
657
  });
@@ -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.4.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 \"@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));\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.submitted' || 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 === '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',\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 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":";AAAA,SAAS,aAAa;;;ACAtB,SAAS,aAAa;AACtB,SAAS,YAAY,gBAAgB;AACrC,SAAS,UAAU,IAAI,iBAAiB;AACxC,SAAS,qBAAqB;AAC9B,OAAO,aAAa;;;ACJpB,SAAS,aAAa;AACtB,SAAS,eAAe;AACxB,OAAO,UAAU;;;ACFjB;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,gBAAkB;AAAA,EAClB,KAAO;AAAA,IACL,UAAY;AAAA,IACZ,OAAS;AAAA,EACX;AAAA,EACA,OAAS;AAAA,IACP;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,aAAa;AAAA,IACb,cAAc;AAAA,IACd,OAAS;AAAA,IACT,QAAU;AAAA,IACV,SAAW;AAAA,IACX,WAAW;AAAA,IACX,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,cAAc;AAAA,EAChB;AAAA,EACA,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,cAAgB;AAAA,IACd,qBAAqB;AAAA,IACrB,iBAAiB;AAAA,IACjB,qBAAqB;AAAA,IACrB,WAAa;AAAA,IACb,OAAS;AAAA,IACT,YAAY;AAAA,IACZ,MAAQ;AAAA,IACR,gBAAgB;AAAA,IAChB,MAAQ;AAAA,IACR,OAAS;AAAA,IACT,aAAa;AAAA,IACb,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,SAAW;AAAA,EACb;AAAA,EACA,iBAAmB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,IACpB,wBAAwB;AAAA,IACxB,YAAc;AAAA,IACd,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,YAAc;AAAA,IACd,MAAQ;AAAA,IACR,QAAU;AAAA,EACZ;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAU;AAAA,EACV,SAAW;AAAA,EACX,UAAY;AAAA,EACZ,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,EACT;AAAA,EACA,MAAQ;AAAA,IACN,KAAO;AAAA,EACT;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AACF;;;ADzEO,IAAM,iBAAiB,gBAAY;AAEnC,SAAS,WAAW,OAAuB;AAChD,MAAI,UAAU,KAAK;AACjB,WAAO,QAAQ;AAAA,EACjB;AACA,MAAI,MAAM,WAAW,IAAI,GAAG;AAC1B,WAAO,KAAK,KAAK,QAAQ,GAAG,MAAM,MAAM,CAAC,CAAC;AAAA,EAC5C;AACA,SAAO;AACT;AAEO,SAAS,iBAAyB;AACvC,SAAO,WAAW,QAAQ,IAAI,mBAAmB,UAAU;AAC7D;AAEO,SAAS,mBAA2B;AACzC,SAAO,KAAK,KAAK,eAAe,GAAG,aAAa;AAClD;AAUO,SAAS,mBAA2B;AACzC,SAAO,KAAK,KAAK,eAAe,GAAG,SAAS;AAC9C;AAEO,SAAS,gBAAgB,UAA0B;AACxD,SAAO,KAAK,KAAK,iBAAiB,GAAG,QAAQ;AAC/C;AAEO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,WAAW;AACzD;AAEO,SAAS,qBAAqB,UAA0B;AAC7D,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,WAAW;AACzD;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,eAAe;AAC7D;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,aAAa;AAC3D;AAEO,SAAS,yBAAyB,UAA0B;AACjE,SAAO,KAAK,KAAK,gBAAgB,QAAQ,GAAG,eAAe;AAC7D;AAEA,eAAsB,UAAU,KAA4B;AAC1D,QAAM,MAAM,KAAK,EAAE,WAAW,KAAK,CAAC;AACtC;;;AD4CA,eAAsB,gBAAgB,MAAiC;AACrE,QAAM,UAAU,eAAe,CAAC;AAChC,QAAM,UAAU,iBAAiB,GAAG,GAAG,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAC1E;;;AG9GA,SAAS,YAAAA,iBAAgB;AACzB,OAAOC,WAAU;AACjB,SAAS,iBAAAC,sBAAqB;AAE9B,SAAS,YAAY;;;ACHrB,SAAS,SAAS,YAAAC,WAAU,MAAAC,KAAI,aAAAC,kBAAiB;AACjD,SAAS,YAAY;;;ACArB,SAAS,gBAAgB,SAA0B;AACjD,QAAM,SAAS,QAAQ;AACvB,MAAI,QAAQ,cAAc,QAAQ,SAAS;AACzC,WAAO,GAAG,MAAM,GAAG,QAAQ,SAAS;AAAA,EACtC;AACA,SAAO,GAAG,MAAM,GAAG,QAAQ,SAAS,IAAI,MAAM,GAAG,QAAQ,OAAO;AAClE;AAEA,SAAS,SAAS,SAAyB;AACzC,MAAI,QAAQ;AACZ,SAAO,QAAQ,SAAS,KAAK,GAAG;AAC9B,aAAS;AAAA,EACX;AACA,SAAO;AACT;AAEA,SAAS,gBAAgB,UAA0B;AACjD,QAAM,MAAM,SAAS,MAAM,GAAG,EAAE,IAAI,GAAG,YAAY;AACnD,QAAM,MAA8B;AAAA,IAClC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,IAAI;AAAA,IACJ,MAAM;AAAA,IACN,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,IAAI;AAAA,IACJ,KAAK;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AACA,SAAO,MAAO,IAAI,GAAG,KAAK,MAAO;AACnC;AAEA,SAAS,mBAAmB,UAAkB,SAAyB;AACrE,QAAM,QAAQ,QAAQ,MAAM,IAAI,EAAE,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC;AAClE,QAAM,uBACJ,MAAM,SAAS,KACf,MAAM,KAAK,CAAC,SAAS,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,CAAC,KACjE,MAAM,MAAM,CAAC,SAAS,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,GAAG,CAAC;AAC5F,SAAO,uBAAuB,SAAS,gBAAgB,QAAQ;AACjE;AAEA,SAAS,eAAe,GAAY,GAAoB;AACtD,SACE,EAAE,SAAS,cAAc,EAAE,QAAQ,KACnC,EAAE,YAAY,EAAE,aAChB,EAAE,UAAU,EAAE,WACd,EAAE,KAAK,cAAc,EAAE,IAAI;AAE/B;AAEO,SAAS,0BAA0B,QAAgC;AACxE,QAAM,WAAW,CAAC,GAAG,OAAO,QAAQ,EAAE,KAAK,cAAc;AACzD,QAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,QAAQ,CAAC,CAAC;AACtE,QAAM,QAAkB;AAAA,IACtB,sBAAsB,OAAO,SAAS;AAAA,IACtC,WAAW,OAAO,QAAQ;AAAA,IAC1B,SAAS,OAAO,KAAK,GAAG,KAAK,OAAO,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,cAAc,OAAO,UAAU,YAAY;AAAA,IACnG,UAAU,MAAM,MAAM,gBAAgB,SAAS,MAAM;AAAA,IACrD;AAAA,EACF;AAEA,aAAW,YAAY,OAAO;AAC5B,UAAM,KAAK,MAAM,QAAQ,IAAI,EAAE;AAC/B,eAAW,WAAW,SAAS,OAAO,CAAC,SAAS,KAAK,aAAa,QAAQ,GAAG;AAC3E,YAAM,UAAU,QAAQ,gBAAgB,QAAQ;AAChD,YAAM,mBAAmB,QAAQ,MAAM,IAAI,EAAE,KAAK,CAAC,SAAS,KAAK,KAAK,EAAE,SAAS,CAAC;AAClF,YAAM,UACJ,QAAQ,cAAc,QAAQ,WAAW,mBACrC,OAAO,gBAAgB,OAAO,CAAC,QAAQ,iBAAiB,KAAK,EAAE,MAAM,GAAG,EAAE,CAAC,OAC3E,OAAO,gBAAgB,OAAO,CAAC;AACrC,YAAM,KAAK,SAAS,QAAQ,KAAK,KAAK,GAAG,EAAE;AAC3C,UAAI,SAAS;AACX,cAAM,QAAQ,SAAS,OAAO;AAC9B,cAAM,KAAK,GAAG,KAAK,GAAG,mBAAmB,QAAQ,UAAU,OAAO,CAAC,IAAI,SAAS,OAAO,EAAE;AAAA,MAC3F;AAAA,IACF;AAAA,EACF;AAEA,SAAO,GAAG,MAAM,KAAK,IAAI,EAAE,QAAQ,CAAC;AAAA;AACtC;;;AD9DO,IAAM,cAAN,MAAkB;AAAA,EACN,UAAU,oBAAI,IAA0B;AAAA,EACxC,YAAY,oBAAI,IAA2B;AAAA,EAE5D,MAAM,OAAO,MAA0C;AACrD,UAAM,KAAK,KAAK;AAChB,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,OAAmB;AAAA,MACvB;AAAA,MACA,KAAK,KAAK;AAAA,MACV,MAAM,KAAK;AAAA,MACX,QAAQ,KAAK;AAAA,MACb,QAAQ;AAAA,MACR;AAAA,MACA,aAAa,gBAAgB,EAAE;AAAA,IACjC;AACA,UAAM,SAAuB,EAAE,MAAM,KAAK;AAC1C,SAAK,QAAQ,IAAI,IAAI,MAAM;AAC3B,UAAM,KAAK,eAAe,MAAM;AAChC,SAAK,KAAK,EAAE,MAAM,iBAAiB,UAAU,GAAG,CAAC;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAA8B;AAClC,UAAM,KAAK,eAAe;AAC1B,WAAO,CAAC,GAAG,KAAK,QAAQ,OAAO,CAAC,EAC7B,IAAI,CAAC,WAAW,OAAO,IAAI,EAC3B,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AAAA,EAC1D;AAAA,EAEA,MAAM,IAAI,IAA0C;AAClD,WAAO,KAAK,QAAQ,IAAI,EAAE,KAAM,MAAM,KAAK,gBAAgB,EAAE;AAAA,EAC/D;AAAA,EAEA,MAAM,OACJ,IACA,UAC+E;AAC/E,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,QAAI,OAAO,KAAK,WAAW,WAAW;AACpC,YAAM,IAAI,MAAM,UAAU,EAAE,OAAO,OAAO,KAAK,MAAM,0BAA0B;AAAA,IACjF;AACA,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AACzC,UAAM,WAA2B;AAAA,MAC/B,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAM,OAAO,KAAK;AAAA,MAClB,QAAQ,OAAO,KAAK;AAAA,MACpB,UAAU,CAAC,GAAG,QAAQ,EAAE;AAAA,QACtB,CAAC,GAAG,MACF,EAAE,SAAS,cAAc,EAAE,QAAQ,KACnC,EAAE,YAAY,EAAE,aAChB,EAAE,UAAU,EAAE,WACd,EAAE,KAAK,cAAc,EAAE,IAAI;AAAA,MAC/B;AAAA,IACF;AACA,WAAO,WAAW;AAClB,WAAO,OAAO,EAAE,GAAG,OAAO,MAAM,QAAQ,aAAa,aAAa,UAAU;AAC5E,SAAK,QAAQ,IAAI,IAAI,MAAM;AAE3B,UAAM,cAAc,gBAAgB,EAAE;AACtC,UAAM,eAAe,yBAAyB,EAAE;AAChD,UAAM,eAAe,yBAAyB,EAAE;AAChD,WAAO,OAAO;AAAA,MACZ,GAAG,OAAO;AAAA,MACV;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,UAAM,UAAU,WAAW;AAC3B,UAAM,QAAQ,IAAI;AAAA,MAChBC,WAAU,qBAAqB,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAC/EA,WAAU,cAAc,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAChEA,WAAU,cAAc,0BAA0B,QAAQ,CAAC;AAAA,IAC7D,CAAC;AAED,SAAK,KAAK;AAAA,MACR,MAAM;AAAA,MACN,UAAU;AAAA,MACV,QAAQ;AAAA,QACN,OAAO,IAAI,IAAI,SAAS,SAAS,IAAI,CAAC,YAAY,QAAQ,QAAQ,CAAC,EAAE;AAAA,QACrE,UAAU,SAAS,SAAS;AAAA,MAC9B;AAAA,IACF,CAAC;AACD,WAAO,EAAE,QAAQ,cAAc,aAAa;AAAA,EAC9C;AAAA,EAEA,MAAM,SAAS,IAA4C;AACzD,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,WAAO,QAAQ,YAAY;AAAA,EAC7B;AAAA,EAEA,MAAM,aAAa,IAAY,SAA0C;AACvE,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,SAAK,iBAAiB,QAAQ,EAAE;AAChC,UAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,UAAM,eAAe,IAAI;AAAA,OACtB,OAAO,YAAY,YAAY,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,QAAQ,WAAW,OAAO,CAAC;AAAA,IACnF;AACA,UAAM,WAAW,KAAK;AAAA,OACnB,OAAO,UAAU,YAAY,CAAC,GAAG,IAAI,CAAC,aAAa;AAAA,QAClD,GAAG,aAAa,IAAI,QAAQ,EAAE;AAAA,QAC9B,WAAW,QAAQ;AAAA,QACnB,QAAQ;AAAA,QACR,YAAY,aAAa,IAAI,QAAQ,EAAE,GAAG,cAAc;AAAA,MAC1D,EAAE;AAAA,MACF;AAAA,IACF;AACA,UAAM,aAA+B;AAAA,MACnC,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS,WAAW,OAAO,YAAY,WAAW;AAAA,MAClD;AAAA,MACA;AAAA,IACF;AACA,WAAO,OAAO,EAAE,GAAG,OAAO,MAAM,QAAQ,YAAY,WAAW;AAC/D,WAAO,KAAK,kBAAkB,QAAQ,UAAU;AAAA,EAClD;AAAA,EAEA,MAAM,eAAe,IAAY,WAAmB,SAA0C;AAC5F,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,SAAK,iBAAiB,QAAQ,EAAE;AAChC,SAAK,oBAAoB,QAAQ,SAAS;AAE1C,UAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC1C,UAAM,WAAW,OAAO,YAAY,SAAS,KAAK,CAAC,YAAY,QAAQ,cAAc,SAAS;AAC9F,UAAM,cAAc,WAAW,UAAU;AACzC,UAAM,cAA+B;AAAA,MACnC;AAAA,MACA,QAAQ;AAAA,MACR,GAAI,cAAc,EAAE,SAAS,YAAY,IAAI,CAAC;AAAA,MAC9C;AAAA,IACF;AACA,UAAM,WAAW,KAAK;AAAA,MACpB;AAAA,QACE,IAAI,OAAO,YAAY,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,QAAQ,cAAc,SAAS;AAAA,QAC1F;AAAA,MACF;AAAA,MACA;AAAA,IACF;AACA,UAAM,SAAS,KAAK,iBAAiB,QAAQ,QAAQ;AACrD,UAAM,gBAAgB,OAAO,UAAU,OAAO;AAC9C,UAAM,aAA+B;AAAA,MACnC,UAAU;AAAA,MACV,QAAQ,gBAAgB,aAAa;AAAA,MACrC,SAAS,gBAAiB,OAAO,YAAY,WAAW,OAAQ;AAAA,MAChE,YAAY,gBAAgB,aAAa;AAAA,MACzC;AAAA,IACF;AACA,WAAO,OAAO,gBACV,EAAE,GAAG,OAAO,MAAM,QAAQ,YAAY,WAAW,IACjD,EAAE,GAAG,OAAO,MAAM,QAAQ,aAAa,YAAY,OAAU;AACjE,WAAO,KAAK,kBAAkB,QAAQ,UAAU;AAAA,EAClD;AAAA,EAEA,MAAM,cAAc,IAAY,WAA2C;AACzE,UAAM,SAAS,MAAM,KAAK,IAAI,EAAE;AAChC,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,UAAU,EAAE,YAAY;AAAA,IAC1C;AACA,SAAK,iBAAiB,QAAQ,EAAE;AAChC,SAAK,oBAAoB,QAAQ,SAAS;AAE1C,UAAM,WAAW,KAAK;AAAA,OACnB,OAAO,YAAY,YAAY,CAAC,GAAG,OAAO,CAAC,YAAY,QAAQ,cAAc,SAAS;AAAA,MACvF;AAAA,IACF;AACA,UAAM,SAAS,KAAK,iBAAiB,QAAQ,QAAQ;AACrD,UAAM,gBAAgB,OAAO,QAAQ,KAAK,OAAO,UAAU,OAAO;AAClE,UAAM,aAAa,iBAAgB,oBAAI,KAAK,GAAE,YAAY,IAAI;AAC9D,UAAM,aAA+B;AAAA,MACnC,UAAU;AAAA,MACV,QAAQ,gBAAgB,aAAa;AAAA,MACrC,SAAS,gBAAiB,OAAO,YAAY,WAAW,OAAQ;AAAA,MAChE;AAAA,MACA;AAAA,IACF;AACA,WAAO,OAAO,gBACV,EAAE,GAAG,OAAO,MAAM,QAAQ,YAAY,YAAY,cAAc,OAAU,IAC1E,EAAE,GAAG,OAAO,MAAM,QAAQ,aAAa,YAAY,OAAU;AACjE,WAAO,KAAK,kBAAkB,QAAQ,UAAU;AAAA,EAClD;AAAA,EAEA,UAAU,UAAkB,UAAgC;AAC1D,UAAM,YAAY,KAAK,UAAU,IAAI,QAAQ,KAAK,oBAAI,IAAc;AACpE,cAAU,IAAI,QAAQ;AACtB,SAAK,UAAU,IAAI,UAAU,SAAS;AACtC,WAAO,MAAM;AACX,gBAAU,OAAO,QAAQ;AACzB,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,UAAU,OAAO,QAAQ;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,KAAK,OAA0B;AACrC,eAAW,YAAY,KAAK,UAAU,IAAI,MAAM,QAAQ,KAAK,CAAC,GAAG;AAC/D,eAAS,KAAK;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAc,eAAe,QAAqC;AAChE,UAAM,MAAM,gBAAgB,OAAO,KAAK,EAAE;AAC1C,UAAM,UAAU,GAAG;AACnB,UAAM,QAAQ,IAAI;AAAA,MAChBA,WAAU,qBAAqB,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAC3FA,WAAU,qBAAqB,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IAC7F,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,gBAAgB,IAA0C;AACtE,UAAM,WAAW,KAAK,QAAQ,IAAI,EAAE;AACpC,QAAI,UAAU;AACZ,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,WAAW,EAAE;AAAA,EAC3B;AAAA,EAEA,MAAc,iBAAgC;AAC5C,QAAI;AACJ,QAAI;AACF,gBAAU,MAAM,QAAQ,iBAAiB,GAAG,EAAE,eAAe,KAAK,CAAC;AAAA,IACrE,QAAQ;AACN;AAAA,IACF;AAEA,UAAM,QAAQ;AAAA,MACZ,QAAQ,OAAO,CAAC,UAAU,MAAM,YAAY,CAAC,EAAE,IAAI,CAAC,UAAU,KAAK,WAAW,MAAM,IAAI,CAAC;AAAA,IAC3F;AAAA,EACF;AAAA,EAEA,MAAc,WAAW,IAA0C;AACjE,QAAI;AACF,YAAM,CAAC,SAAS,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,QAC3CC,UAAS,qBAAqB,EAAE,GAAG,MAAM;AAAA,QACzCA,UAAS,qBAAqB,EAAE,GAAG,MAAM;AAAA,MAC3C,CAAC;AACD,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,UAAI;AACJ,UAAI;AACJ,UAAI;AACF,mBAAW,KAAK;AAAA,UACd,MAAMA,UAAS,yBAAyB,EAAE,GAAG,MAAM;AAAA,QACrD;AAAA,MACF,QAAQ;AACN,mBAAW;AAAA,MACb;AACA,UAAI;AACF,qBAAa,KAAK;AAAA,UAChB,MAAMA,UAAS,yBAAyB,EAAE,GAAG,MAAM;AAAA,QACrD;AAAA,MACF,QAAQ;AACN,qBAAa;AAAA,MACf;AAEA,YAAM,SAAuB;AAAA,QAC3B,MAAM;AAAA,UACJ,GAAG;AAAA,UACH,aAAa,KAAK,eAAe,gBAAgB,EAAE;AAAA,UACnD,cAAc,KAAK,iBAAiB,WAAW,yBAAyB,EAAE,IAAI;AAAA,UAC9E,cAAc,KAAK,iBAAiB,WAAW,yBAAyB,EAAE,IAAI;AAAA,QAChF;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,WAAK,QAAQ,IAAI,IAAI,MAAM;AAC3B,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,iBACN,QACA,IAGA;AACA,QAAI,OAAO,KAAK,WAAW,eAAe,OAAO,KAAK,WAAW,YAAY;AAC3E,YAAM,IAAI,MAAM,UAAU,EAAE,OAAO,OAAO,KAAK,MAAM,yBAAyB;AAAA,IAChF;AACA,QAAI,CAAC,OAAO,UAAU;AACpB,YAAM,IAAI,MAAM,UAAU,EAAE,4BAA4B;AAAA,IAC1D;AAAA,EACF;AAAA,EAEQ,oBACN,QACA,WACM;AACN,QAAI,CAAC,OAAO,SAAS,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,SAAS,GAAG;AACzE,YAAM,IAAI,MAAM,WAAW,SAAS,YAAY;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,QACA,YACwB;AACxB,WAAO,aAAa;AACpB,SAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,MAAM;AACvC,UAAM,eAAe,yBAAyB,OAAO,KAAK,EAAE;AAC5D,UAAM,UAAU,gBAAgB,OAAO,KAAK,EAAE,CAAC;AAC/C,UAAM,QAAQ,IAAI;AAAA,MAChBD,WAAU,cAAc,GAAG,KAAK,UAAU,YAAY,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,MAClEA,WAAU,qBAAqB,OAAO,KAAK,EAAE,GAAG,GAAG,KAAK,UAAU,OAAO,MAAM,MAAM,CAAC,CAAC;AAAA,CAAI;AAAA,IAC7F,CAAC;AACD,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,UAAU,OAAO,KAAK;AAAA,MACtB,QAAQ,OAAO,KAAK;AAAA,MACpB,kBAAkB,WAAW;AAAA,MAC7B,UAAU,KAAK,iBAAiB,QAAQ,WAAW,QAAQ;AAAA,MAC3D,MAAM;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,qBACN,UACA,QACmB;AACnB,UAAM,gBAAgB,IAAI;AAAA,MACxB,OAAO,SAAS,SAAS,IAAI,CAAC,SAAS,UAAU,CAAC,QAAQ,IAAI,KAAK,CAAU;AAAA,IAC/E;AACA,WAAO,SACJ,OAAO,CAAC,YAAY,cAAc,IAAI,QAAQ,SAAS,CAAC,EACxD;AAAA,MACC,CAAC,GAAG,OACD,cAAc,IAAI,EAAE,SAAS,KAAK,OAAO,qBACzC,cAAc,IAAI,EAAE,SAAS,KAAK,OAAO;AAAA,IAC9C;AAAA,EACJ;AAAA,EAEQ,iBACN,QACA,UACmD;AACnD,UAAM,QAAQ,OAAO,SAAS,SAAS;AACvC,UAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,YAAY,QAAQ,SAAS,CAAC;AACxE,UAAM,WAAW,OAAO,SAAS,SAAS;AAAA,MAAO,CAAC,YAChD,YAAY,IAAI,QAAQ,EAAE;AAAA,IAC5B,EAAE;AACF,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,MAAM,QAAQ;AAAA,IAChB;AAAA,EACF;AACF;AAEO,IAAM,cAAc,IAAI,YAAY;;;AD/X3C,IAAM,UAAUE,eAAc,IAAI,IAAI,UAAU,YAAY,GAAG,CAAC;AAEhE,IAAM,YAAoC;AAAA,EACxC,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,OAAO;AAAA,EACP,SAAS;AAAA,EACT,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,QAAQ;AACV;AAEO,SAAS,UAAUC,SAAsB;AAC9C,QAAM,MAAM,IAAI,KAAK;AAErB,MAAI,IAAI,eAAe,OAAO,MAAM;AAClC,UAAM,UAAU,MAAM,YAAY,KAAK;AACvC,WAAO,EAAE,KAAK;AAAA,MACZ,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,eAAe,QAAQ,OAAO,CAAC,WAAW,OAAO,WAAW,SAAS,EAAE;AAAA,IACzE,CAAC;AAAA,EACH,CAAC;AAED,MAAI,IAAI,gBAAgB,OAAO,MAAM,EAAE,KAAK,EAAE,SAAS,MAAM,YAAY,KAAK,EAAE,CAAC,CAAC;AAElF,MAAI,KAAK,gBAAgB,OAAO,MAAM;AACpC,UAAM,OAAQ,MAAM,EAAE,IAAI,KAAK;AAC/B,UAAM,SAAS,MAAM,YAAY,OAAO,IAAI;AAC5C,WAAO,EAAE,KAAK,EAAE,MAAM,OAAO,MAAM,KAAK,GAAGA,OAAM,WAAW,OAAO,KAAK,EAAE,GAAG,GAAG,GAAG;AAAA,EACrF,CAAC;AAED,MAAI,IAAI,oBAAoB,OAAO,MAAM;AACvC,UAAM,SAAS,MAAM,YAAY,IAAI,EAAE,IAAI,MAAM,IAAI,CAAC;AACtD,QAAI,CAAC,QAAQ;AACX,aAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,GAAG,GAAG;AAAA,IAClD;AACA,WAAO,EAAE,KAAK,MAAM;AAAA,EACtB,CAAC;AAED,MAAI,IAAI,6BAA6B,OAAO,MAAM;AAChD,UAAM,WAAW,MAAM,YAAY,SAAS,EAAE,IAAI,MAAM,IAAI,CAAC;AAC7D,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,GAAG,GAAG;AAAA,IACpD;AACA,WAAO,EAAE,KAAK,QAAQ;AAAA,EACxB,CAAC;AAED,MAAI,IAAI,2BAA2B,OAAO,MAAM;AAC9C,UAAM,KAAK,EAAE,IAAI,MAAM,IAAI;AAC3B,UAAM,SAAS,MAAM,YAAY,IAAI,EAAE;AACvC,QAAI,CAAC,QAAQ;AACX,aAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,GAAG,GAAG;AAAA,IAClD;AAEA,UAAM,UAAU,IAAI,YAAY;AAChC,QAAI,UAA+B;AACnC,UAAM,SAAS,IAAI,eAA2B;AAAA,MAC5C,MAAM,YAAY;AAChB,cAAM,OAAO,CAAC,UAAuB;AACnC,qBAAW,QAAQ,QAAQ,OAAO,SAAS,KAAK,UAAU,KAAK,CAAC;AAAA;AAAA,CAAM,CAAC;AACvE,cAAI,MAAM,SAAS,sBAAsB,MAAM,SAAS,oBAAoB;AAC1E,sBAAU;AACV,uBAAW,MAAM;AAAA,UACnB;AAAA,QACF;AACA,kBAAU,YAAY,UAAU,IAAI,IAAI;AACxC,aAAK,EAAE,MAAM,iBAAiB,UAAU,GAAG,CAAC;AAC5C,aACG,OAAO,KAAK,WAAW,eAAe,OAAO,KAAK,WAAW,eAC9D,OAAO,UACP;AACA,eAAK;AAAA,YACH,MAAM;AAAA,YACN,UAAU;AAAA,YACV,QAAQ;AAAA,cACN,OAAO,IAAI,IAAI,OAAO,SAAS,SAAS,IAAI,CAAC,YAAY,QAAQ,QAAQ,CAAC,EAAE;AAAA,cAC5E,UAAU,OAAO,SAAS,SAAS;AAAA,YACrC;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MACA,SAAS;AACP,kBAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAED,WAAO,IAAI,SAAS,QAAQ;AAAA,MAC1B,SAAS;AAAA,QACP,iBAAiB;AAAA,QACjB,YAAY;AAAA,QACZ,gBAAgB;AAAA,MAClB;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,MAAI,KAAK,2BAA2B,OAAO,MAAM;AAC/C,UAAM,KAAK,EAAE,IAAI,MAAM,IAAI;AAC3B,UAAM,WAAW,MAAM,YAAY,IAAI,EAAE;AACzC,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,GAAG,GAAG;AAAA,IAClD;AACA,QAAI,SAAS,KAAK,WAAW,WAAW;AACtC,aAAO,EAAE,KAAK,EAAE,OAAO,aAAa,SAAS,KAAK,MAAM,2BAA2B,GAAG,GAAG;AAAA,IAC3F;AACA,UAAM,OAAQ,MAAM,EAAE,IAAI,KAAK;AAC/B,UAAM,EAAE,QAAQ,cAAc,aAAa,IAAI,MAAM,YAAY;AAAA,MAC/D;AAAA,MACA,KAAK,YAAY,CAAC;AAAA,IACpB;AACA,WAAO,EAAE,KAAK;AAAA,MACZ,UAAU;AAAA,MACV,KAAK,GAAGA,OAAM,WAAW,EAAE;AAAA,MAC3B,OAAO,OAAO,KAAK,MAAM;AAAA,MACzB,UAAU,KAAK,UAAU,UAAU;AAAA,MACnC,aAAa,OAAO,KAAK;AAAA,MACzB;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH,CAAC;AAED,MAAI,KAAK,6BAA6B,OAAO,MAAM;AACjD,UAAM,KAAK,EAAE,IAAI,MAAM,IAAI;AAC3B,UAAM,WAAW,MAAM,YAAY,IAAI,EAAE;AACzC,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,GAAG,GAAG;AAAA,IAClD;AACA,QAAI,SAAS,KAAK,WAAW,eAAe,SAAS,KAAK,WAAW,YAAY;AAC/E,aAAO,EAAE,KAAK,EAAE,OAAO,aAAa,SAAS,KAAK,MAAM,0BAA0B,GAAG,GAAG;AAAA,IAC1F;AACA,QAAI,CAAC,SAAS,UAAU;AACtB,aAAO,EAAE,KAAK,EAAE,OAAO,+BAA+B,GAAG,GAAG;AAAA,IAC9D;AACA,UAAM,OAAQ,MAAM,EAAE,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACjD,WAAO,EAAE,KAAK,MAAM,YAAY,aAAa,IAAI,KAAK,OAAO,CAAC;AAAA,EAChE,CAAC;AAED,MAAI,KAAK,iDAAiD,OAAO,MAAM;AACrE,UAAM,KAAK,EAAE,IAAI,MAAM,IAAI;AAC3B,UAAM,YAAY,EAAE,IAAI,MAAM,WAAW;AACzC,UAAM,WAAW,MAAM,YAAY,IAAI,EAAE;AACzC,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,GAAG,GAAG;AAAA,IAClD;AACA,QAAI,SAAS,KAAK,WAAW,eAAe,SAAS,KAAK,WAAW,YAAY;AAC/E,aAAO,EAAE,KAAK,EAAE,OAAO,aAAa,SAAS,KAAK,MAAM,0BAA0B,GAAG,GAAG;AAAA,IAC1F;AACA,QAAI,CAAC,SAAS,UAAU,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,SAAS,GAAG;AAC5E,aAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;AAAA,IACnD;AACA,UAAM,OAAQ,MAAM,EAAE,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AACjD,WAAO,EAAE,KAAK,MAAM,YAAY,eAAe,IAAI,WAAW,KAAK,OAAO,CAAC;AAAA,EAC7E,CAAC;AAED,MAAI,OAAO,iDAAiD,OAAO,MAAM;AACvE,UAAM,KAAK,EAAE,IAAI,MAAM,IAAI;AAC3B,UAAM,YAAY,EAAE,IAAI,MAAM,WAAW;AACzC,UAAM,WAAW,MAAM,YAAY,IAAI,EAAE;AACzC,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,GAAG,GAAG;AAAA,IAClD;AACA,QAAI,SAAS,KAAK,WAAW,eAAe,SAAS,KAAK,WAAW,YAAY;AAC/E,aAAO,EAAE,KAAK,EAAE,OAAO,aAAa,SAAS,KAAK,MAAM,0BAA0B,GAAG,GAAG;AAAA,IAC1F;AACA,QAAI,CAAC,SAAS,UAAU,SAAS,KAAK,CAAC,YAAY,QAAQ,OAAO,SAAS,GAAG;AAC5E,aAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,GAAG,GAAG;AAAA,IACnD;AACA,WAAO,EAAE,KAAK,MAAM,YAAY,cAAc,IAAI,SAAS,CAAC;AAAA,EAC9D,CAAC;AAED,MAAI,IAAI,aAAa,cAAc,YAAY,UAAU,MAAM,CAAC,CAAC;AACjE,MAAI,IAAI,kBAAkB,cAAc,iBAAiB,UAAU,MAAM,CAAC,CAAC;AAC3E,MAAI,IAAI,WAAW,cAAc,UAAU,UAAU,MAAM,CAAC,CAAC;AAC7D,MAAI,IAAI,eAAe,cAAc,cAAc,UAAU,KAAK,CAAC,CAAC;AACpE,MAAI,IAAI,aAAa,cAAc,YAAY,8BAA8B,CAAC;AAC9E,MAAI,IAAI,cAAc,cAAc,aAAa,8BAA8B,CAAC;AAChF,MAAI,IAAI,aAAa,UAAU;AAC/B,MAAI,IAAI,UAAU,UAAU;AAC5B,MAAI,IAAI,WAAW,UAAU;AAC7B,MAAI,IAAI,eAAe,UAAU;AACjC,MAAI,IAAI,KAAK,UAAU;AAEvB,SAAO;AACT;AAEA,eAAe,WAAW,GAAY;AACpC,QAAM,cAAc,IAAI,IAAI,EAAE,IAAI,GAAG,EAAE,SAAS,QAAQ,eAAe,EAAE;AACzE,QAAM,aAAaC,MAAK,UAAU,WAAW,EAAE,QAAQ,qBAAqB,EAAE;AAC9E,QAAM,YAAYA,MAAK,KAAK,SAAS,UAAU,UAAU;AACzD,MAAI;AACF,UAAM,OAAO,MAAMC,UAAS,SAAS;AACrC,WAAO,IAAI,SAAS,MAAM;AAAA,MACxB,SAAS;AAAA,QACP,gBAAgB,UAAUD,MAAK,QAAQ,SAAS,CAAC,KAAK;AAAA,MACxD;AAAA,IACF,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,IAAI,SAAS,aAAa,EAAE,QAAQ,IAAI,CAAC;AAAA,EAClD;AACF;AAEA,eAAe,aAAa;AAC1B,MAAI;AACF,UAAM,OAAO,MAAMC,UAASD,MAAK,KAAK,SAAS,YAAY,CAAC;AAC5D,WAAO,IAAI,SAAS,MAAM;AAAA,MACxB,SAAS,EAAE,gBAAgB,2BAA2B;AAAA,IACxD,CAAC;AAAA,EACH,QAAQ;AACN,WAAO,IAAI,SAAS,iDAAiD,EAAE,QAAQ,IAAI,CAAC;AAAA,EACtF;AACF;AAEA,SAAS,cAAc,UAAkB,aAAqB;AAC5D,SAAO,YAAY;AACjB,QAAI;AACF,YAAM,OAAO,MAAMC,UAASD,MAAK,KAAK,SAAS,QAAQ,CAAC;AACxD,aAAO,IAAI,SAAS,MAAM;AAAA,QACxB,SAAS,EAAE,gBAAgB,YAAY;AAAA,MACzC,CAAC;AAAA,IACH,QAAQ;AACN,aAAO,IAAI,SAAS,GAAG,QAAQ,gCAAgC,EAAE,QAAQ,IAAI,CAAC;AAAA,IAChF;AAAA,EACF;AACF;;;AJpOA,IAAM,OAAO,OAAO,QAAQ,IAAI,cAAc,GAAG;AAEjD,IAAI,CAAC,MAAM;AACT,QAAM,IAAI,MAAM,wBAAwB;AAC1C;AAEA,IAAM,SAAS,oBAAoB,IAAI;AACvC,IAAM,SAAS,MAAM;AAAA,EACnB,OAAO,UAAU,MAAM,EAAE;AAAA,EACzB;AACF,CAAC;AAED,MAAM,gBAAgB;AAAA,EACpB,KAAK,QAAQ;AAAA,EACb;AAAA,EACA,SAAS;AAAA,EACT,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,EAClC,UAAU,eAAe;AAC3B,CAAC;AAED,QAAQ,GAAG,WAAW,MAAM;AAC1B,SAAO,MAAM,MAAM;AACjB,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH,CAAC;","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"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "getgloss",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Local browser-based diff review for coding-agent loops.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@10.33.2",