markdown-markdown 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/AGENT.md +47 -0
  2. package/LICENSE +21 -0
  3. package/README.md +110 -0
  4. package/dist/cli.d.ts +13 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +308 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/index.d.ts +6 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +3 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/lib/lifecycle.d.ts +18 -0
  13. package/dist/lib/lifecycle.d.ts.map +1 -0
  14. package/dist/lib/lifecycle.js +48 -0
  15. package/dist/lib/lifecycle.js.map +1 -0
  16. package/dist/lib/review.d.ts +27 -0
  17. package/dist/lib/review.d.ts.map +1 -0
  18. package/dist/lib/review.js +124 -0
  19. package/dist/lib/review.js.map +1 -0
  20. package/dist/lib/utils.d.ts +3 -0
  21. package/dist/lib/utils.d.ts.map +1 -0
  22. package/dist/lib/utils.js +6 -0
  23. package/dist/lib/utils.js.map +1 -0
  24. package/dist/server/browser.d.ts +13 -0
  25. package/dist/server/browser.d.ts.map +1 -0
  26. package/dist/server/browser.js +135 -0
  27. package/dist/server/browser.js.map +1 -0
  28. package/dist/server/runtime.d.ts +15 -0
  29. package/dist/server/runtime.d.ts.map +1 -0
  30. package/dist/server/runtime.js +69 -0
  31. package/dist/server/runtime.js.map +1 -0
  32. package/dist/server/session.d.ts +12 -0
  33. package/dist/server/session.d.ts.map +1 -0
  34. package/dist/server/session.js +61 -0
  35. package/dist/server/session.js.map +1 -0
  36. package/dist/server/tunnel.d.ts +13 -0
  37. package/dist/server/tunnel.d.ts.map +1 -0
  38. package/dist/server/tunnel.js +131 -0
  39. package/dist/server/tunnel.js.map +1 -0
  40. package/dist/types.d.ts +64 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/types.js +2 -0
  43. package/dist/types.js.map +1 -0
  44. package/dist/web/assets/_baseUniq-DWSAgCYE.js +1 -0
  45. package/dist/web/assets/arc-BLgyBygL.js +1 -0
  46. package/dist/web/assets/architectureDiagram-Q4EWVU46-WgZ5UMvM.js +36 -0
  47. package/dist/web/assets/blockDiagram-DXYQGD6D-CLfiyr9S.js +132 -0
  48. package/dist/web/assets/c4Diagram-AHTNJAMY-DetWrVzN.js +10 -0
  49. package/dist/web/assets/channel-B52zE7C-.js +1 -0
  50. package/dist/web/assets/chunk-4BX2VUAB-CwFW4HRp.js +1 -0
  51. package/dist/web/assets/chunk-4TB4RGXK-jdkxDJTI.js +206 -0
  52. package/dist/web/assets/chunk-55IACEB6-LHLQ9Mhr.js +1 -0
  53. package/dist/web/assets/chunk-EDXVE4YY-gXBG7iiV.js +1 -0
  54. package/dist/web/assets/chunk-FMBD7UC4-D0c2ufl0.js +15 -0
  55. package/dist/web/assets/chunk-OYMX7WX6-Cam5t0AC.js +231 -0
  56. package/dist/web/assets/chunk-QZHKN3VN-VDTy7PR1.js +1 -0
  57. package/dist/web/assets/chunk-YZCP3GAM-DDQlY4hF.js +1 -0
  58. package/dist/web/assets/classDiagram-6PBFFD2Q-Bn5mNtvt.js +1 -0
  59. package/dist/web/assets/classDiagram-v2-HSJHXN6E-Bn5mNtvt.js +1 -0
  60. package/dist/web/assets/clone-CWdO33LD.js +1 -0
  61. package/dist/web/assets/cose-bilkent-S5V4N54A-CydpJVOO.js +1 -0
  62. package/dist/web/assets/cytoscape.esm-DxGcaOPV.js +331 -0
  63. package/dist/web/assets/dagre-KV5264BT-DfWRqVQs.js +4 -0
  64. package/dist/web/assets/defaultLocale-DX6XiGOO.js +1 -0
  65. package/dist/web/assets/diagram-5BDNPKRD-DYocjsGb.js +10 -0
  66. package/dist/web/assets/diagram-G4DWMVQ6-BwxP9kS5.js +24 -0
  67. package/dist/web/assets/diagram-MMDJMWI5-BmV1mUfz.js +43 -0
  68. package/dist/web/assets/diagram-TYMM5635-DMUZyCDV.js +24 -0
  69. package/dist/web/assets/erDiagram-SMLLAGMA-CDgJ2VS3.js +85 -0
  70. package/dist/web/assets/flowDiagram-DWJPFMVM-aLxzOWpe.js +162 -0
  71. package/dist/web/assets/ganttDiagram-T4ZO3ILL-ct-v0U4O.js +292 -0
  72. package/dist/web/assets/gitGraphDiagram-UUTBAWPF-DJ-FLYU_.js +106 -0
  73. package/dist/web/assets/graph-DUCnU9ms.js +1 -0
  74. package/dist/web/assets/index-D7013kRO.js +492 -0
  75. package/dist/web/assets/index-Lxs7QZQJ.css +1 -0
  76. package/dist/web/assets/infoDiagram-42DDH7IO-DmMBz9mk.js +2 -0
  77. package/dist/web/assets/init-Gi6I4Gst.js +1 -0
  78. package/dist/web/assets/ishikawaDiagram-UXIWVN3A-D-dfZT_7.js +70 -0
  79. package/dist/web/assets/journeyDiagram-VCZTEJTY-DCLyO8ny.js +139 -0
  80. package/dist/web/assets/kanban-definition-6JOO6SKY-DaSer7-n.js +89 -0
  81. package/dist/web/assets/katex-DkKDou_j.js +257 -0
  82. package/dist/web/assets/layout-BaZRT940.js +1 -0
  83. package/dist/web/assets/linear-CH1vCRmv.js +1 -0
  84. package/dist/web/assets/min-C200fz71.js +1 -0
  85. package/dist/web/assets/mindmap-definition-QFDTVHPH-CCqZjE9I.js +96 -0
  86. package/dist/web/assets/ordinal-Cboi1Yqb.js +1 -0
  87. package/dist/web/assets/pieDiagram-DEJITSTG-Beh4XRu6.js +30 -0
  88. package/dist/web/assets/quadrantDiagram-34T5L4WZ-DOPc33qF.js +7 -0
  89. package/dist/web/assets/requirementDiagram-MS252O5E-DwblBLZK.js +84 -0
  90. package/dist/web/assets/sankeyDiagram-XADWPNL6-DlMTDWAl.js +10 -0
  91. package/dist/web/assets/sequenceDiagram-FGHM5R23-CPvNK8NS.js +157 -0
  92. package/dist/web/assets/stateDiagram-FHFEXIEX-C51anF0K.js +1 -0
  93. package/dist/web/assets/stateDiagram-v2-QKLJ7IA2-DgIcCuV2.js +1 -0
  94. package/dist/web/assets/timeline-definition-GMOUNBTQ-B0M6txNM.js +120 -0
  95. package/dist/web/assets/vennDiagram-DHZGUBPP-DuNg6iKA.js +34 -0
  96. package/dist/web/assets/wardley-RL74JXVD-CnLmvQxW.js +162 -0
  97. package/dist/web/assets/wardleyDiagram-NUSXRM2D-DVMWnQbQ.js +20 -0
  98. package/dist/web/assets/xychartDiagram-5P7HB3ND-Cec8luZO.js +7 -0
  99. package/dist/web/index.html +14 -0
  100. package/package.json +67 -0
@@ -0,0 +1,124 @@
1
+ function normalizeWhitespace(text) {
2
+ return text.replace(/\s+/g, ' ').trim();
3
+ }
4
+ function escapeForQuotes(text) {
5
+ return text.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
6
+ }
7
+ function truncateMiddle(text, maxLength) {
8
+ const compact = normalizeWhitespace(text);
9
+ if (compact.length <= maxLength) {
10
+ return compact;
11
+ }
12
+ const headLength = Math.max(18, Math.floor(maxLength * 0.6));
13
+ const tailLength = Math.max(10, maxLength - headLength - 1);
14
+ return `${compact.slice(0, headLength).trimEnd()}…${compact.slice(-tailLength).trimStart()}`;
15
+ }
16
+ function getMeaningfulLines(selectedText) {
17
+ return selectedText
18
+ .split('\n')
19
+ .map((line) => line.trim())
20
+ .filter((line) => line.length > 0);
21
+ }
22
+ function classifySelectedText(selectedText) {
23
+ const lines = getMeaningfulLines(selectedText);
24
+ const firstLine = lines[0] ?? '';
25
+ if (/^```/.test(firstLine)) {
26
+ return 'code block';
27
+ }
28
+ if (/^!\[[^\]]*\]\(/.test(firstLine)) {
29
+ return 'image';
30
+ }
31
+ if (/^#{1,6}\s/.test(firstLine)) {
32
+ return 'heading';
33
+ }
34
+ if (/^>\s?/.test(firstLine)) {
35
+ return 'blockquote';
36
+ }
37
+ if (/^([-*+]\s|\d+[.)]\s)/.test(firstLine)) {
38
+ return 'list item';
39
+ }
40
+ if (/^\s*[-*_]{3,}\s*$/.test(firstLine)) {
41
+ return 'separator';
42
+ }
43
+ if (lines.length >= 2 && lines.every((line) => line.includes('|'))) {
44
+ return 'table';
45
+ }
46
+ return 'paragraph';
47
+ }
48
+ function formatSnippet(selectedText, kind) {
49
+ const lines = getMeaningfulLines(selectedText);
50
+ if (lines.length === 0) {
51
+ return '';
52
+ }
53
+ if (kind === 'image') {
54
+ const altMatch = lines[0].match(/!\[([^\]]*)\]/);
55
+ if (altMatch?.[1]) {
56
+ return `image alt: "${escapeForQuotes(truncateMiddle(altMatch[1], 48))}"`;
57
+ }
58
+ return truncateMiddle(lines[0], 48);
59
+ }
60
+ if (kind === 'separator') {
61
+ return truncateMiddle(lines[0], 24);
62
+ }
63
+ if (kind === 'code block') {
64
+ const bodyLines = lines.filter((line) => !/^```/.test(line));
65
+ const firstLine = bodyLines[0] ?? lines[0];
66
+ const lastLine = bodyLines[bodyLines.length - 1] ?? firstLine;
67
+ if (bodyLines.length <= 1 || firstLine === lastLine) {
68
+ return truncateMiddle(firstLine, 44);
69
+ }
70
+ return `${truncateMiddle(firstLine, 34)} … ${truncateMiddle(lastLine, 34)}`;
71
+ }
72
+ if (kind === 'table') {
73
+ const firstRow = lines[0];
74
+ const lastRow = lines[lines.length - 1];
75
+ if (firstRow === lastRow) {
76
+ return truncateMiddle(firstRow, 48);
77
+ }
78
+ return `${truncateMiddle(firstRow, 34)} … ${truncateMiddle(lastRow, 34)}`;
79
+ }
80
+ if (kind === 'heading' || kind === 'blockquote' || kind === 'list item') {
81
+ const firstLine = lines[0];
82
+ const lastLine = lines[lines.length - 1];
83
+ if (firstLine === lastLine) {
84
+ return truncateMiddle(firstLine, 46);
85
+ }
86
+ return `${truncateMiddle(firstLine, 34)} … ${truncateMiddle(lastLine, 34)}`;
87
+ }
88
+ const firstLine = lines[0];
89
+ const lastLine = lines[lines.length - 1];
90
+ if (firstLine === lastLine) {
91
+ return truncateMiddle(firstLine, 48);
92
+ }
93
+ return `${truncateMiddle(firstLine, 34)} … ${truncateMiddle(lastLine, 34)}`;
94
+ }
95
+ export function buildReviewPrompt({ rootPath, files, annotations }) {
96
+ const sections = files
97
+ .map((file) => {
98
+ const fileAnnotations = annotations.filter((annotation) => annotation.filePath === file.relativePath);
99
+ if (fileAnnotations.length === 0) {
100
+ return null;
101
+ }
102
+ const lines = [`## ${file.relativePath} (${fileAnnotations.length} notes)`];
103
+ for (const annotation of fileAnnotations) {
104
+ const kind = classifySelectedText(annotation.selectedText);
105
+ const snippet = formatSnippet(annotation.selectedText, kind);
106
+ const note = annotation.note.trim();
107
+ const detail = snippet ? ` · anchor: "${escapeForQuotes(snippet)}"` : '';
108
+ lines.push(`- L${annotation.selection.startLine}-L${annotation.selection.endLine} · ${kind}${detail} -> ${note}`);
109
+ }
110
+ return lines.join('\n');
111
+ })
112
+ .filter((section) => Boolean(section));
113
+ const header = [
114
+ `Review notes for ${rootPath}`,
115
+ '',
116
+ 'Use the file path, line range, and short anchor text to update the markdown files. Keep edits surgical.',
117
+ '',
118
+ ];
119
+ if (sections.length === 0) {
120
+ return [...header, 'No annotations were submitted.'].join('\n');
121
+ }
122
+ return [...header, ...sections].join('\n');
123
+ }
124
+ //# sourceMappingURL=review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/lib/review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type ClassValue } from "clsx";
2
+ export declare function cn(...inputs: ClassValue[]): string;
3
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAG7C,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAEzC"}
@@ -0,0 +1,6 @@
1
+ import { clsx } from "clsx";
2
+ import { twMerge } from "tailwind-merge";
3
+ export function cn(...inputs) {
4
+ return twMerge(clsx(inputs));
5
+ }
6
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAmB,MAAM,MAAM,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAEzC,MAAM,UAAU,EAAE,CAAC,GAAG,MAAoB;IACxC,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ export interface BrowserHandle {
3
+ process: ChildProcess | null;
4
+ browserName: string;
5
+ userDataDir: string | null;
6
+ close: () => Promise<void>;
7
+ }
8
+ export interface LaunchBrowserOptions {
9
+ executableCandidates?: string[];
10
+ allowSystemFallback?: boolean;
11
+ }
12
+ export declare function launchBrowser(url: string, options?: LaunchBrowserOptions): Promise<BrowserHandle>;
13
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/server/browser.ts"],"names":[],"mappings":"AAEA,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIzE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AA8ED,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,aAAa,CAAC,CAsE3G"}
@@ -0,0 +1,135 @@
1
+ import { mkdtempSync, rmSync } from 'node:fs';
2
+ import { existsSync } from 'node:fs';
3
+ import { spawn, spawnSync } from 'node:child_process';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ const BROWSER_CANDIDATES = {
7
+ darwin: [
8
+ '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
9
+ '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
10
+ '/Applications/Chromium.app/Contents/MacOS/Chromium',
11
+ 'google-chrome',
12
+ 'google-chrome-stable',
13
+ 'chromium',
14
+ 'chromium-browser',
15
+ 'microsoft-edge',
16
+ ],
17
+ linux: [
18
+ 'google-chrome',
19
+ 'google-chrome-stable',
20
+ 'chromium',
21
+ 'chromium-browser',
22
+ 'microsoft-edge',
23
+ 'brave-browser',
24
+ ],
25
+ win32: [
26
+ 'chrome.exe',
27
+ 'msedge.exe',
28
+ 'chromium.exe',
29
+ ],
30
+ aix: [],
31
+ android: [],
32
+ freebsd: [],
33
+ haiku: [],
34
+ illumos: [],
35
+ netbsd: [],
36
+ openbsd: [],
37
+ sunos: [],
38
+ };
39
+ function commandExists(command) {
40
+ if (path.isAbsolute(command)) {
41
+ return existsSync(command);
42
+ }
43
+ const result = spawnSync(command, ['--version'], { stdio: 'ignore' });
44
+ return result.status === 0 || result.status === 1;
45
+ }
46
+ function pickBrowserExecutable() {
47
+ for (const candidate of BROWSER_CANDIDATES[process.platform] ?? []) {
48
+ if (commandExists(candidate)) {
49
+ return candidate;
50
+ }
51
+ }
52
+ return null;
53
+ }
54
+ async function killBrowserProcess(processHandle) {
55
+ if (!processHandle?.pid) {
56
+ return;
57
+ }
58
+ if (process.platform === 'win32') {
59
+ spawnSync('taskkill', ['/pid', String(processHandle.pid), '/t', '/f'], {
60
+ stdio: 'ignore',
61
+ });
62
+ return;
63
+ }
64
+ try {
65
+ process.kill(-processHandle.pid, 'SIGTERM');
66
+ }
67
+ catch {
68
+ try {
69
+ processHandle.kill('SIGTERM');
70
+ }
71
+ catch {
72
+ // Ignore shutdown errors; we already tried the best-effort path.
73
+ }
74
+ }
75
+ }
76
+ export async function launchBrowser(url, options = {}) {
77
+ const executable = options.executableCandidates
78
+ ? options.executableCandidates.find((candidate) => commandExists(candidate)) ?? null
79
+ : pickBrowserExecutable();
80
+ if (!executable) {
81
+ if (options.allowSystemFallback === false) {
82
+ throw new Error('No supported browser launcher was found on this system.');
83
+ }
84
+ if (process.platform === 'darwin' && commandExists('open')) {
85
+ spawn('open', [url], { stdio: 'ignore', detached: true }).unref();
86
+ return {
87
+ process: null,
88
+ browserName: 'system-default',
89
+ userDataDir: null,
90
+ close: async () => { },
91
+ };
92
+ }
93
+ if (process.platform === 'win32' && commandExists('cmd')) {
94
+ spawn('cmd', ['/c', 'start', '""', url], { stdio: 'ignore', detached: true }).unref();
95
+ return {
96
+ process: null,
97
+ browserName: 'system-default',
98
+ userDataDir: null,
99
+ close: async () => { },
100
+ };
101
+ }
102
+ if (commandExists('xdg-open')) {
103
+ spawn('xdg-open', [url], { stdio: 'ignore', detached: true }).unref();
104
+ return {
105
+ process: null,
106
+ browserName: 'system-default',
107
+ userDataDir: null,
108
+ close: async () => { },
109
+ };
110
+ }
111
+ throw new Error('No supported browser launcher was found on this system.');
112
+ }
113
+ const userDataDir = mkdtempSync(path.join(os.tmpdir(), 'markdown-markdown-browser-'));
114
+ const childProcess = spawn(executable, [
115
+ `--app=${url}`,
116
+ `--user-data-dir=${userDataDir}`,
117
+ '--no-first-run',
118
+ '--disable-extensions',
119
+ '--disable-session-crashed-bubble',
120
+ ], {
121
+ detached: true,
122
+ stdio: 'ignore',
123
+ });
124
+ childProcess.unref();
125
+ return {
126
+ process: childProcess,
127
+ browserName: path.basename(executable),
128
+ userDataDir,
129
+ close: async () => {
130
+ await killBrowserProcess(childProcess);
131
+ rmSync(userDataDir, { recursive: true, force: true });
132
+ },
133
+ };
134
+ }
135
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/server/browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { MarkdownFile, ReviewSubmissionResult } from '../types.js';
2
+ export interface ReviewRuntimeOptions {
3
+ rootPath: string;
4
+ mode: 'file' | 'directory';
5
+ files: MarkdownFile[];
6
+ staticDir: string;
7
+ }
8
+ export interface ReviewRuntimeHandle {
9
+ port: number;
10
+ url: string;
11
+ result: Promise<ReviewSubmissionResult>;
12
+ close: () => Promise<void>;
13
+ }
14
+ export declare function startReviewRuntime({ rootPath, mode, files, staticDir, }: ReviewRuntimeOptions): Promise<ReviewRuntimeHandle>;
15
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/server/runtime.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,YAAY,EAGZ,sBAAsB,EACvB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;IACxC,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAiBD,wBAAsB,kBAAkB,CAAC,EACvC,QAAQ,EACR,IAAI,EACJ,KAAK,EACL,SAAS,GACV,EAAE,oBAAoB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA8DrD"}
@@ -0,0 +1,69 @@
1
+ import express from 'express';
2
+ import { createServer } from 'node:http';
3
+ import path from 'node:path';
4
+ import { buildReviewPrompt } from '../lib/review.js';
5
+ function listen(server) {
6
+ return new Promise((resolve, reject) => {
7
+ server.once('error', reject);
8
+ server.listen(0, '127.0.0.1', () => {
9
+ const address = server.address();
10
+ if (typeof address === 'object' && address) {
11
+ resolve(address.port);
12
+ return;
13
+ }
14
+ reject(new Error('Unable to determine review server port.'));
15
+ });
16
+ });
17
+ }
18
+ export async function startReviewRuntime({ rootPath, mode, files, staticDir, }) {
19
+ const app = express();
20
+ app.use(express.json({ limit: '2mb' }));
21
+ const sessionData = {
22
+ rootPath,
23
+ mode,
24
+ files,
25
+ annotations: [],
26
+ };
27
+ let resolvedResult = null;
28
+ let resolveResult = () => { };
29
+ const result = new Promise((resolve) => {
30
+ resolveResult = resolve;
31
+ });
32
+ app.get('/api/session', (_request, response) => {
33
+ response.json(sessionData);
34
+ });
35
+ app.post('/api/submit', (request, response) => {
36
+ if (resolvedResult) {
37
+ response.json(resolvedResult);
38
+ return;
39
+ }
40
+ const body = request.body;
41
+ const annotations = Array.isArray(body?.annotations) ? body.annotations : [];
42
+ const submittedAt = new Date().toISOString();
43
+ const prompt = buildReviewPrompt({ rootPath, files, annotations });
44
+ resolvedResult = {
45
+ ...sessionData,
46
+ annotations,
47
+ prompt,
48
+ submittedAt,
49
+ };
50
+ response.json(resolvedResult);
51
+ resolveResult(resolvedResult);
52
+ });
53
+ app.use(express.static(staticDir));
54
+ app.get('*', (_request, response) => {
55
+ response.sendFile(path.join(staticDir, 'index.html'));
56
+ });
57
+ const server = createServer(app);
58
+ const port = await listen(server);
59
+ const url = `http://127.0.0.1:${port}`;
60
+ return {
61
+ port,
62
+ url,
63
+ result,
64
+ close: () => new Promise((resolve) => {
65
+ server.close(() => resolve());
66
+ }),
67
+ };
68
+ }
69
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/server/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { buildReviewPrompt } from '../lib/review.js';
2
+ export interface MarkdownSource {
3
+ id: string;
4
+ name: string;
5
+ absolutePath: string;
6
+ relativePath: string;
7
+ content: string;
8
+ lineCount: number;
9
+ }
10
+ export declare function discoverMarkdownFiles(targetPath: string): Promise<MarkdownSource[]>;
11
+ export { buildReviewPrompt };
12
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;CACnB;AA0DD,wBAAsB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAazF;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { readdir, readFile, stat } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { buildReviewPrompt } from '../lib/review.js';
4
+ const MARKDOWN_EXTENSIONS = new Set(['.md', '.markdown']);
5
+ const SKIP_DIRECTORIES = new Set(['.git', 'node_modules', 'dist', 'coverage']);
6
+ function isMarkdownFile(fileName) {
7
+ return MARKDOWN_EXTENSIONS.has(path.extname(fileName).toLowerCase());
8
+ }
9
+ function toPosixRelativePath(filePath) {
10
+ return filePath.split(path.sep).join('/');
11
+ }
12
+ function countLines(content) {
13
+ if (content.length === 0) {
14
+ return 0;
15
+ }
16
+ return content.split('\n').length;
17
+ }
18
+ async function readMarkdownSource(rootPath, absolutePath) {
19
+ const content = await readFile(absolutePath, 'utf8');
20
+ const relativePath = toPosixRelativePath(path.relative(rootPath, absolutePath));
21
+ const name = path.basename(absolutePath);
22
+ return {
23
+ id: relativePath,
24
+ name,
25
+ absolutePath,
26
+ relativePath,
27
+ content,
28
+ lineCount: countLines(content),
29
+ };
30
+ }
31
+ async function walkMarkdownDirectory(rootPath, currentPath) {
32
+ const entries = await readdir(currentPath, { withFileTypes: true });
33
+ const collected = [];
34
+ for (const entry of entries) {
35
+ if (entry.isDirectory()) {
36
+ if (SKIP_DIRECTORIES.has(entry.name) || entry.name.startsWith('.')) {
37
+ continue;
38
+ }
39
+ const nested = await walkMarkdownDirectory(rootPath, path.join(currentPath, entry.name));
40
+ collected.push(...nested);
41
+ continue;
42
+ }
43
+ if (entry.isFile() && isMarkdownFile(entry.name)) {
44
+ collected.push(await readMarkdownSource(rootPath, path.join(currentPath, entry.name)));
45
+ }
46
+ }
47
+ return collected;
48
+ }
49
+ export async function discoverMarkdownFiles(targetPath) {
50
+ const targetStat = await stat(targetPath);
51
+ if (targetStat.isFile()) {
52
+ if (!isMarkdownFile(targetPath)) {
53
+ return [];
54
+ }
55
+ return [await readMarkdownSource(path.dirname(targetPath), targetPath)];
56
+ }
57
+ const files = await walkMarkdownDirectory(targetPath, targetPath);
58
+ return files.sort((left, right) => left.relativePath.localeCompare(right.relativePath));
59
+ }
60
+ export { buildReviewPrompt };
61
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type ChildProcess } from 'node:child_process';
2
+ export interface CloudflaredTunnelHandle {
3
+ process: ChildProcess | null;
4
+ publicUrl: string;
5
+ close: () => Promise<void>;
6
+ }
7
+ export interface LaunchCloudflaredTunnelOptions {
8
+ executableCandidates?: string[];
9
+ timeoutMs?: number;
10
+ }
11
+ export declare function hasCloudflaredExecutable(): boolean;
12
+ export declare function launchCloudflaredTunnel(localUrl: string, options?: LaunchCloudflaredTunnelOptions): Promise<CloudflaredTunnelHandle | null>;
13
+ //# sourceMappingURL=tunnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../src/server/tunnel.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGzE,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,8BAA8B;IAC7C,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6BD,wBAAgB,wBAAwB,IAAI,OAAO,CAElD;AAwDD,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,8BAAmC,GAC3C,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAqEzC"}
@@ -0,0 +1,131 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { spawn, spawnSync } from 'node:child_process';
3
+ import path from 'node:path';
4
+ const TUNNEL_CANDIDATES = {
5
+ darwin: ['cloudflared', '/opt/homebrew/bin/cloudflared', '/usr/local/bin/cloudflared'],
6
+ linux: ['cloudflared'],
7
+ win32: ['cloudflared.exe'],
8
+ aix: [],
9
+ android: [],
10
+ freebsd: [],
11
+ haiku: [],
12
+ illumos: [],
13
+ netbsd: [],
14
+ openbsd: [],
15
+ sunos: [],
16
+ };
17
+ function commandExists(command) {
18
+ if (path.isAbsolute(command)) {
19
+ return existsSync(command);
20
+ }
21
+ const result = spawnSync(command, ['--version'], { stdio: 'ignore' });
22
+ return result.status === 0 || result.status === 1;
23
+ }
24
+ function pickTunnelExecutable(candidates) {
25
+ return candidates.find((candidate) => commandExists(candidate)) ?? null;
26
+ }
27
+ export function hasCloudflaredExecutable() {
28
+ return pickTunnelExecutable(TUNNEL_CANDIDATES[process.platform] ?? []) !== null;
29
+ }
30
+ function extractPublicUrl(output) {
31
+ const match = output.match(/https:\/\/[^\s"'`]+\.trycloudflare\.com/);
32
+ return match?.[0] ?? null;
33
+ }
34
+ function stopProcess(childProcess) {
35
+ return new Promise((resolve) => {
36
+ if (!childProcess?.pid) {
37
+ resolve();
38
+ return;
39
+ }
40
+ let settled = false;
41
+ const finish = () => {
42
+ if (settled) {
43
+ return;
44
+ }
45
+ settled = true;
46
+ childProcess.off('exit', finish);
47
+ childProcess.off('close', finish);
48
+ resolve();
49
+ };
50
+ if (childProcess.exitCode !== null || childProcess.signalCode !== null) {
51
+ resolve();
52
+ return;
53
+ }
54
+ childProcess.once('exit', finish);
55
+ childProcess.once('close', finish);
56
+ try {
57
+ childProcess.kill('SIGTERM');
58
+ }
59
+ catch {
60
+ finish();
61
+ return;
62
+ }
63
+ const timeout = setTimeout(() => {
64
+ if (childProcess.exitCode === null && childProcess.signalCode === null) {
65
+ try {
66
+ childProcess.kill('SIGKILL');
67
+ }
68
+ catch {
69
+ // Ignore shutdown errors; the process is already on the way out.
70
+ }
71
+ }
72
+ }, 2000);
73
+ timeout.unref();
74
+ });
75
+ }
76
+ export async function launchCloudflaredTunnel(localUrl, options = {}) {
77
+ const executable = options.executableCandidates
78
+ ? pickTunnelExecutable(options.executableCandidates)
79
+ : pickTunnelExecutable(TUNNEL_CANDIDATES[process.platform] ?? []);
80
+ if (!executable) {
81
+ return null;
82
+ }
83
+ const childProcess = spawn(executable, ['tunnel', '--url', localUrl], {
84
+ stdio: ['ignore', 'pipe', 'pipe'],
85
+ });
86
+ const timeoutMs = options.timeoutMs ?? 15_000;
87
+ const bufferedOutput = [];
88
+ const publicUrlPromise = new Promise((resolve, reject) => {
89
+ const timer = setTimeout(() => {
90
+ reject(new Error('Timed out waiting for cloudflared to report a public URL.'));
91
+ }, timeoutMs);
92
+ timer.unref();
93
+ const resolveFromChunk = (chunk) => {
94
+ const text = chunk.toString();
95
+ bufferedOutput.push(text);
96
+ const publicUrl = extractPublicUrl(bufferedOutput.join(''));
97
+ if (publicUrl) {
98
+ clearTimeout(timer);
99
+ resolve(publicUrl);
100
+ }
101
+ };
102
+ childProcess.stdout?.on('data', resolveFromChunk);
103
+ childProcess.stderr?.on('data', resolveFromChunk);
104
+ childProcess.once('error', (error) => {
105
+ clearTimeout(timer);
106
+ reject(error);
107
+ });
108
+ childProcess.once('close', () => {
109
+ clearTimeout(timer);
110
+ const publicUrl = extractPublicUrl(bufferedOutput.join(''));
111
+ if (publicUrl) {
112
+ resolve(publicUrl);
113
+ return;
114
+ }
115
+ reject(new Error('cloudflared exited before reporting a public URL.'));
116
+ });
117
+ });
118
+ try {
119
+ const publicUrl = await publicUrlPromise;
120
+ return {
121
+ process: childProcess,
122
+ publicUrl,
123
+ close: () => stopProcess(childProcess),
124
+ };
125
+ }
126
+ catch {
127
+ await stopProcess(childProcess);
128
+ return null;
129
+ }
130
+ }
131
+ //# sourceMappingURL=tunnel.js.map