aicodeman 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/README.md +2 -1
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +27 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/config/dependency-registry.d.ts +42 -0
  6. package/dist/config/dependency-registry.d.ts.map +1 -0
  7. package/dist/config/dependency-registry.js +104 -0
  8. package/dist/config/dependency-registry.js.map +1 -0
  9. package/dist/document-conversion-limiter.d.ts +27 -0
  10. package/dist/document-conversion-limiter.d.ts.map +1 -0
  11. package/dist/document-conversion-limiter.js +64 -0
  12. package/dist/document-conversion-limiter.js.map +1 -0
  13. package/dist/document-preview-cache.d.ts +15 -0
  14. package/dist/document-preview-cache.d.ts.map +1 -0
  15. package/dist/document-preview-cache.js +261 -0
  16. package/dist/document-preview-cache.js.map +1 -0
  17. package/dist/document-thumbnailer.d.ts +9 -0
  18. package/dist/document-thumbnailer.d.ts.map +1 -0
  19. package/dist/document-thumbnailer.js +70 -0
  20. package/dist/document-thumbnailer.js.map +1 -0
  21. package/dist/hooks-config.d.ts +34 -0
  22. package/dist/hooks-config.d.ts.map +1 -1
  23. package/dist/hooks-config.js +203 -73
  24. package/dist/hooks-config.js.map +1 -1
  25. package/dist/image-watcher.d.ts.map +1 -1
  26. package/dist/image-watcher.js +2 -6
  27. package/dist/image-watcher.js.map +1 -1
  28. package/dist/session-attachment-history.d.ts +19 -0
  29. package/dist/session-attachment-history.d.ts.map +1 -0
  30. package/dist/session-attachment-history.js +63 -0
  31. package/dist/session-attachment-history.js.map +1 -0
  32. package/dist/session.d.ts +10 -0
  33. package/dist/session.d.ts.map +1 -1
  34. package/dist/session.js +27 -0
  35. package/dist/session.js.map +1 -1
  36. package/dist/types/session.d.ts +35 -0
  37. package/dist/types/session.d.ts.map +1 -1
  38. package/dist/types/session.js.map +1 -1
  39. package/dist/usage-telemetry.d.ts +102 -0
  40. package/dist/usage-telemetry.d.ts.map +1 -0
  41. package/dist/usage-telemetry.js +130 -0
  42. package/dist/usage-telemetry.js.map +1 -0
  43. package/dist/utils/dependency-checker.d.ts +42 -0
  44. package/dist/utils/dependency-checker.d.ts.map +1 -0
  45. package/dist/utils/dependency-checker.js +167 -0
  46. package/dist/utils/dependency-checker.js.map +1 -0
  47. package/dist/utils/dependency-report.d.ts +26 -0
  48. package/dist/utils/dependency-report.d.ts.map +1 -0
  49. package/dist/utils/dependency-report.js +68 -0
  50. package/dist/utils/dependency-report.js.map +1 -0
  51. package/dist/web/middleware/auth.d.ts +4 -8
  52. package/dist/web/middleware/auth.d.ts.map +1 -1
  53. package/dist/web/middleware/auth.js +18 -25
  54. package/dist/web/middleware/auth.js.map +1 -1
  55. package/dist/web/plan-usage-latest.d.ts +15 -0
  56. package/dist/web/plan-usage-latest.d.ts.map +1 -0
  57. package/dist/web/plan-usage-latest.js +20 -0
  58. package/dist/web/plan-usage-latest.js.map +1 -0
  59. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  60. package/dist/web/public/app.92f49a9d.js +37 -0
  61. package/dist/web/public/app.92f49a9d.js.br +0 -0
  62. package/dist/web/public/app.92f49a9d.js.gz +0 -0
  63. package/dist/web/public/{constants.aa510a4d.js → constants.59faac65.js} +16 -0
  64. package/dist/web/public/constants.59faac65.js.br +0 -0
  65. package/dist/web/public/constants.59faac65.js.gz +0 -0
  66. package/dist/web/public/image-input.0ea86695.js.gz +0 -0
  67. package/dist/web/public/index.html +40 -27
  68. package/dist/web/public/index.html.br +0 -0
  69. package/dist/web/public/index.html.gz +0 -0
  70. package/dist/web/public/input-cjk.b8686b5e.js.gz +0 -0
  71. package/dist/web/public/keyboard-accessory.bc753cc7.js.gz +0 -0
  72. package/dist/web/public/{mobile-handlers.763a7439.js → mobile-handlers.db3dc3c8.js} +3 -0
  73. package/dist/web/public/mobile-handlers.db3dc3c8.js.br +0 -0
  74. package/dist/web/public/mobile-handlers.db3dc3c8.js.gz +0 -0
  75. package/dist/web/public/mobile.06b38d3a.css +1 -0
  76. package/dist/web/public/mobile.06b38d3a.css.br +0 -0
  77. package/dist/web/public/mobile.06b38d3a.css.gz +0 -0
  78. package/dist/web/public/notification-manager.9c984ac2.js.gz +0 -0
  79. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  80. package/dist/web/public/{panels-ui.ba0b0f1a.js → panels-ui.2f467969.js} +141 -87
  81. package/dist/web/public/panels-ui.2f467969.js.br +0 -0
  82. package/dist/web/public/panels-ui.2f467969.js.gz +0 -0
  83. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  84. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  85. package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
  86. package/dist/web/public/sanitize-html.bc7078d6.js +1 -0
  87. package/dist/web/public/sanitize-html.bc7078d6.js.br +0 -0
  88. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  89. package/dist/web/public/session-ui.1463b824.js +36 -0
  90. package/dist/web/public/session-ui.1463b824.js.br +0 -0
  91. package/dist/web/public/session-ui.1463b824.js.gz +0 -0
  92. package/dist/web/public/settings-ui.44b99ce0.js +55 -0
  93. package/dist/web/public/settings-ui.44b99ce0.js.br +0 -0
  94. package/dist/web/public/settings-ui.44b99ce0.js.gz +0 -0
  95. package/dist/web/public/styles.8e1ea0c6.css +1 -0
  96. package/dist/web/public/styles.8e1ea0c6.css.br +0 -0
  97. package/dist/web/public/styles.8e1ea0c6.css.gz +0 -0
  98. package/dist/web/public/subagent-windows.a366a4ad.js.gz +0 -0
  99. package/dist/web/public/sw.js.gz +0 -0
  100. package/dist/web/public/terminal-ui.a7e046da.js +3 -0
  101. package/dist/web/public/terminal-ui.a7e046da.js.br +0 -0
  102. package/dist/web/public/terminal-ui.a7e046da.js.gz +0 -0
  103. package/dist/web/public/upload.html.gz +0 -0
  104. package/dist/web/public/vendor/dompurify.min.js +3 -0
  105. package/dist/web/public/vendor/dompurify.min.js.br +0 -0
  106. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  107. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  108. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  109. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  110. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  111. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  112. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  113. package/dist/web/public/vendor/xterm.css.gz +0 -0
  114. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  115. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  116. package/dist/web/routes/file-routes.d.ts +2 -2
  117. package/dist/web/routes/file-routes.d.ts.map +1 -1
  118. package/dist/web/routes/file-routes.js +298 -1
  119. package/dist/web/routes/file-routes.js.map +1 -1
  120. package/dist/web/routes/index.d.ts +1 -0
  121. package/dist/web/routes/index.d.ts.map +1 -1
  122. package/dist/web/routes/index.js +1 -0
  123. package/dist/web/routes/index.js.map +1 -1
  124. package/dist/web/routes/session-routes.d.ts.map +1 -1
  125. package/dist/web/routes/session-routes.js +27 -1
  126. package/dist/web/routes/session-routes.js.map +1 -1
  127. package/dist/web/routes/status-telemetry-routes.d.ts +17 -0
  128. package/dist/web/routes/status-telemetry-routes.d.ts.map +1 -0
  129. package/dist/web/routes/status-telemetry-routes.js +57 -0
  130. package/dist/web/routes/status-telemetry-routes.js.map +1 -0
  131. package/dist/web/routes/system-routes.d.ts.map +1 -1
  132. package/dist/web/routes/system-routes.js +21 -1
  133. package/dist/web/routes/system-routes.js.map +1 -1
  134. package/dist/web/schemas.d.ts +30 -1
  135. package/dist/web/schemas.d.ts.map +1 -1
  136. package/dist/web/schemas.js +52 -0
  137. package/dist/web/schemas.js.map +1 -1
  138. package/dist/web/server.d.ts.map +1 -1
  139. package/dist/web/server.js +51 -5
  140. package/dist/web/server.js.map +1 -1
  141. package/dist/web/sse-events.d.ts +3 -0
  142. package/dist/web/sse-events.d.ts.map +1 -1
  143. package/dist/web/sse-events.js +3 -0
  144. package/dist/web/sse-events.js.map +1 -1
  145. package/package.json +1 -1
  146. package/dist/web/public/app.95e6e231.js +0 -35
  147. package/dist/web/public/app.95e6e231.js.br +0 -0
  148. package/dist/web/public/app.95e6e231.js.gz +0 -0
  149. package/dist/web/public/constants.aa510a4d.js.br +0 -0
  150. package/dist/web/public/constants.aa510a4d.js.gz +0 -0
  151. package/dist/web/public/mobile-handlers.763a7439.js.br +0 -0
  152. package/dist/web/public/mobile-handlers.763a7439.js.gz +0 -0
  153. package/dist/web/public/mobile.c7513aed.css +0 -1
  154. package/dist/web/public/mobile.c7513aed.css.br +0 -0
  155. package/dist/web/public/mobile.c7513aed.css.gz +0 -0
  156. package/dist/web/public/panels-ui.ba0b0f1a.js.br +0 -0
  157. package/dist/web/public/panels-ui.ba0b0f1a.js.gz +0 -0
  158. package/dist/web/public/session-ui.34f25fdf.js +0 -36
  159. package/dist/web/public/session-ui.34f25fdf.js.br +0 -0
  160. package/dist/web/public/session-ui.34f25fdf.js.gz +0 -0
  161. package/dist/web/public/settings-ui.bf79c4c0.js +0 -55
  162. package/dist/web/public/settings-ui.bf79c4c0.js.br +0 -0
  163. package/dist/web/public/settings-ui.bf79c4c0.js.gz +0 -0
  164. package/dist/web/public/styles.f3cc9833.css +0 -1
  165. package/dist/web/public/styles.f3cc9833.css.br +0 -0
  166. package/dist/web/public/styles.f3cc9833.css.gz +0 -0
  167. package/dist/web/public/terminal-ui.5bf97f7e.js +0 -3
  168. package/dist/web/public/terminal-ui.5bf97f7e.js.br +0 -0
  169. package/dist/web/public/terminal-ui.5bf97f7e.js.gz +0 -0
@@ -0,0 +1,261 @@
1
+ /**
2
+ * @fileoverview Shared disk cache for expensive Office document previews.
3
+ */
4
+ import { createHash } from 'node:crypto';
5
+ import { execFile } from 'node:child_process';
6
+ import fs from 'node:fs/promises';
7
+ import { tmpdir } from 'node:os';
8
+ import { basename, dirname, extname, join } from 'node:path';
9
+ import { pathToFileURL } from 'node:url';
10
+ import { promisify } from 'node:util';
11
+ import { runWithConversionLimit } from './document-conversion-limiter.js';
12
+ const execFileAsync = promisify(execFile);
13
+ const OFFICE_CONVERSION_TIMEOUT_MS = 5 * 60_000;
14
+ const DOCUMENT_PREVIEW_CACHE_DIR = join(tmpdir(), 'codeman-document-preview-cache');
15
+ /**
16
+ * Cap on persistent converted-PDF files kept in DOCUMENT_PREVIEW_CACHE_DIR.
17
+ * The cache key embeds the source mtime, so every edit to a doc orphans its
18
+ * prior PDF; without a cap the dir grows unbounded across long-running sessions.
19
+ * Override with CODEMAN_MAX_PREVIEW_CACHE_FILES (clamped to >= 1).
20
+ */
21
+ const MAX_PREVIEW_CACHE_FILES = (() => {
22
+ const raw = Number(process.env.CODEMAN_MAX_PREVIEW_CACHE_FILES);
23
+ return Number.isFinite(raw) && raw >= 1 ? Math.floor(raw) : 100;
24
+ })();
25
+ function buildWordExportPdfScript(sourcePath, outputPath) {
26
+ return `
27
+ $ErrorActionPreference = "Stop"
28
+ $source = ${toPowerShellSingleQuotedString(sourcePath)}
29
+ $output = ${toPowerShellSingleQuotedString(outputPath)}
30
+ $word = $null
31
+ $doc = $null
32
+ try {
33
+ $word = New-Object -ComObject Word.Application
34
+ $word.Visible = $false
35
+ $word.DisplayAlerts = 0
36
+ $doc = $word.Documents.Open($source)
37
+ $doc.ExportAsFixedFormat($output, 17)
38
+ } finally {
39
+ if ($null -ne $doc) {
40
+ $doc.Close($false) | Out-Null
41
+ [System.Runtime.InteropServices.Marshal]::ReleaseComObject($doc) | Out-Null
42
+ }
43
+ if ($null -ne $word) {
44
+ $word.Quit() | Out-Null
45
+ [System.Runtime.InteropServices.Marshal]::ReleaseComObject($word) | Out-Null
46
+ }
47
+ [System.GC]::Collect()
48
+ [System.GC]::WaitForPendingFinalizers()
49
+ }
50
+ `.trim();
51
+ }
52
+ const inFlightOfficeConversions = new Map();
53
+ export function clearDocumentPreviewCache() {
54
+ inFlightOfficeConversions.clear();
55
+ }
56
+ /**
57
+ * Best-effort LRU-ish eviction for the persistent converted-PDF cache: keeps at
58
+ * most MAX_PREVIEW_CACHE_FILES `*.pdf` files in `cacheDir`, deleting the oldest
59
+ * by mtime once over the cap. Never throws — a pruning failure must not fail the
60
+ * conversion that triggered it. Only `*.pdf` files are considered, so the
61
+ * transient `work-*` mkdtemp dirs are ignored.
62
+ */
63
+ export async function pruneDocumentPreviewCache(cacheDir) {
64
+ try {
65
+ const entries = await fs.readdir(cacheDir);
66
+ const pdfs = entries.filter((name) => name.toLowerCase().endsWith('.pdf'));
67
+ if (pdfs.length <= MAX_PREVIEW_CACHE_FILES)
68
+ return;
69
+ const stats = await Promise.all(pdfs.map(async (name) => {
70
+ const fullPath = join(cacheDir, name);
71
+ try {
72
+ const stat = await fs.stat(fullPath);
73
+ return { fullPath, mtimeMs: stat.mtimeMs ?? 0 };
74
+ }
75
+ catch {
76
+ return null;
77
+ }
78
+ }));
79
+ const sorted = stats.filter((s) => s !== null);
80
+ sorted.sort((a, b) => a.mtimeMs - b.mtimeMs); // oldest first
81
+ const toRemove = sorted.slice(0, Math.max(0, sorted.length - MAX_PREVIEW_CACHE_FILES));
82
+ await Promise.all(toRemove.map((entry) => fs.rm(entry.fullPath, { force: true }).catch(() => { })));
83
+ }
84
+ catch {
85
+ // Best-effort: pruning must never break a conversion.
86
+ }
87
+ }
88
+ export async function getOfficePreviewPdfPath(filePath, extension) {
89
+ const ext = extension.toLowerCase().replace(/^\./, '');
90
+ if (ext !== 'docx' && ext !== 'pptx')
91
+ return null;
92
+ let sourceStat;
93
+ try {
94
+ sourceStat = await fs.stat(filePath);
95
+ }
96
+ catch {
97
+ return null;
98
+ }
99
+ for (const converter of getOfficePreviewConverters(filePath, ext)) {
100
+ const cacheKey = createDocumentPreviewCacheKey(filePath, ext, sourceStat.size, sourceStat.mtimeMs ?? 0, converter);
101
+ const cachePath = getOfficePreviewCachePath(filePath, cacheKey, converter);
102
+ if (await fileExists(cachePath)) {
103
+ return cachePath;
104
+ }
105
+ const inFlightKey = `${converter}:${cacheKey}`;
106
+ const inFlight = inFlightOfficeConversions.get(inFlightKey);
107
+ if (inFlight) {
108
+ const converted = await inFlight;
109
+ if (converted)
110
+ return converted;
111
+ continue;
112
+ }
113
+ const conversion = converter === 'msword'
114
+ ? convertWordDocumentToCachedPdf(filePath, cachePath)
115
+ : convertLibreOfficeDocumentToCachedPdf(filePath, cachePath);
116
+ inFlightOfficeConversions.set(inFlightKey, conversion);
117
+ try {
118
+ const converted = await conversion;
119
+ if (converted)
120
+ return converted;
121
+ }
122
+ finally {
123
+ inFlightOfficeConversions.delete(inFlightKey);
124
+ }
125
+ }
126
+ return null;
127
+ }
128
+ function getOfficePreviewConverters(filePath, extension) {
129
+ if (extension === 'docx' && wslMountPathToWindowsPath(filePath)) {
130
+ return ['msword', 'libreoffice'];
131
+ }
132
+ return ['libreoffice'];
133
+ }
134
+ function createDocumentPreviewCacheKey(filePath, extension, size, mtimeMs, converter) {
135
+ return createHash('sha256')
136
+ .update(JSON.stringify({ cacheVersion: 2, converter, filePath, extension, size, mtimeMs }))
137
+ .digest('hex')
138
+ .slice(0, 32);
139
+ }
140
+ function getOfficePreviewCachePath(filePath, cacheKey, converter) {
141
+ if (converter === 'msword') {
142
+ const windowsCacheDir = getWindowsUserTempCacheDir(filePath);
143
+ if (windowsCacheDir) {
144
+ return join(windowsCacheDir, `${cacheKey}.pdf`);
145
+ }
146
+ }
147
+ return join(DOCUMENT_PREVIEW_CACHE_DIR, `${cacheKey}.pdf`);
148
+ }
149
+ async function fileExists(filePath) {
150
+ try {
151
+ const stat = await fs.stat(filePath);
152
+ return typeof stat.isFile !== 'function' || stat.isFile();
153
+ }
154
+ catch {
155
+ return false;
156
+ }
157
+ }
158
+ async function convertWordDocumentToCachedPdf(filePath, cachePath) {
159
+ const outputPath = wslMountPathToWindowsPath(cachePath);
160
+ if (!outputPath)
161
+ return null;
162
+ let sourceCopyPath;
163
+ try {
164
+ await fs.mkdir(dirname(cachePath), { recursive: true });
165
+ sourceCopyPath = join(dirname(cachePath), `${basename(cachePath, '.pdf')}.docx`);
166
+ await fs.copyFile(filePath, sourceCopyPath);
167
+ const sourcePath = wslMountPathToWindowsPath(sourceCopyPath);
168
+ if (!sourcePath)
169
+ return null;
170
+ await runWithConversionLimit(() => execFileAsync('powershell.exe', [
171
+ '-NoProfile',
172
+ '-NonInteractive',
173
+ '-ExecutionPolicy',
174
+ 'Bypass',
175
+ '-EncodedCommand',
176
+ encodePowerShellCommand(buildWordExportPdfScript(sourcePath, outputPath)),
177
+ ], {
178
+ timeout: OFFICE_CONVERSION_TIMEOUT_MS,
179
+ maxBuffer: 1024 * 1024,
180
+ }));
181
+ if (await fileExists(cachePath)) {
182
+ await pruneDocumentPreviewCache(dirname(cachePath));
183
+ return cachePath;
184
+ }
185
+ console.warn(`[DocumentPreviewCache] Microsoft Word did not produce PDF output for ${filePath}`);
186
+ return null;
187
+ }
188
+ catch (err) {
189
+ console.warn(`[DocumentPreviewCache] Failed to convert DOCX with Microsoft Word (${filePath}):`, getCacheErrorMessage(err));
190
+ return null;
191
+ }
192
+ finally {
193
+ if (sourceCopyPath) {
194
+ await fs.rm(sourceCopyPath, { force: true }).catch(() => { });
195
+ }
196
+ }
197
+ }
198
+ async function convertLibreOfficeDocumentToCachedPdf(filePath, cachePath) {
199
+ let workDir;
200
+ try {
201
+ await fs.mkdir(DOCUMENT_PREVIEW_CACHE_DIR, { recursive: true });
202
+ const outDir = await fs.mkdtemp(join(DOCUMENT_PREVIEW_CACHE_DIR, 'work-'));
203
+ workDir = outDir;
204
+ const profileDir = join(outDir, 'profile');
205
+ await fs.mkdir(profileDir, { recursive: true });
206
+ await runWithConversionLimit(() => execFileAsync('soffice', [
207
+ '--headless',
208
+ '--nologo',
209
+ '--nofirststartwizard',
210
+ `-env:UserInstallation=${pathToFileURL(profileDir).href}`,
211
+ '--convert-to',
212
+ 'pdf',
213
+ '--outdir',
214
+ outDir,
215
+ filePath,
216
+ ], {
217
+ timeout: OFFICE_CONVERSION_TIMEOUT_MS,
218
+ maxBuffer: 1024 * 1024,
219
+ }));
220
+ const converted = (await fs.readdir(outDir)).find((name) => name.toLowerCase().endsWith('.pdf'));
221
+ if (!converted)
222
+ return null;
223
+ await fs.rename(join(workDir, converted), cachePath);
224
+ await pruneDocumentPreviewCache(DOCUMENT_PREVIEW_CACHE_DIR);
225
+ return cachePath;
226
+ }
227
+ catch (err) {
228
+ console.warn(`[DocumentPreviewCache] Failed to convert Office file to PDF (${filePath}):`, getCacheErrorMessage(err));
229
+ return null;
230
+ }
231
+ finally {
232
+ if (workDir) {
233
+ await fs.rm(workDir, { recursive: true, force: true }).catch(() => { });
234
+ }
235
+ }
236
+ }
237
+ function wslMountPathToWindowsPath(filePath) {
238
+ const match = filePath.match(/^\/mnt\/([a-zA-Z])\/(.+)$/);
239
+ if (!match)
240
+ return null;
241
+ return `${match[1].toUpperCase()}:\\${match[2].replace(/\//g, '\\')}`;
242
+ }
243
+ function getWindowsUserTempCacheDir(filePath) {
244
+ const match = filePath.match(/^\/mnt\/([a-zA-Z])\/Users\/([^/]+)\//);
245
+ if (!match)
246
+ return null;
247
+ return `/mnt/${match[1].toLowerCase()}/Users/${match[2]}/AppData/Local/Temp/codeman-document-preview-cache`;
248
+ }
249
+ function toPowerShellSingleQuotedString(value) {
250
+ return `'${value.replace(/'/g, "''")}'`;
251
+ }
252
+ function encodePowerShellCommand(script) {
253
+ return Buffer.from(script, 'utf16le').toString('base64');
254
+ }
255
+ export function getPreviewPdfDownloadName(fileName, extension) {
256
+ return `${basename(fileName, extname(fileName) || `.${extension}`)}.pdf`;
257
+ }
258
+ function getCacheErrorMessage(err) {
259
+ return err instanceof Error ? err.message : String(err);
260
+ }
261
+ //# sourceMappingURL=document-preview-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-preview-cache.js","sourceRoot":"","sources":["../src/document-preview-cache.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAE1E,MAAM,aAAa,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;AAE1C,MAAM,4BAA4B,GAAG,CAAC,GAAG,MAAM,CAAC;AAChD,MAAM,0BAA0B,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,gCAAgC,CAAC,CAAC;AACpF;;;;;GAKG;AACH,MAAM,uBAAuB,GAAG,CAAC,GAAG,EAAE;IACpC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAChE,OAAO,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;AAClE,CAAC,CAAC,EAAE,CAAC;AACL,SAAS,wBAAwB,CAAC,UAAkB,EAAE,UAAkB;IACtE,OAAO;;YAEG,8BAA8B,CAAC,UAAU,CAAC;YAC1C,8BAA8B,CAAC,UAAU,CAAC;;;;;;;;;;;;;;;;;;;;;CAqBrD,CAAC,IAAI,EAAE,CAAC;AACT,CAAC;AAID,MAAM,yBAAyB,GAAG,IAAI,GAAG,EAAkC,CAAC;AAE5E,MAAM,UAAU,yBAAyB;IACvC,yBAAyB,CAAC,KAAK,EAAE,CAAC;AACpC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,QAAgB;IAC9D,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QAC3C,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3E,IAAI,IAAI,CAAC,MAAM,IAAI,uBAAuB;YAAE,OAAO;QAEnD,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAC7B,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;YACtB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;gBACrC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,IAAI,CAAC,EAAE,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QAEF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAA8C,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;QAC3F,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe;QAC7D,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,GAAG,uBAAuB,CAAC,CAAC,CAAC;QACvF,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACrG,CAAC;IAAC,MAAM,CAAC;QACP,sDAAsD;IACxD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,QAAgB,EAAE,SAAiB;IAC/E,MAAM,GAAG,GAAG,SAAS,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACvD,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IAElD,IAAI,UAAU,CAAC;IACf,IAAI,CAAC;QACH,UAAU,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,MAAM,SAAS,IAAI,0BAA0B,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;QAClE,MAAM,QAAQ,GAAG,6BAA6B,CAAC,QAAQ,EAAE,GAAG,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;QACnH,MAAM,SAAS,GAAG,yBAAyB,CAAC,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC;QAE3E,IAAI,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,WAAW,GAAG,GAAG,SAAS,IAAI,QAAQ,EAAE,CAAC;QAC/C,MAAM,QAAQ,GAAG,yBAAyB,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC5D,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC;YACjC,IAAI,SAAS;gBAAE,OAAO,SAAS,CAAC;YAChC,SAAS;QACX,CAAC;QAED,MAAM,UAAU,GACd,SAAS,KAAK,QAAQ;YACpB,CAAC,CAAC,8BAA8B,CAAC,QAAQ,EAAE,SAAS,CAAC;YACrD,CAAC,CAAC,qCAAqC,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;QACjE,yBAAyB,CAAC,GAAG,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,UAAU,CAAC;YACnC,IAAI,SAAS;gBAAE,OAAO,SAAS,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,yBAAyB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,0BAA0B,CAAC,QAAgB,EAAE,SAAiB;IACrE,IAAI,SAAS,KAAK,MAAM,IAAI,yBAAyB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChE,OAAO,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,CAAC,aAAa,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,6BAA6B,CACpC,QAAgB,EAChB,SAAiB,EACjB,IAAY,EACZ,OAAe,EACf,SAAiC;IAEjC,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;SAC1F,MAAM,CAAC,KAAK,CAAC;SACb,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,yBAAyB,CAAC,QAAgB,EAAE,QAAgB,EAAE,SAAiC;IACtG,IAAI,SAAS,KAAK,QAAQ,EAAE,CAAC;QAC3B,MAAM,eAAe,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;QAC7D,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC,eAAe,EAAE,GAAG,QAAQ,MAAM,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC,0BAA0B,EAAE,GAAG,QAAQ,MAAM,CAAC,CAAC;AAC7D,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,QAAgB;IACxC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,KAAK,UAAU,8BAA8B,CAAC,QAAgB,EAAE,SAAiB;IAC/E,MAAM,UAAU,GAAG,yBAAyB,CAAC,SAAS,CAAC,CAAC;IACxD,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,IAAI,cAAkC,CAAC;IAEvC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACxD,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACjF,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;QAE5C,MAAM,UAAU,GAAG,yBAAyB,CAAC,cAAc,CAAC,CAAC;QAC7D,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAE7B,MAAM,sBAAsB,CAAC,GAAG,EAAE,CAChC,aAAa,CACX,gBAAgB,EAChB;YACE,YAAY;YACZ,iBAAiB;YACjB,kBAAkB;YAClB,QAAQ;YACR,iBAAiB;YACjB,uBAAuB,CAAC,wBAAwB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;SAC1E,EACD;YACE,OAAO,EAAE,4BAA4B;YACrC,SAAS,EAAE,IAAI,GAAG,IAAI;SACvB,CACF,CACF,CAAC;QAEF,IAAI,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAChC,MAAM,yBAAyB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YACpD,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,wEAAwE,QAAQ,EAAE,CAAC,CAAC;QACjG,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,sEAAsE,QAAQ,IAAI,EAClF,oBAAoB,CAAC,GAAG,CAAC,CAC1B,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,cAAc,EAAE,CAAC;YACnB,MAAM,EAAE,CAAC,EAAE,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;AACH,CAAC;AAED,KAAK,UAAU,qCAAqC,CAAC,QAAgB,EAAE,SAAiB;IACtF,IAAI,OAA2B,CAAC;IAChC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,KAAK,CAAC,0BAA0B,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,0BAA0B,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3E,OAAO,GAAG,MAAM,CAAC;QACjB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAC3C,MAAM,EAAE,CAAC,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAEhD,MAAM,sBAAsB,CAAC,GAAG,EAAE,CAChC,aAAa,CACX,SAAS,EACT;YACE,YAAY;YACZ,UAAU;YACV,sBAAsB;YACtB,yBAAyB,aAAa,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE;YACzD,cAAc;YACd,KAAK;YACL,UAAU;YACV,MAAM;YACN,QAAQ;SACT,EACD;YACE,OAAO,EAAE,4BAA4B;YACrC,SAAS,EAAE,IAAI,GAAG,IAAI;SACvB,CACF,CACF,CAAC;QAEF,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACjG,IAAI,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QAE5B,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;QACrD,MAAM,yBAAyB,CAAC,0BAA0B,CAAC,CAAC;QAC5D,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CACV,gEAAgE,QAAQ,IAAI,EAC5E,oBAAoB,CAAC,GAAG,CAAC,CAC1B,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;YAAS,CAAC;QACT,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACzE,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,yBAAyB,CAAC,QAAgB;IACjD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IAC1D,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,SAAS,0BAA0B,CAAC,QAAgB;IAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,sCAAsC,CAAC,CAAC;IACrE,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,UAAU,KAAK,CAAC,CAAC,CAAC,oDAAoD,CAAC;AAC9G,CAAC;AAED,SAAS,8BAA8B,CAAC,KAAa;IACnD,OAAO,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC;AAC1C,CAAC;AAED,SAAS,uBAAuB,CAAC,MAAc;IAC7C,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,QAAgB,EAAE,SAAiB;IAC3E,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,SAAS,EAAE,CAAC,MAAM,CAAC;AAC3E,CAAC;AAED,SAAS,oBAAoB,CAAC,GAAY;IACxC,OAAO,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;AAC1D,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * @fileoverview Best-effort first-page thumbnails for attachment cards.
3
+ */
4
+ export interface ThumbnailResult {
5
+ content: Buffer;
6
+ contentType: 'image/png';
7
+ }
8
+ export declare function generateFirstPageThumbnail(filePath: string, extension: string): Promise<ThumbnailResult | null>;
9
+ //# sourceMappingURL=document-thumbnailer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-thumbnailer.d.ts","sourceRoot":"","sources":["../src/document-thumbnailer.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,wBAAsB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAuBrH"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @fileoverview Best-effort first-page thumbnails for attachment cards.
3
+ */
4
+ import { execFile } from 'node:child_process';
5
+ import fs from 'node:fs/promises';
6
+ import { tmpdir } from 'node:os';
7
+ import { basename, extname, join } from 'node:path';
8
+ import { promisify } from 'node:util';
9
+ import { getOfficePreviewPdfPath } from './document-preview-cache.js';
10
+ import { runWithConversionLimit } from './document-conversion-limiter.js';
11
+ const execFileAsync = promisify(execFile);
12
+ const THUMBNAIL_CONVERSION_TIMEOUT_MS = 5 * 60_000;
13
+ export async function generateFirstPageThumbnail(filePath, extension) {
14
+ const ext = extension.toLowerCase().replace(/^\./, '');
15
+ try {
16
+ await fs.stat(filePath);
17
+ if (ext === 'png') {
18
+ return { content: await fs.readFile(filePath), contentType: 'image/png' };
19
+ }
20
+ if (ext === 'pdf') {
21
+ return renderPdfFirstPage(filePath);
22
+ }
23
+ if (ext === 'docx' || ext === 'pptx') {
24
+ return renderOfficeFirstPage(filePath);
25
+ }
26
+ }
27
+ catch (err) {
28
+ console.warn(`[Thumbnailer] Failed to generate ${ext} thumbnail for ${filePath}:`, getThumbnailErrorMessage(err));
29
+ return null;
30
+ }
31
+ return null;
32
+ }
33
+ async function renderOfficeFirstPage(filePath) {
34
+ try {
35
+ const previewPdfPath = await getOfficePreviewPdfPath(filePath, extname(filePath).toLowerCase().replace(/^\./, ''));
36
+ if (!previewPdfPath)
37
+ return null;
38
+ return await renderPdfFirstPage(previewPdfPath);
39
+ }
40
+ catch (err) {
41
+ console.warn(`[Thumbnailer] Failed to convert Office file to PDF for thumbnail (${filePath}):`, getThumbnailErrorMessage(err));
42
+ return null;
43
+ }
44
+ }
45
+ async function renderPdfFirstPage(filePath) {
46
+ let previewDir;
47
+ try {
48
+ previewDir = await fs.mkdtemp(join(tmpdir(), 'codeman-thumb-pdf-'));
49
+ const prefix = join(previewDir, basename(filePath, extname(filePath)));
50
+ await runWithConversionLimit(() => execFileAsync('pdftoppm', ['-png', '-singlefile', '-f', '1', '-l', '1', '-scale-to', '520', filePath, prefix], {
51
+ timeout: THUMBNAIL_CONVERSION_TIMEOUT_MS,
52
+ maxBuffer: 1024 * 1024,
53
+ }));
54
+ const content = await fs.readFile(`${prefix}.png`);
55
+ return { content, contentType: 'image/png' };
56
+ }
57
+ catch (err) {
58
+ console.warn(`[Thumbnailer] Failed to render PDF first page for thumbnail (${filePath}):`, getThumbnailErrorMessage(err));
59
+ return null;
60
+ }
61
+ finally {
62
+ if (previewDir) {
63
+ await fs.rm(previewDir, { recursive: true, force: true }).catch(() => { });
64
+ }
65
+ }
66
+ }
67
+ function getThumbnailErrorMessage(err) {
68
+ return err instanceof Error ? err.message : String(err);
69
+ }
70
+ //# sourceMappingURL=document-thumbnailer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-thumbnailer.js","sourceRoot":"","sources":["../src/document-thumbnailer.ts"],"names":[],"mappings":"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"}
@@ -57,4 +57,38 @@ export declare function updateCaseModel(casePath: string, model: string | null):
57
57
  * Merges with existing file content, only touching the `hooks` key.
58
58
  */
59
59
  export declare function writeHooksConfig(casePath: string): Promise<void>;
60
+ /**
61
+ * Self-heal a case's hooks block so the COD-91 unconditional hook-secret gate keeps
62
+ * accepting its hook events.
63
+ *
64
+ * `writeHooksConfig` only runs when a case is first CREATED. Cases created before the
65
+ * X-Codeman-Hook-Secret header was added (COD-54, 2026-06-10) keep hook curls in their
66
+ * settings.local.json that POST to /api/hook-event WITHOUT the secret — which, once the
67
+ * gate requires it unconditionally (COD-91), silently 401 on a password-protected
68
+ * install. This refreshes the hooks block so those stale curls regain the header.
69
+ *
70
+ * Deliberately surgical: regenerates ONLY when settings.local.json already contains
71
+ * Codeman's own hook curls (they target `/api/hook-event`) that lack the secret header.
72
+ * No-op when the file/hooks are absent (we never impose hooks on a user who removed
73
+ * them), when the hooks aren't ours, or when the secret is already present — so it never
74
+ * clobbers a user's customizations and is cheap enough to call on every Claude spawn.
75
+ */
76
+ export declare function refreshStaleHookSecret(casePath: string): Promise<void>;
77
+ /**
78
+ * The plan-usage statusLine exporter command. Mirrors the hook `curlCmd` pattern:
79
+ * reads Claude Code's statusline stdin JSON, POSTs `{sessionId,data}` to Codeman,
80
+ * and prints the response body (a compact "⟳ 5h 15% · 7d 34%" footer) back to
81
+ * stdout so the in-terminal statusline stays useful. Env vars resolve at runtime
82
+ * (present in every managed session via tmux setenv), so the config is static.
83
+ */
84
+ export declare function generateStatusLineCommand(): string;
85
+ /**
86
+ * Add or remove Codeman's plan-usage statusLine exporter in
87
+ * `.claude/settings.local.json`. Only ever touches a statusLine that is OURS
88
+ * (command targets `/api/status-telemetry`), so a user's hand-authored
89
+ * statusLine is never removed OR overwritten — on both the enable and disable
90
+ * paths we bail out when an existing statusLine isn't ours. Callers gate on
91
+ * Claude mode. Merges, preserving all other keys (hooks, env, model).
92
+ */
93
+ export declare function applyStatusLineConfig(casePath: string, enabled: boolean): Promise<void>;
60
94
  //# sourceMappingURL=hooks-config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hooks-config.d.ts","sourceRoot":"","sources":["../src/hooks-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AASH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAmD1E;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BvG;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BxG;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAsB3F;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBtE"}
1
+ {"version":3,"file":"hooks-config.d.ts","sourceRoot":"","sources":["../src/hooks-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAiCH;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI;IAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAmD1E;AAED;;;;;;GAMG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BvG;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CA2BxG;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAuB3F;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBtE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB5E;AAKD;;;;;;GAMG;AACH,wBAAgB,yBAAyB,IAAI,MAAM,CAalD;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B7F"}