flow-agent-bridge 0.32.0 → 0.34.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.
@@ -0,0 +1,480 @@
1
+ // Persistent agent session: one CLI process per conversation (#519).
2
+ //
3
+ // The bridge used to spawn a `claude` process per turn and kill it the moment
4
+ // the turn's `result` event arrived. That took the agent's background work with
5
+ // it — a backgrounded Bash task, a subagent, a pending wakeup — so an agent
6
+ // could not do anything asynchronous at all.
7
+ //
8
+ // Here the process is spawned once per conversation and kept alive:
9
+ // `--input-format stream-json` with stdin held open, each Flow message written
10
+ // as a user message, each `result` event a turn boundary rather than the end of
11
+ // the process. Background tasks then survive the boundary, and when one
12
+ // finishes the SDK re-invokes the agent inside the same process — a turn nobody
13
+ // sent a message for, whose reply is posted like any other (`onAmbientEnd`).
14
+ //
15
+ // What this buys costs a lifecycle to manage, which is the rest of this file:
16
+ // per-turn timers (silence *between* turns is normal and must expire nothing),
17
+ // an idle reaper that a pending background task holds off up to a hard cap, and
18
+ // an interrupt that ends the turn without ending the session.
19
+ import { spawn } from 'node:child_process';
20
+ import { randomUUID } from 'node:crypto';
21
+ import { StreamJsonParser, buildClaudeArgs, describeResultError, killGroup, registerGroup, unregisterGroup, } from './runtime.js';
22
+ /** What an interrupted turn resolves to — no CLI error, just a stopped run. */
23
+ const INTERRUPTED = 'interrupted';
24
+ /**
25
+ * How long a turn we asked to stop gets to produce its `result` before we stop
26
+ * asking and kill the process group. The control request is the good path (it
27
+ * leaves the session and its background tasks alive); this is the backstop for
28
+ * a CLI too wedged to answer it.
29
+ */
30
+ const INTERRUPT_GRACE_MS = 10_000;
31
+ /** SIGTERM → SIGKILL grace on a reap, long enough to flush the transcript. */
32
+ const REAP_GRACE_MS = 5_000;
33
+ /**
34
+ * One conversation's CLI process. Turns are serialised: a message arriving
35
+ * while a turn (of either kind) is running waits for it, exactly as messages
36
+ * queued behind a running turn did before.
37
+ */
38
+ export class RuntimeSession {
39
+ cfg;
40
+ hooks;
41
+ makeSpawn;
42
+ sessionId;
43
+ interruptGraceMs;
44
+ child = null;
45
+ parser;
46
+ resume;
47
+ spawnCleanup = null;
48
+ turn = null;
49
+ stderrTail = '';
50
+ /** Set by the close handler when the CLI refused our `--session-id`. */
51
+ collided = false;
52
+ disposed = false;
53
+ /** Serialises runTurn callers against each other. */
54
+ gate = Promise.resolve();
55
+ idleWaiters = [];
56
+ /** When the last turn of any kind ended — what both reaper clocks measure. */
57
+ lastTurnEndAt = Date.now();
58
+ constructor(opts) {
59
+ this.cfg = opts.cfg;
60
+ this.hooks = opts.hooks;
61
+ this.makeSpawn = opts.makeSpawn;
62
+ this.sessionId = opts.sessionId;
63
+ this.resume = opts.resume;
64
+ this.interruptGraceMs = opts.interruptGraceMs ?? INTERRUPT_GRACE_MS;
65
+ this.parser = this.newParser();
66
+ }
67
+ /** The CLI has produced events under this session id, so a respawn resumes it. */
68
+ get sawSession() {
69
+ return this.parser.sawEvent || this.resume;
70
+ }
71
+ get turnInFlight() {
72
+ return this.turn !== null;
73
+ }
74
+ /** Background work the agent started and hasn't finished. */
75
+ get pendingTasks() {
76
+ return this.parser.pending.size;
77
+ }
78
+ get pid() {
79
+ return this.child?.pid;
80
+ }
81
+ /**
82
+ * Idle = nothing to wait for: no turn running and no background task open.
83
+ * Only an idle session is reapable on the short clock.
84
+ */
85
+ get idle() {
86
+ return this.turn === null && this.parser.pending.size === 0;
87
+ }
88
+ /**
89
+ * Reap when the session has been quiet past its clock. A pending background
90
+ * task buys time — up to the hard cap, so a wedged task cannot pin a session
91
+ * open forever — but a turn in flight is never interrupted by the reaper.
92
+ */
93
+ reapReason(now, idleMs, hardCapMs) {
94
+ if (this.child === null || this.turn !== null)
95
+ return null;
96
+ const quiet = now - this.lastTurnEndAt;
97
+ if (this.parser.pending.size === 0) {
98
+ return quiet >= idleMs ? `idle for ${Math.round(quiet / 1000)}s` : null;
99
+ }
100
+ return quiet >= hardCapMs
101
+ ? `hit the ${Math.round(hardCapMs / 1000)}s cap with ${this.parser.pending.size} background task(s) still open`
102
+ : null;
103
+ }
104
+ /**
105
+ * Run one turn. Spawns the process if this conversation hasn't got one (first
106
+ * message, or the first after a reap or a crash), then writes the message and
107
+ * resolves when that turn's `result` arrives.
108
+ */
109
+ async runTurn(prompt, signal) {
110
+ const run = this.gate.then(async () => {
111
+ if (signal?.aborted)
112
+ return { ok: false, text: '', error: INTERRUPTED, interrupted: true };
113
+ await this.waitForNoTurn();
114
+ let result = await this.attempt(prompt, signal);
115
+ // Session-id collision (a previous process died after the CLI created the
116
+ // session): the session exists — flip to --resume and retry this same
117
+ // message transparently, exactly as the per-turn runtime used to.
118
+ if (this.collided) {
119
+ this.collided = false;
120
+ this.resume = true;
121
+ this.hooks.log('session collision — retrying this message with --resume');
122
+ result = await this.attempt(prompt, signal);
123
+ }
124
+ return result;
125
+ });
126
+ // The gate must advance even when a turn throws, or the conversation wedges.
127
+ this.gate = run.catch(() => { });
128
+ return run;
129
+ }
130
+ /** Interrupt button / `/stop`: end the turn, keep the session. */
131
+ interrupt() {
132
+ this.endTurnEarly(INTERRUPTED, true);
133
+ }
134
+ /** Reap or shut down: the process and everything it started go away. */
135
+ dispose(reason, graceMs = REAP_GRACE_MS) {
136
+ this.disposed = true;
137
+ const pid = this.child?.pid;
138
+ if (pid) {
139
+ this.hooks.log(`ending the session process (pid ${pid}): ${reason}`);
140
+ killGroup(pid, graceMs);
141
+ unregisterGroup(pid);
142
+ }
143
+ this.child = null;
144
+ this.spawnCleanup?.();
145
+ this.spawnCleanup = null;
146
+ // A turn still waiting settles from the close handler; if the process was
147
+ // already gone, settle it here so no caller hangs.
148
+ if (this.turn)
149
+ this.settleTurn(this.buildResult(`session ended: ${reason}`));
150
+ }
151
+ // ---- internals -----------------------------------------------------------
152
+ newParser() {
153
+ return new StreamJsonParser((step) => this.hooks.onToolStep(step), (text) => this.hooks.onText(text), {
154
+ onTurnStart: () => this.onTurnStart(),
155
+ onResult: () => this.onResult(),
156
+ onPendingChange: (pending) => this.hooks.log(`background tasks open: ${pending}`),
157
+ });
158
+ }
159
+ /** Resolves once no turn is running — ambient turns queue new messages too. */
160
+ waitForNoTurn() {
161
+ if (this.turn === null)
162
+ return Promise.resolve();
163
+ return new Promise((resolve) => this.idleWaiters.push(resolve));
164
+ }
165
+ async attempt(prompt, signal) {
166
+ const spawnError = this.ensureProcess();
167
+ if (spawnError)
168
+ return { ok: false, text: '', error: spawnError };
169
+ return new Promise((resolve) => {
170
+ const turn = this.startTurn(false, resolve);
171
+ turn.signal = signal;
172
+ turn.onAbort = () => this.endTurnEarly(INTERRUPTED, true);
173
+ signal?.addEventListener('abort', turn.onAbort);
174
+ if (signal?.aborted)
175
+ return turn.onAbort();
176
+ const line = JSON.stringify({
177
+ type: 'user',
178
+ message: { role: 'user', content: [{ type: 'text', text: prompt }] },
179
+ });
180
+ try {
181
+ this.child.stdin.write(`${line}\n`);
182
+ }
183
+ catch (err) {
184
+ this.settleTurn({ ok: false, text: '', error: `could not write to the session: ${err.message}` });
185
+ }
186
+ });
187
+ }
188
+ startTurn(ambient, resolve) {
189
+ this.parser.resetTurn();
190
+ const turn = {
191
+ ambient,
192
+ resolve,
193
+ ending: null,
194
+ idleTimer: null,
195
+ capTimer: null,
196
+ killTimer: null,
197
+ };
198
+ this.turn = turn;
199
+ // Per-turn, not per-process: between turns a session is *meant* to be
200
+ // silent, and a lifetime timer would kill it for being well behaved.
201
+ turn.capTimer = setTimeout(() => this.endTurnEarly(`hit the ${this.cfg.timeoutSec}s run cap`), this.cfg.timeoutSec * 1000);
202
+ turn.capTimer.unref();
203
+ this.bumpIdle();
204
+ return turn;
205
+ }
206
+ /**
207
+ * `system`/`init` with nothing in flight means the SDK started a turn on its
208
+ * own — a background task finished and it re-invoked the agent. Announce it
209
+ * so the conversation gets a progress row and, at the end, a reply.
210
+ */
211
+ onTurnStart() {
212
+ if (this.turn !== null)
213
+ return;
214
+ this.hooks.log('agent re-invoked itself (a background task finished) — following turn');
215
+ this.startTurn(true, null);
216
+ this.hooks.onAmbientStart();
217
+ }
218
+ onResult() {
219
+ if (!this.turn)
220
+ return;
221
+ this.settleTurn(this.buildResult());
222
+ }
223
+ /** Shape a finished turn's result exactly as the per-turn runtime did. */
224
+ buildResult(hardError) {
225
+ const turn = this.turn;
226
+ if (turn?.ending) {
227
+ // A stopped turn never reaches its own conclusion, so the salvage is the
228
+ // last thing the agent said — the only record of the work it did.
229
+ return {
230
+ ok: false,
231
+ text: this.parser.lastText,
232
+ error: turn.ending.error,
233
+ sawSession: this.sawSession,
234
+ interrupted: turn.ending.interrupted,
235
+ };
236
+ }
237
+ if (hardError) {
238
+ return { ok: false, text: this.parser.finalText || this.parser.lastText, error: hardError, sawSession: this.sawSession };
239
+ }
240
+ if (this.parser.sawResult && !this.parser.isError) {
241
+ return { ok: true, text: this.parser.finalText, sawSession: true };
242
+ }
243
+ return {
244
+ ok: false,
245
+ text: this.parser.finalText || this.parser.lastText,
246
+ error: describeResultError(this.parser.errorSubtype, this.cfg.maxTurns),
247
+ sawSession: this.sawSession,
248
+ };
249
+ }
250
+ settleTurn(result) {
251
+ const turn = this.turn;
252
+ if (!turn)
253
+ return;
254
+ this.turn = null;
255
+ this.lastTurnEndAt = Date.now();
256
+ if (turn.idleTimer)
257
+ clearTimeout(turn.idleTimer);
258
+ if (turn.capTimer)
259
+ clearTimeout(turn.capTimer);
260
+ if (turn.killTimer)
261
+ clearTimeout(turn.killTimer);
262
+ if (turn.onAbort)
263
+ turn.signal?.removeEventListener('abort', turn.onAbort);
264
+ if (result.sawSession)
265
+ this.resume = true;
266
+ const waiters = this.idleWaiters;
267
+ this.idleWaiters = [];
268
+ for (const w of waiters)
269
+ w();
270
+ if (turn.ambient)
271
+ this.hooks.onAmbientEnd(result);
272
+ else
273
+ turn.resolve?.(result);
274
+ }
275
+ /**
276
+ * Ask the CLI to end the current turn. The control request is the good path —
277
+ * it stops the turn and leaves the session, and its background tasks, alive.
278
+ * If no `result` follows within the grace we fall back to the process-group
279
+ * kill this used to do unconditionally.
280
+ */
281
+ endTurnEarly(error, interrupted = false) {
282
+ const turn = this.turn;
283
+ if (!turn || turn.ending)
284
+ return;
285
+ turn.ending = { error, interrupted };
286
+ if (turn.idleTimer)
287
+ clearTimeout(turn.idleTimer);
288
+ if (turn.capTimer)
289
+ clearTimeout(turn.capTimer);
290
+ this.hooks.log(interrupted ? 'run interrupted — asking the session to stop this turn' : `turn expired: ${error} — asking the session to stop it`);
291
+ const request = {
292
+ type: 'control_request',
293
+ request_id: `req_${randomUUID()}`,
294
+ request: { subtype: 'interrupt' },
295
+ };
296
+ const stdin = this.child?.stdin;
297
+ try {
298
+ if (!stdin)
299
+ throw new Error('no session process');
300
+ stdin.write(`${JSON.stringify(request)}\n`);
301
+ }
302
+ catch {
303
+ return this.killForStuckTurn();
304
+ }
305
+ turn.killTimer = setTimeout(() => this.killForStuckTurn(), this.interruptGraceMs);
306
+ turn.killTimer.unref();
307
+ }
308
+ /** The interrupt didn't take. Kill the group; the close handler settles. */
309
+ killForStuckTurn() {
310
+ if (!this.turn)
311
+ return;
312
+ this.hooks.log('the session did not answer the interrupt — killing the process group');
313
+ const pid = this.child?.pid;
314
+ this.child = null;
315
+ this.spawnCleanup?.();
316
+ this.spawnCleanup = null;
317
+ if (pid) {
318
+ killGroup(pid, REAP_GRACE_MS);
319
+ unregisterGroup(pid);
320
+ return; // the close handler settles the turn
321
+ }
322
+ this.settleTurn(this.buildResult('the session process was gone'));
323
+ }
324
+ /**
325
+ * Rearmed by every byte the session emits *while a turn is running*. A turn
326
+ * that is still working narrates itself, so it never expires however long it
327
+ * runs; only genuine mid-turn silence does.
328
+ */
329
+ bumpIdle() {
330
+ const turn = this.turn;
331
+ if (!turn || turn.ending)
332
+ return;
333
+ if (turn.idleTimer)
334
+ clearTimeout(turn.idleTimer);
335
+ turn.idleTimer = setTimeout(() => this.endTurnEarly(`no output for ${this.cfg.idleTimeoutSec}s`), this.cfg.idleTimeoutSec * 1000);
336
+ turn.idleTimer.unref();
337
+ }
338
+ /** Spawn if needed. Returns an error string when the spawn itself failed. */
339
+ ensureProcess() {
340
+ if (this.child)
341
+ return null;
342
+ this.disposed = false;
343
+ this.parser = this.newParser();
344
+ this.stderrTail = '';
345
+ const spec = this.makeSpawn();
346
+ const args = buildClaudeArgs(this.cfg, {
347
+ sessionId: this.sessionId,
348
+ resume: this.resume,
349
+ prompt: '',
350
+ systemPrompt: spec.systemPrompt,
351
+ mcpConfigPath: spec.mcpConfigPath,
352
+ streamInput: true,
353
+ });
354
+ let child;
355
+ try {
356
+ child = spawn(this.cfg.command, args, {
357
+ cwd: this.cfg.cwd,
358
+ stdio: ['pipe', 'pipe', 'pipe'],
359
+ env: { ...process.env },
360
+ // Own process group, so a reap or a shutdown takes the agent's whole
361
+ // subprocess tree — background tasks included — and not just the CLI.
362
+ detached: true,
363
+ });
364
+ }
365
+ catch (err) {
366
+ spec.cleanup?.();
367
+ return `could not spawn ${this.cfg.command}: ${err.message}`;
368
+ }
369
+ this.child = child;
370
+ this.spawnCleanup = spec.cleanup ?? null;
371
+ if (child.pid)
372
+ registerGroup(child.pid);
373
+ this.hooks.log(`session process ${child.pid} started (${this.resume ? '--resume' : '--session-id'} ${this.sessionId})`);
374
+ child.stdin?.on('error', () => {
375
+ /* the close handler reports a dead CLI */
376
+ });
377
+ child.stdout?.on('data', (d) => {
378
+ this.bumpIdle();
379
+ this.parser.feed(d.toString('utf8'));
380
+ });
381
+ child.stderr?.on('data', (d) => {
382
+ this.bumpIdle();
383
+ this.stderrTail = `${this.stderrTail}${d.toString('utf8')}`.slice(-2000);
384
+ });
385
+ child.on('error', (err) => this.onExit(null, `could not spawn ${this.cfg.command}: ${err.message}`, child));
386
+ child.on('close', (code) => this.onExit(code, null, child));
387
+ return null;
388
+ }
389
+ /**
390
+ * The process is gone. Any turn waiting on it fails as it did before; the
391
+ * next message respawns and `--resume`s, so the conversation carries on.
392
+ */
393
+ onExit(code, spawnError, child) {
394
+ if (this.child !== null && this.child !== child)
395
+ return; // a later spawn owns us now
396
+ const pid = child.pid;
397
+ if (pid)
398
+ unregisterGroup(pid);
399
+ this.child = null;
400
+ this.spawnCleanup?.();
401
+ this.spawnCleanup = null;
402
+ this.parser.feed('\n'); // flush a trailing unterminated line
403
+ if (this.sawSession)
404
+ this.resume = true;
405
+ // Background tasks died with the process — nothing is pending any more, so
406
+ // the reaper isn't held off by ghosts.
407
+ this.parser.pending.clear();
408
+ if (!this.turn) {
409
+ if (!this.disposed)
410
+ this.hooks.log(`session process ${pid ?? '?'} exited (${spawnError ?? `code ${code}`})`);
411
+ return;
412
+ }
413
+ if (!this.resume && this.stderrTail.includes('already in use'))
414
+ this.collided = true;
415
+ const error = spawnError ??
416
+ (this.parser.sawResult
417
+ ? describeResultError(this.parser.errorSubtype, this.cfg.maxTurns)
418
+ : `runtime exited ${code} without a result${this.stderrTail ? `: ${this.stderrTail.slice(-300)}` : ''}`);
419
+ this.settleTurn(this.buildResult(error));
420
+ }
421
+ }
422
+ /** How often the reaper looks, unless a caller says otherwise. */
423
+ const DEFAULT_SWEEP_MS = 30_000;
424
+ /** The live sessions, one per conversation, plus the reaper that ends them. */
425
+ export class SessionManager {
426
+ opts;
427
+ sessions = new Map();
428
+ sweepTimer = null;
429
+ constructor(opts) {
430
+ this.opts = opts;
431
+ const every = opts.sweepMs ?? DEFAULT_SWEEP_MS;
432
+ this.sweepTimer = setInterval(() => this.sweep(), every);
433
+ this.sweepTimer.unref();
434
+ }
435
+ /** The session for a conversation, created (not spawned) on first use. */
436
+ session(key, make) {
437
+ let s = this.sessions.get(key);
438
+ if (!s) {
439
+ s = new RuntimeSession(make());
440
+ this.sessions.set(key, s);
441
+ }
442
+ return s;
443
+ }
444
+ get(key) {
445
+ return this.sessions.get(key);
446
+ }
447
+ get size() {
448
+ return this.sessions.size;
449
+ }
450
+ /** `/reset`, or a conversation going away: end the process and forget it. */
451
+ dispose(key, reason) {
452
+ const s = this.sessions.get(key);
453
+ if (!s)
454
+ return;
455
+ this.sessions.delete(key);
456
+ s.dispose(reason, 0);
457
+ }
458
+ /** Bridge shutdown: every live session process dies with us (AC 6). */
459
+ killAll() {
460
+ if (this.sweepTimer)
461
+ clearInterval(this.sweepTimer);
462
+ this.sweepTimer = null;
463
+ for (const [key, s] of this.sessions)
464
+ s.dispose(`bridge shutting down (${key})`, 0);
465
+ this.sessions.clear();
466
+ }
467
+ /** One reaper pass — exported behaviour, so tests can drive it directly. */
468
+ sweep(now = Date.now()) {
469
+ for (const [key, s] of this.sessions) {
470
+ const reason = s.reapReason(now, this.opts.idleMs, this.opts.hardCapMs);
471
+ if (!reason)
472
+ continue;
473
+ this.opts.log(`reaping the session for ${key}: ${reason} — the next message resumes it`);
474
+ this.sessions.delete(key);
475
+ // SIGTERM first: the CLI flushes its transcript, so `--resume` works.
476
+ s.dispose(reason);
477
+ }
478
+ }
479
+ }
480
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../src/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { PreparedSharedFile } from './shared-files.js';
2
+ /** Text extraction never executes macros, formulas, embedded scripts, or links. */
3
+ export declare function extractSharedFile(input: {
4
+ filePath: string;
5
+ name: string;
6
+ mimeType: string;
7
+ }): Promise<PreparedSharedFile>;
@@ -0,0 +1,93 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import path from 'node:path';
3
+ import { parentPort, workerData } from 'node:worker_threads';
4
+ import { fileURLToPath } from 'node:url';
5
+ const TEXT_LIMIT = 100_000;
6
+ /** Text extraction never executes macros, formulas, embedded scripts, or links. */
7
+ export async function extractSharedFile(input) {
8
+ const { filePath, name, mimeType } = input;
9
+ const data = await fs.readFile(filePath);
10
+ const extension = path.extname(name).toLowerCase();
11
+ const result = { name, path: filePath, text: '', images: [] };
12
+ if (['.png', '.jpg', '.jpeg', '.webp'].includes(extension)) {
13
+ const { loadImage } = await import('@napi-rs/canvas');
14
+ const image = await loadImage(data);
15
+ if (image.width * image.height > 25_000_000)
16
+ throw new Error('Image exceeds 25 megapixels');
17
+ result.images.push(filePath);
18
+ result.notice = 'Image supplied for visual inspection; no text extraction was performed.';
19
+ }
20
+ else if (extension === '.pdf') {
21
+ const { getDocument } = await import('pdfjs-dist/legacy/build/pdf.mjs');
22
+ const { createCanvas } = await import('@napi-rs/canvas');
23
+ const document = await getDocument({
24
+ data: new Uint8Array(data), isEvalSupported: false,
25
+ standardFontDataUrl: fileURLToPath(new URL('./standard_fonts/', import.meta.resolve('pdfjs-dist/package.json'))).replace(/\\/g, '/'),
26
+ }).promise;
27
+ try {
28
+ const pages = Math.min(document.numPages, 20);
29
+ for (let i = 1; i <= pages && result.text.length < TEXT_LIMIT; i++) {
30
+ const page = await document.getPage(i);
31
+ const content = await page.getTextContent();
32
+ result.text += `\n[Page ${i}]\n${content.items.map((item) => 'str' in item ? item.str : '').join(' ')}\n`;
33
+ if (i <= 4) {
34
+ const natural = page.getViewport({ scale: 1 });
35
+ const viewport = page.getViewport({ scale: Math.min(1.5, 1400 / Math.max(natural.width, natural.height)) });
36
+ const canvas = createCanvas(Math.ceil(viewport.width), Math.ceil(viewport.height));
37
+ await page.render({ canvasContext: canvas.getContext('2d'), viewport, canvas: canvas }).promise;
38
+ const imagePath = `${filePath}.page-${i}.png`;
39
+ await fs.writeFile(imagePath, canvas.toBuffer('image/png'), { mode: 0o600 });
40
+ result.images.push(imagePath);
41
+ }
42
+ page.cleanup();
43
+ }
44
+ result.notice = `PDF has ${document.numPages} pages. Text: first ${pages} pages (up to ${TEXT_LIMIT} characters). Visual previews: first ${Math.min(pages, 4)} pages only. Scanned pages require visual inspection; do not infer unseen pages.`;
45
+ }
46
+ finally {
47
+ await document.destroy();
48
+ }
49
+ }
50
+ else if (extension === '.docx') {
51
+ const mammoth = await import('mammoth');
52
+ result.text = (await mammoth.extractRawText({ buffer: data })).value;
53
+ result.notice = 'Document text only; embedded images and layout are not extracted.';
54
+ }
55
+ else if (extension === '.xlsx') {
56
+ const { default: ExcelJS } = await import('exceljs');
57
+ const workbook = new ExcelJS.Workbook();
58
+ await workbook.xlsx.load(data);
59
+ for (const sheet of workbook.worksheets.slice(0, 10)) {
60
+ result.text += `\n[Sheet ${sheet.name}]\n`;
61
+ sheet.eachRow((row, index) => {
62
+ if (index > 500 || result.text.length >= TEXT_LIMIT)
63
+ return;
64
+ const cells = [];
65
+ row.eachCell((cell, col) => { if (col <= 40)
66
+ cells.push(`${cell.address}: ${cell.text}`); });
67
+ result.text += `${cells.join(' | ')}\n`;
68
+ });
69
+ }
70
+ result.notice = 'Values from up to 10 sheets, 500 rows and 40 columns per sheet. Formulas are not recalculated; charts/images are not extracted.';
71
+ }
72
+ else if (mimeType.startsWith('text/') || ['.txt', '.md', '.csv', '.json', '.yaml', '.yml', '.xml', '.html', '.js', '.ts', '.tsx', '.py', '.css', '.log', '.sql'].includes(extension)) {
73
+ if (data.includes(0))
74
+ throw new Error('This file is binary, not readable text');
75
+ result.text = data.toString('utf8');
76
+ }
77
+ else {
78
+ throw new Error('Unsupported call format. Send text, PDF, PNG/JPEG/WebP, DOCX, or XLSX. Audio/video and legacy Office files are not decoded.');
79
+ }
80
+ if (result.text.length > TEXT_LIMIT)
81
+ result.notice = `${result.notice ?? ''} Text truncated at ${TEXT_LIMIT} characters.`.trim();
82
+ result.text = result.text.slice(0, TEXT_LIMIT);
83
+ if (result.text) {
84
+ const extracted = `${filePath}.extracted.txt`;
85
+ await fs.writeFile(extracted, result.text, { mode: 0o600 });
86
+ result.notice = `${result.notice ?? ''} Extracted text saved at ${extracted}.`.trim();
87
+ }
88
+ return result;
89
+ }
90
+ if (parentPort) {
91
+ void extractSharedFile(workerData).then((result) => parentPort.postMessage({ result }), (error) => parentPort.postMessage({ error: error instanceof Error ? error.message : 'Document could not be opened' }));
92
+ }
93
+ //# sourceMappingURL=shared-file-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-file-worker.js","sourceRoot":"","sources":["../src/shared-file-worker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,UAAU,GAAG,OAAO,CAAC;AAC3B,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAEvC;IACC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAC3C,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,MAAM,GAAuB,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAClF,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QAC5F,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,GAAG,yEAAyE,CAAC;IAC5F,CAAC;SAAM,IAAI,SAAS,KAAK,MAAM,EAAE,CAAC;QAChC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,iCAAiC,CAAC,CAAC;QACxE,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;QACzD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC;YACjC,IAAI,EAAE,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,eAAe,EAAE,KAAK;YAClD,mBAAmB,EAAE,aAAa,CAAC,IAAI,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC;SACrI,CAAC,CAAC,OAAO,CAAC;QACX,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;YAC9C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;gBACnE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBACvC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;gBAC5C,MAAM,CAAC,IAAI,IAAI,WAAW,CAAC,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;gBAC1G,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACX,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;oBAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC;oBAC5G,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;oBACnF,MAAM,IAAI,CAAC,MAAM,CAAC,EAAE,aAAa,EAAE,MAAM,CAAC,UAAU,CAAC,IAAI,CAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAe,EAAE,CAAC,CAAC,OAAO,CAAC;oBAClH,MAAM,SAAS,GAAG,GAAG,QAAQ,SAAS,CAAC,MAAM,CAAC;oBAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;oBAC7E,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gBAChC,CAAC;gBACD,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,CAAC;YACD,MAAM,CAAC,MAAM,GAAG,WAAW,QAAQ,CAAC,QAAQ,uBAAuB,KAAK,iBAAiB,UAAU,wCAAwC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,kFAAkF,CAAC;QAClP,CAAC;gBAAS,CAAC;YAAC,MAAM,QAAQ,CAAC,OAAO,EAAE,CAAC;QAAC,CAAC;IACzC,CAAC;SAAM,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QACxC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,cAAc,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QACrE,MAAM,CAAC,MAAM,GAAG,mEAAmE,CAAC;IACtF,CAAC;SAAM,IAAI,SAAS,KAAK,OAAO,EAAE,CAAC;QACjC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,QAAQ,GAAG,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACxC,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAa,CAAC,CAAC;QACxC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;YACrD,MAAM,CAAC,IAAI,IAAI,YAAY,KAAK,CAAC,IAAI,KAAK,CAAC;YAC3C,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;gBAC3B,IAAI,KAAK,GAAG,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,IAAI,UAAU;oBAAE,OAAO;gBAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;gBAC3B,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE;oBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC7F,MAAM,CAAC,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1C,CAAC,CAAC,CAAC;QACL,CAAC;QACD,MAAM,CAAC,MAAM,GAAG,iIAAiI,CAAC;IACpJ,CAAC;SAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACvL,IAAI,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;QAChF,MAAM,CAAC,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,KAAK,CAAC,6HAA6H,CAAC,CAAC;IACjJ,CAAC;IACD,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,UAAU;QAAE,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,sBAAsB,UAAU,cAAc,CAAC,IAAI,EAAE,CAAC;IACjI,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC/C,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,MAAM,SAAS,GAAG,GAAG,QAAQ,gBAAgB,CAAC;QAC9C,MAAM,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5D,MAAM,CAAC,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,4BAA4B,SAAS,GAAG,CAAC,IAAI,EAAE,CAAC;IACxF,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,IAAI,UAAU,EAAE,CAAC;IACf,KAAK,iBAAiB,CAAC,UAAU,CAAC,CAAC,IAAI,CACrC,CAAC,MAAM,EAAE,EAAE,CAAC,UAAW,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC,EAC/C,CAAC,KAAc,EAAE,EAAE,CAAC,UAAW,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,8BAA8B,EAAE,CAAC,CAChI,CAAC;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { FileDTO } from '@flow/shared';
2
+ export declare const MAX_SHARED_FILE_BYTES: number;
3
+ export interface PreparedSharedFile {
4
+ name: string;
5
+ path: string;
6
+ text: string;
7
+ images: string[];
8
+ notice?: string;
9
+ }
10
+ /** A cancellable worker keeps malformed/expensive documents off the audio loop. */
11
+ export declare function prepareSharedFile(file: FileDTO, directory: string, download: (id: string, signal: AbortSignal) => Promise<Buffer>, signal: AbortSignal): Promise<PreparedSharedFile>;