@dreb/dashboard 2.64.0 → 2.64.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.
@@ -28,6 +28,7 @@ export declare class DashboardImagePreviewError extends Error {
28
28
  export declare class DashboardImageService {
29
29
  private readonly previews;
30
30
  private readonly images;
31
+ private readonly originalFlights;
31
32
  private readonly previewFlights;
32
33
  private readonly maxBytes;
33
34
  private readonly maxRecords;
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-images.d.ts","sourceRoot":"","sources":["../../src/server/dashboard-images.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAEN,KAAK,qBAAqB,EAI1B,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAC5D,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAClD,eAAO,MAAM,0BAA0B,QAAmB,CAAC;AAC3D,eAAO,MAAM,0BAA0B,8DAKrC,CAAC;AAEH,MAAM,WAAW,mBAAmB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,+BAA+B;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA2ED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CASxG;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAE5E;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAY7F;AAED,qBAAa,2BAA4B,SAAQ,KAAK;CAAG;AACzD,qBAAa,0BAA2B,SAAQ,KAAK;CAAG;AAExD,oEAAoE;AACpE,qBAAa,qBAAqB;IAUhC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAT1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoD;IACnF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAK;IAElB,YACkB,QAAQ,EAAE,qBAAqB,EAChD,OAAO,GAAE,+BAAoC,EAI7C;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,gFAAgF;IAChF,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEhG;IAED,4DAA4D;IAC5D,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,mBAAmB,GAAG,CAAC,CAGlD;IAEK,QAAQ,CACb,KAAK,EAAE,mBAAmB,EAC1B,EAAE,EAAE,MAAM,EACV,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GACvC,OAAO,CAAC,oBAAoB,CAAC,CAI/B;IAEK,OAAO,CACZ,KAAK,EAAE,mBAAmB,EAC1B,EAAE,EAAE,MAAM,EACV,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GACvC,OAAO,CAAC,oBAAoB,CAAC,CAuC/B;IAED,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAOtC;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;IAED,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;YAaP,eAAe;IA2B7B,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,WAAW;CAQnB","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { DashboardImageReferenceDto } from \"../shared/protocol.js\";\nimport {\n\ttype GeneratedImagePreview,\n\ttype ImagePreviewGenerator,\n\tMAX_PREVIEW_BYTES,\n\tMAX_PREVIEW_HEIGHT,\n\tMAX_PREVIEW_WIDTH,\n} from \"./image-preview.js\";\n\nexport const DASHBOARD_IMAGE_CACHE_BYTES = 64 * 1024 * 1024;\nexport const DASHBOARD_IMAGE_CACHE_RECORDS = 2000;\nexport const DASHBOARD_IMAGE_ID_PATTERN = /^[0-9a-f]{64}$/;\nexport const DASHBOARD_IMAGE_MIME_TYPES = new Set<DashboardImageReferenceDto[\"mimeType\"]>([\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n]);\n\nexport interface DashboardImageScope {\n\truntimeKey: string;\n\tagentId?: string;\n}\n\nexport interface DashboardImageBinary {\n\tbytes: Uint8Array;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n}\n\nexport interface DashboardImageRepositoryOptions {\n\tmaxBytes?: number;\n\tmaxRecords?: number;\n}\n\ninterface CachedVariant extends DashboardImageBinary {\n\tlastUsed: number;\n}\n\ninterface CachedImage {\n\tid: string;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n\tsize: number;\n\tscopes: Set<string>;\n\toriginal?: CachedVariant;\n\tpreview?: CachedVariant;\n}\n\nconst DROP = Symbol(\"drop-dashboard-image\");\nconst JPEG_EOI = Buffer.from([0xff, 0xd9]);\n\nfunction scopeKey(scope: DashboardImageScope): string {\n\treturn `${scope.runtimeKey}\\0${scope.agentId ?? \"\"}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasRasterSignature(mimeType: DashboardImageReferenceDto[\"mimeType\"], bytes: Uint8Array): boolean {\n\tconst buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\tswitch (mimeType) {\n\t\tcase \"image/png\": {\n\t\t\tconst signature =\n\t\t\t\tbytes.length >= 24 &&\n\t\t\t\t[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every((byte, i) => bytes[i] === byte);\n\t\t\treturn (\n\t\t\t\tsignature &&\n\t\t\t\tbuffer.subarray(12, 16).toString(\"ascii\") === \"IHDR\" &&\n\t\t\t\tbuffer.readUInt32BE(16) > 0 &&\n\t\t\t\tbuffer.readUInt32BE(20) > 0 &&\n\t\t\t\tbuffer.indexOf(Buffer.from(\"IEND\"), 24) >= 0\n\t\t\t);\n\t\t}\n\t\tcase \"image/jpeg\": {\n\t\t\tif (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes[2] !== 0xff) return false;\n\t\t\t// EOI does not have to be the final byte. Phone JPEGs commonly append\n\t\t\t// auxiliary gain-map, motion-photo, or vendor metadata after the primary\n\t\t\t// image. Browsers and Photon decode the JPEG through EOI and preserve the\n\t\t\t// trailing bytes when the exact original is requested.\n\t\t\treturn buffer.lastIndexOf(JPEG_EOI) >= 2;\n\t\t}\n\t\tcase \"image/gif\": {\n\t\t\tconst header = buffer.subarray(0, 6).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbytes.length >= 14 &&\n\t\t\t\t(header === \"GIF87a\" || header === \"GIF89a\") &&\n\t\t\t\tbuffer.readUInt16LE(6) > 0 &&\n\t\t\t\tbuffer.readUInt16LE(8) > 0 &&\n\t\t\t\tbytes[bytes.length - 1] === 0x3b\n\t\t\t);\n\t\t}\n\t\tcase \"image/webp\": {\n\t\t\tif (\n\t\t\t\tbytes.length < 20 ||\n\t\t\t\tbuffer.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n\t\t\t\tbuffer.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst chunk = buffer.subarray(12, 16).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbuffer.readUInt32LE(4) + 8 <= bytes.length && (chunk === \"VP8 \" || chunk === \"VP8L\" || chunk === \"VP8X\")\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** Strict standard base64 decode: whitespace, data URLs, and non-canonical padding are rejected. */\nexport function decodeDashboardImage(value: unknown, mimeType: unknown): DashboardImageBinary | undefined {\n\tif (typeof value !== \"string\" || typeof mimeType !== \"string\") return undefined;\n\tif (!DASHBOARD_IMAGE_MIME_TYPES.has(mimeType as DashboardImageReferenceDto[\"mimeType\"])) return undefined;\n\tif (value.length === 0 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(value)) return undefined;\n\tconst bytes = Buffer.from(value, \"base64\");\n\tif (bytes.toString(\"base64\") !== value) return undefined;\n\tconst exactMimeType = mimeType as DashboardImageReferenceDto[\"mimeType\"];\n\tif (!hasRasterSignature(exactMimeType, bytes)) return undefined;\n\treturn { bytes, mimeType: exactMimeType };\n}\n\nexport function dashboardImageId(mimeType: string, bytes: Uint8Array): string {\n\treturn createHash(\"sha256\").update(mimeType).update(Uint8Array.of(0)).update(bytes).digest(\"hex\");\n}\n\nexport function isDashboardImageReference(value: unknown): value is DashboardImageReferenceDto {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\tvalue.type === \"image_reference\" &&\n\t\ttypeof value.id === \"string\" &&\n\t\tDASHBOARD_IMAGE_ID_PATTERN.test(value.id) &&\n\t\ttypeof value.mimeType === \"string\" &&\n\t\tDASHBOARD_IMAGE_MIME_TYPES.has(value.mimeType as DashboardImageReferenceDto[\"mimeType\"]) &&\n\t\ttypeof value.size === \"number\" &&\n\t\tNumber.isSafeInteger(value.size) &&\n\t\tvalue.size > 0\n\t);\n}\n\nexport class DashboardImageNotFoundError extends Error {}\nexport class DashboardImagePreviewError extends Error {}\n\n/** Synchronous projection + bounded original/preview repository. */\nexport class DashboardImageService {\n\tprivate readonly images = new Map<string, CachedImage>();\n\tprivate readonly previewFlights = new Map<string, Promise<DashboardImageBinary>>();\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRecords: number;\n\tprivate usedBytes = 0;\n\tprivate usedRecords = 0;\n\tprivate clock = 0;\n\n\tconstructor(\n\t\tprivate readonly previews: ImagePreviewGenerator,\n\t\toptions: DashboardImageRepositoryOptions = {},\n\t) {\n\t\tthis.maxBytes = options.maxBytes ?? DASHBOARD_IMAGE_CACHE_BYTES;\n\t\tthis.maxRecords = options.maxRecords ?? DASHBOARD_IMAGE_CACHE_RECORDS;\n\t}\n\n\tget byteSize(): number {\n\t\treturn this.usedBytes;\n\t}\n\n\tget recordCount(): number {\n\t\treturn this.usedRecords;\n\t}\n\n\t/** Project a browser-facing event without mutating the authoritative source. */\n\tprojectEvent(event: Record<string, unknown>, scope: DashboardImageScope): Record<string, unknown> {\n\t\treturn this.projectNode(event, scope) as Record<string, unknown>;\n\t}\n\n\t/** Project messages/snapshots before JSON serialization. */\n\tproject<T>(value: T, scope: DashboardImageScope): T {\n\t\tconst projected = this.projectNode(value, scope);\n\t\treturn (projected === DROP ? undefined : projected) as T;\n\t}\n\n\tasync original(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"original\");\n\t\tif (cached) return cached;\n\t\treturn this.recoverOriginal(scope, id, loadAuthoritative);\n\t}\n\n\tasync preview(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"preview\");\n\t\tif (cached) return cached;\n\t\t// Authorize/recover this scope before joining a content-global flight. A\n\t\t// guessed ID from another runtime must not piggyback its in-flight preview.\n\t\tconst original = await this.original(scope, id, loadAuthoritative);\n\t\tconst recoveredPreview = this.cachedVariant(scope, id, \"preview\");\n\t\tif (recoveredPreview) return recoveredPreview;\n\t\tconst flight = this.previewFlights.get(id);\n\t\tif (flight) return flight;\n\t\tconst promise = (async () => {\n\t\t\tlet generated: GeneratedImagePreview;\n\t\t\ttry {\n\t\t\t\tgenerated = await this.previews.generate(original.bytes, original.mimeType);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new DashboardImagePreviewError(\n\t\t\t\t\t`Preview generation failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tgenerated.bytes.byteLength > MAX_PREVIEW_BYTES ||\n\t\t\t\tgenerated.width < 1 ||\n\t\t\t\tgenerated.height < 1 ||\n\t\t\t\tgenerated.width > MAX_PREVIEW_WIDTH ||\n\t\t\t\tgenerated.height > MAX_PREVIEW_HEIGHT ||\n\t\t\t\t(generated.mimeType !== \"image/png\" && generated.mimeType !== \"image/jpeg\")\n\t\t\t) {\n\t\t\t\tthrow new DashboardImagePreviewError(\"Preview worker returned an invalid or over-budget image\");\n\t\t\t}\n\t\t\tconst binary: DashboardImageBinary = { bytes: generated.bytes, mimeType: generated.mimeType };\n\t\t\tthis.putVariant(id, scope, \"preview\", binary);\n\t\t\treturn binary;\n\t\t})();\n\t\tthis.previewFlights.set(id, promise);\n\t\ttry {\n\t\t\treturn await promise;\n\t\t} finally {\n\t\t\tthis.previewFlights.delete(id);\n\t\t}\n\t}\n\n\tremoveRuntime(runtimeKey: string): void {\n\t\tfor (const image of [...this.images.values()]) {\n\t\t\tfor (const key of image.scopes) {\n\t\t\t\tif (key === runtimeKey || key.startsWith(`${runtimeKey}\\0`)) image.scopes.delete(key);\n\t\t\t}\n\t\t\tif (image.scopes.size === 0) this.deleteImage(image);\n\t\t}\n\t}\n\n\tclose(): Promise<void> {\n\t\treturn this.previews.close();\n\t}\n\n\tprivate projectNode(value: unknown, scope: DashboardImageScope): unknown | typeof DROP {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst projected: unknown[] = [];\n\t\t\tfor (const item of value) {\n\t\t\t\tconst next = this.projectNode(item, scope);\n\t\t\t\tif (next !== DROP) projected.push(next);\n\t\t\t}\n\t\t\treturn projected;\n\t\t}\n\t\tif (!isRecord(value)) return value;\n\t\tif (value.type === \"image\") {\n\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\tif (!image) return DROP;\n\t\t\treturn this.insertOriginal(scope, image);\n\t\t}\n\t\tif (value.type === \"image_reference\") return isDashboardImageReference(value) ? { ...value } : DROP;\n\t\tconst childScope =\n\t\t\tvalue.type === \"background_agent_event\" && typeof value.agentId === \"string\"\n\t\t\t\t? { runtimeKey: scope.runtimeKey, agentId: value.agentId }\n\t\t\t\t: scope;\n\t\tconst copy: Record<string, unknown> = {};\n\t\tfor (const [key, item] of Object.entries(value)) {\n\t\t\tconst next = this.projectNode(item, key === \"event\" ? childScope : scope);\n\t\t\tif (next !== DROP) copy[key] = next;\n\t\t}\n\t\treturn copy;\n\t}\n\n\tprivate insertOriginal(scope: DashboardImageScope, binary: DashboardImageBinary): DashboardImageReferenceDto {\n\t\tconst id = dashboardImageId(binary.mimeType, binary.bytes);\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tif (!image.original) this.putVariant(id, scope, \"original\", binary);\n\t\telse image.original.lastUsed = ++this.clock;\n\t\treturn { type: \"image_reference\", id, mimeType: binary.mimeType, size: binary.bytes.byteLength };\n\t}\n\n\tprivate cachedVariant(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tvariant: \"original\" | \"preview\",\n\t): DashboardImageBinary | undefined {\n\t\tconst image = this.images.get(id);\n\t\tif (!image || !image.scopes.has(scopeKey(scope))) return undefined;\n\t\tconst cached = image[variant];\n\t\tif (!cached) return undefined;\n\t\tcached.lastUsed = ++this.clock;\n\t\treturn { bytes: cached.bytes, mimeType: cached.mimeType };\n\t}\n\n\tprivate async recoverOriginal(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst source = await loadAuthoritative();\n\t\tlet recovered: DashboardImageBinary | undefined;\n\t\tconst visit = (value: unknown): void => {\n\t\t\tif (recovered) return;\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const item of value) visit(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!isRecord(value)) return;\n\t\t\tif (value.type === \"image\") {\n\t\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\t\tif (image && dashboardImageId(image.mimeType, image.bytes) === id) recovered = image;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const item of Object.values(value)) visit(item);\n\t\t};\n\t\tvisit(source);\n\t\tif (!recovered) throw new DashboardImageNotFoundError(\"Image is no longer available from this transcript\");\n\t\tthis.insertOriginal(scope, recovered);\n\t\treturn recovered;\n\t}\n\n\tprivate putVariant(\n\t\tid: string,\n\t\tscope: DashboardImageScope,\n\t\tvariant: \"original\" | \"preview\",\n\t\tbinary: DashboardImageBinary,\n\t): void {\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tconst previous = image[variant];\n\t\tif (previous) {\n\t\t\tthis.usedBytes -= previous.bytes.byteLength;\n\t\t} else {\n\t\t\tthis.usedRecords += 1;\n\t\t}\n\t\timage[variant] = { bytes: binary.bytes, mimeType: binary.mimeType, lastUsed: ++this.clock };\n\t\tthis.usedBytes += binary.bytes.byteLength;\n\t\tthis.evict();\n\t}\n\n\tprivate evict(): void {\n\t\twhile (this.usedBytes > this.maxBytes || this.usedRecords > this.maxRecords) {\n\t\t\tlet oldest: { image: CachedImage; variant: \"original\" | \"preview\"; lastUsed: number } | undefined;\n\t\t\tfor (const image of this.images.values()) {\n\t\t\t\tfor (const variant of [\"original\", \"preview\"] as const) {\n\t\t\t\t\tconst candidate = image[variant];\n\t\t\t\t\tif (candidate && (!oldest || candidate.lastUsed < oldest.lastUsed)) {\n\t\t\t\t\t\toldest = { image, variant, lastUsed: candidate.lastUsed };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!oldest) break;\n\t\t\tconst removed = oldest.image[oldest.variant]!;\n\t\t\tthis.usedBytes -= removed.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t\tdelete oldest.image[oldest.variant];\n\t\t\tif (!oldest.image.original && !oldest.image.preview) this.images.delete(oldest.image.id);\n\t\t}\n\t}\n\n\tprivate deleteImage(image: CachedImage): void {\n\t\tfor (const variant of [image.original, image.preview]) {\n\t\t\tif (!variant) continue;\n\t\t\tthis.usedBytes -= variant.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t}\n\t\tthis.images.delete(image.id);\n\t}\n}\n"]}
1
+ {"version":3,"file":"dashboard-images.d.ts","sourceRoot":"","sources":["../../src/server/dashboard-images.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAEN,KAAK,qBAAqB,EAI1B,MAAM,oBAAoB,CAAC;AAE5B,eAAO,MAAM,2BAA2B,QAAmB,CAAC;AAC5D,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAClD,eAAO,MAAM,0BAA0B,QAAmB,CAAC;AAC3D,eAAO,MAAM,0BAA0B,8DAKrC,CAAC;AAEH,MAAM,WAAW,mBAAmB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACpC,KAAK,EAAE,UAAU,CAAC;IAClB,QAAQ,EAAE,0BAA0B,CAAC,UAAU,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,+BAA+B;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA2ED,oGAAoG;AACpG,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,GAAG,oBAAoB,GAAG,SAAS,CASxG;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,MAAM,CAE5E;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,0BAA0B,CAY7F;AAED,qBAAa,2BAA4B,SAAQ,KAAK;CAAG;AACzD,qBAAa,0BAA2B,SAAQ,KAAK;CAAG;AAExD,oEAAoE;AACpE,qBAAa,qBAAqB;IAWhC,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAV1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoD;IACpF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAoD;IACnF,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,KAAK,CAAK;IAElB,YACkB,QAAQ,EAAE,qBAAqB,EAChD,OAAO,GAAE,+BAAoC,EAI7C;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,gFAAgF;IAChF,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,mBAAmB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEhG;IAED,4DAA4D;IAC5D,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,mBAAmB,GAAG,CAAC,CAGlD;IAEK,QAAQ,CACb,KAAK,EAAE,mBAAmB,EAC1B,EAAE,EAAE,MAAM,EACV,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GACvC,OAAO,CAAC,oBAAoB,CAAC,CAmB/B;IAEK,OAAO,CACZ,KAAK,EAAE,mBAAmB,EAC1B,EAAE,EAAE,MAAM,EACV,iBAAiB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,GACvC,OAAO,CAAC,oBAAoB,CAAC,CAuC/B;IAED,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAOtC;IAED,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAErB;IAED,OAAO,CAAC,WAAW;IA4BnB,OAAO,CAAC,cAAc;IAatB,OAAO,CAAC,aAAa;YAaP,eAAe;IA2B7B,OAAO,CAAC,UAAU;IAuBlB,OAAO,CAAC,KAAK;IAoBb,OAAO,CAAC,WAAW;CAQnB","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { DashboardImageReferenceDto } from \"../shared/protocol.js\";\nimport {\n\ttype GeneratedImagePreview,\n\ttype ImagePreviewGenerator,\n\tMAX_PREVIEW_BYTES,\n\tMAX_PREVIEW_HEIGHT,\n\tMAX_PREVIEW_WIDTH,\n} from \"./image-preview.js\";\n\nexport const DASHBOARD_IMAGE_CACHE_BYTES = 64 * 1024 * 1024;\nexport const DASHBOARD_IMAGE_CACHE_RECORDS = 2000;\nexport const DASHBOARD_IMAGE_ID_PATTERN = /^[0-9a-f]{64}$/;\nexport const DASHBOARD_IMAGE_MIME_TYPES = new Set<DashboardImageReferenceDto[\"mimeType\"]>([\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n]);\n\nexport interface DashboardImageScope {\n\truntimeKey: string;\n\tagentId?: string;\n}\n\nexport interface DashboardImageBinary {\n\tbytes: Uint8Array;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n}\n\nexport interface DashboardImageRepositoryOptions {\n\tmaxBytes?: number;\n\tmaxRecords?: number;\n}\n\ninterface CachedVariant extends DashboardImageBinary {\n\tlastUsed: number;\n}\n\ninterface CachedImage {\n\tid: string;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n\tsize: number;\n\tscopes: Set<string>;\n\toriginal?: CachedVariant;\n\tpreview?: CachedVariant;\n}\n\nconst DROP = Symbol(\"drop-dashboard-image\");\nconst JPEG_EOI = Buffer.from([0xff, 0xd9]);\n\nfunction scopeKey(scope: DashboardImageScope): string {\n\treturn `${scope.runtimeKey}\\0${scope.agentId ?? \"\"}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasRasterSignature(mimeType: DashboardImageReferenceDto[\"mimeType\"], bytes: Uint8Array): boolean {\n\tconst buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\tswitch (mimeType) {\n\t\tcase \"image/png\": {\n\t\t\tconst signature =\n\t\t\t\tbytes.length >= 24 &&\n\t\t\t\t[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every((byte, i) => bytes[i] === byte);\n\t\t\treturn (\n\t\t\t\tsignature &&\n\t\t\t\tbuffer.subarray(12, 16).toString(\"ascii\") === \"IHDR\" &&\n\t\t\t\tbuffer.readUInt32BE(16) > 0 &&\n\t\t\t\tbuffer.readUInt32BE(20) > 0 &&\n\t\t\t\tbuffer.indexOf(Buffer.from(\"IEND\"), 24) >= 0\n\t\t\t);\n\t\t}\n\t\tcase \"image/jpeg\": {\n\t\t\tif (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes[2] !== 0xff) return false;\n\t\t\t// EOI does not have to be the final byte. Phone JPEGs commonly append\n\t\t\t// auxiliary gain-map, motion-photo, or vendor metadata after the primary\n\t\t\t// image. Browsers and Photon decode the JPEG through EOI and preserve the\n\t\t\t// trailing bytes when the exact original is requested.\n\t\t\treturn buffer.lastIndexOf(JPEG_EOI) >= 2;\n\t\t}\n\t\tcase \"image/gif\": {\n\t\t\tconst header = buffer.subarray(0, 6).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbytes.length >= 14 &&\n\t\t\t\t(header === \"GIF87a\" || header === \"GIF89a\") &&\n\t\t\t\tbuffer.readUInt16LE(6) > 0 &&\n\t\t\t\tbuffer.readUInt16LE(8) > 0 &&\n\t\t\t\tbytes[bytes.length - 1] === 0x3b\n\t\t\t);\n\t\t}\n\t\tcase \"image/webp\": {\n\t\t\tif (\n\t\t\t\tbytes.length < 20 ||\n\t\t\t\tbuffer.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n\t\t\t\tbuffer.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst chunk = buffer.subarray(12, 16).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbuffer.readUInt32LE(4) + 8 <= bytes.length && (chunk === \"VP8 \" || chunk === \"VP8L\" || chunk === \"VP8X\")\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** Strict standard base64 decode: whitespace, data URLs, and non-canonical padding are rejected. */\nexport function decodeDashboardImage(value: unknown, mimeType: unknown): DashboardImageBinary | undefined {\n\tif (typeof value !== \"string\" || typeof mimeType !== \"string\") return undefined;\n\tif (!DASHBOARD_IMAGE_MIME_TYPES.has(mimeType as DashboardImageReferenceDto[\"mimeType\"])) return undefined;\n\tif (value.length === 0 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(value)) return undefined;\n\tconst bytes = Buffer.from(value, \"base64\");\n\tif (bytes.toString(\"base64\") !== value) return undefined;\n\tconst exactMimeType = mimeType as DashboardImageReferenceDto[\"mimeType\"];\n\tif (!hasRasterSignature(exactMimeType, bytes)) return undefined;\n\treturn { bytes, mimeType: exactMimeType };\n}\n\nexport function dashboardImageId(mimeType: string, bytes: Uint8Array): string {\n\treturn createHash(\"sha256\").update(mimeType).update(Uint8Array.of(0)).update(bytes).digest(\"hex\");\n}\n\nexport function isDashboardImageReference(value: unknown): value is DashboardImageReferenceDto {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\tvalue.type === \"image_reference\" &&\n\t\ttypeof value.id === \"string\" &&\n\t\tDASHBOARD_IMAGE_ID_PATTERN.test(value.id) &&\n\t\ttypeof value.mimeType === \"string\" &&\n\t\tDASHBOARD_IMAGE_MIME_TYPES.has(value.mimeType as DashboardImageReferenceDto[\"mimeType\"]) &&\n\t\ttypeof value.size === \"number\" &&\n\t\tNumber.isSafeInteger(value.size) &&\n\t\tvalue.size > 0\n\t);\n}\n\nexport class DashboardImageNotFoundError extends Error {}\nexport class DashboardImagePreviewError extends Error {}\n\n/** Synchronous projection + bounded original/preview repository. */\nexport class DashboardImageService {\n\tprivate readonly images = new Map<string, CachedImage>();\n\tprivate readonly originalFlights = new Map<string, Promise<DashboardImageBinary>>();\n\tprivate readonly previewFlights = new Map<string, Promise<DashboardImageBinary>>();\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRecords: number;\n\tprivate usedBytes = 0;\n\tprivate usedRecords = 0;\n\tprivate clock = 0;\n\n\tconstructor(\n\t\tprivate readonly previews: ImagePreviewGenerator,\n\t\toptions: DashboardImageRepositoryOptions = {},\n\t) {\n\t\tthis.maxBytes = options.maxBytes ?? DASHBOARD_IMAGE_CACHE_BYTES;\n\t\tthis.maxRecords = options.maxRecords ?? DASHBOARD_IMAGE_CACHE_RECORDS;\n\t}\n\n\tget byteSize(): number {\n\t\treturn this.usedBytes;\n\t}\n\n\tget recordCount(): number {\n\t\treturn this.usedRecords;\n\t}\n\n\t/** Project a browser-facing event without mutating the authoritative source. */\n\tprojectEvent(event: Record<string, unknown>, scope: DashboardImageScope): Record<string, unknown> {\n\t\treturn this.projectNode(event, scope) as Record<string, unknown>;\n\t}\n\n\t/** Project messages/snapshots before JSON serialization. */\n\tproject<T>(value: T, scope: DashboardImageScope): T {\n\t\tconst projected = this.projectNode(value, scope);\n\t\treturn (projected === DROP ? undefined : projected) as T;\n\t}\n\n\tasync original(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"original\");\n\t\tif (cached) return cached;\n\t\t// Single-flight authoritative recovery per scope+id. In originals display\n\t\t// mode the browser auto-fetches every tool-result image, so N concurrent\n\t\t// cache misses for distinct ids would each trigger a full authoritative\n\t\t// (getMessages) re-fetch over the same RPC pipe. Coalescing the concurrent\n\t\t// misses for one id collapses them into a single load. The key is\n\t\t// scope-bound so requesters from another runtime/agent never piggyback.\n\t\tconst key = `${scopeKey(scope)}\\0${id}`;\n\t\tconst flight = this.originalFlights.get(key);\n\t\tif (flight) return flight;\n\t\tconst promise = this.recoverOriginal(scope, id, loadAuthoritative);\n\t\tthis.originalFlights.set(key, promise);\n\t\ttry {\n\t\t\treturn await promise;\n\t\t} finally {\n\t\t\tthis.originalFlights.delete(key);\n\t\t}\n\t}\n\n\tasync preview(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"preview\");\n\t\tif (cached) return cached;\n\t\t// Authorize/recover this scope before joining a content-global flight. A\n\t\t// guessed ID from another runtime must not piggyback its in-flight preview.\n\t\tconst original = await this.original(scope, id, loadAuthoritative);\n\t\tconst recoveredPreview = this.cachedVariant(scope, id, \"preview\");\n\t\tif (recoveredPreview) return recoveredPreview;\n\t\tconst flight = this.previewFlights.get(id);\n\t\tif (flight) return flight;\n\t\tconst promise = (async () => {\n\t\t\tlet generated: GeneratedImagePreview;\n\t\t\ttry {\n\t\t\t\tgenerated = await this.previews.generate(original.bytes, original.mimeType);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new DashboardImagePreviewError(\n\t\t\t\t\t`Preview generation failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tgenerated.bytes.byteLength > MAX_PREVIEW_BYTES ||\n\t\t\t\tgenerated.width < 1 ||\n\t\t\t\tgenerated.height < 1 ||\n\t\t\t\tgenerated.width > MAX_PREVIEW_WIDTH ||\n\t\t\t\tgenerated.height > MAX_PREVIEW_HEIGHT ||\n\t\t\t\t(generated.mimeType !== \"image/png\" && generated.mimeType !== \"image/jpeg\")\n\t\t\t) {\n\t\t\t\tthrow new DashboardImagePreviewError(\"Preview worker returned an invalid or over-budget image\");\n\t\t\t}\n\t\t\tconst binary: DashboardImageBinary = { bytes: generated.bytes, mimeType: generated.mimeType };\n\t\t\tthis.putVariant(id, scope, \"preview\", binary);\n\t\t\treturn binary;\n\t\t})();\n\t\tthis.previewFlights.set(id, promise);\n\t\ttry {\n\t\t\treturn await promise;\n\t\t} finally {\n\t\t\tthis.previewFlights.delete(id);\n\t\t}\n\t}\n\n\tremoveRuntime(runtimeKey: string): void {\n\t\tfor (const image of [...this.images.values()]) {\n\t\t\tfor (const key of image.scopes) {\n\t\t\t\tif (key === runtimeKey || key.startsWith(`${runtimeKey}\\0`)) image.scopes.delete(key);\n\t\t\t}\n\t\t\tif (image.scopes.size === 0) this.deleteImage(image);\n\t\t}\n\t}\n\n\tclose(): Promise<void> {\n\t\treturn this.previews.close();\n\t}\n\n\tprivate projectNode(value: unknown, scope: DashboardImageScope): unknown | typeof DROP {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst projected: unknown[] = [];\n\t\t\tfor (const item of value) {\n\t\t\t\tconst next = this.projectNode(item, scope);\n\t\t\t\tif (next !== DROP) projected.push(next);\n\t\t\t}\n\t\t\treturn projected;\n\t\t}\n\t\tif (!isRecord(value)) return value;\n\t\tif (value.type === \"image\") {\n\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\tif (!image) return DROP;\n\t\t\treturn this.insertOriginal(scope, image);\n\t\t}\n\t\tif (value.type === \"image_reference\") return isDashboardImageReference(value) ? { ...value } : DROP;\n\t\tconst childScope =\n\t\t\tvalue.type === \"background_agent_event\" && typeof value.agentId === \"string\"\n\t\t\t\t? { runtimeKey: scope.runtimeKey, agentId: value.agentId }\n\t\t\t\t: scope;\n\t\tconst copy: Record<string, unknown> = {};\n\t\tfor (const [key, item] of Object.entries(value)) {\n\t\t\tconst next = this.projectNode(item, key === \"event\" ? childScope : scope);\n\t\t\tif (next !== DROP) copy[key] = next;\n\t\t}\n\t\treturn copy;\n\t}\n\n\tprivate insertOriginal(scope: DashboardImageScope, binary: DashboardImageBinary): DashboardImageReferenceDto {\n\t\tconst id = dashboardImageId(binary.mimeType, binary.bytes);\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tif (!image.original) this.putVariant(id, scope, \"original\", binary);\n\t\telse image.original.lastUsed = ++this.clock;\n\t\treturn { type: \"image_reference\", id, mimeType: binary.mimeType, size: binary.bytes.byteLength };\n\t}\n\n\tprivate cachedVariant(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tvariant: \"original\" | \"preview\",\n\t): DashboardImageBinary | undefined {\n\t\tconst image = this.images.get(id);\n\t\tif (!image || !image.scopes.has(scopeKey(scope))) return undefined;\n\t\tconst cached = image[variant];\n\t\tif (!cached) return undefined;\n\t\tcached.lastUsed = ++this.clock;\n\t\treturn { bytes: cached.bytes, mimeType: cached.mimeType };\n\t}\n\n\tprivate async recoverOriginal(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst source = await loadAuthoritative();\n\t\tlet recovered: DashboardImageBinary | undefined;\n\t\tconst visit = (value: unknown): void => {\n\t\t\tif (recovered) return;\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const item of value) visit(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!isRecord(value)) return;\n\t\t\tif (value.type === \"image\") {\n\t\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\t\tif (image && dashboardImageId(image.mimeType, image.bytes) === id) recovered = image;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const item of Object.values(value)) visit(item);\n\t\t};\n\t\tvisit(source);\n\t\tif (!recovered) throw new DashboardImageNotFoundError(\"Image is no longer available from this transcript\");\n\t\tthis.insertOriginal(scope, recovered);\n\t\treturn recovered;\n\t}\n\n\tprivate putVariant(\n\t\tid: string,\n\t\tscope: DashboardImageScope,\n\t\tvariant: \"original\" | \"preview\",\n\t\tbinary: DashboardImageBinary,\n\t): void {\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tconst previous = image[variant];\n\t\tif (previous) {\n\t\t\tthis.usedBytes -= previous.bytes.byteLength;\n\t\t} else {\n\t\t\tthis.usedRecords += 1;\n\t\t}\n\t\timage[variant] = { bytes: binary.bytes, mimeType: binary.mimeType, lastUsed: ++this.clock };\n\t\tthis.usedBytes += binary.bytes.byteLength;\n\t\tthis.evict();\n\t}\n\n\tprivate evict(): void {\n\t\twhile (this.usedBytes > this.maxBytes || this.usedRecords > this.maxRecords) {\n\t\t\tlet oldest: { image: CachedImage; variant: \"original\" | \"preview\"; lastUsed: number } | undefined;\n\t\t\tfor (const image of this.images.values()) {\n\t\t\t\tfor (const variant of [\"original\", \"preview\"] as const) {\n\t\t\t\t\tconst candidate = image[variant];\n\t\t\t\t\tif (candidate && (!oldest || candidate.lastUsed < oldest.lastUsed)) {\n\t\t\t\t\t\toldest = { image, variant, lastUsed: candidate.lastUsed };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!oldest) break;\n\t\t\tconst removed = oldest.image[oldest.variant]!;\n\t\t\tthis.usedBytes -= removed.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t\tdelete oldest.image[oldest.variant];\n\t\t\tif (!oldest.image.original && !oldest.image.preview) this.images.delete(oldest.image.id);\n\t\t}\n\t}\n\n\tprivate deleteImage(image: CachedImage): void {\n\t\tfor (const variant of [image.original, image.preview]) {\n\t\t\tif (!variant) continue;\n\t\t\tthis.usedBytes -= variant.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t}\n\t\tthis.images.delete(image.id);\n\t}\n}\n"]}
@@ -96,6 +96,7 @@ export class DashboardImagePreviewError extends Error {
96
96
  export class DashboardImageService {
97
97
  previews;
98
98
  images = new Map();
99
+ originalFlights = new Map();
99
100
  previewFlights = new Map();
100
101
  maxBytes;
101
102
  maxRecords;
@@ -126,7 +127,24 @@ export class DashboardImageService {
126
127
  const cached = this.cachedVariant(scope, id, "original");
127
128
  if (cached)
128
129
  return cached;
129
- return this.recoverOriginal(scope, id, loadAuthoritative);
130
+ // Single-flight authoritative recovery per scope+id. In originals display
131
+ // mode the browser auto-fetches every tool-result image, so N concurrent
132
+ // cache misses for distinct ids would each trigger a full authoritative
133
+ // (getMessages) re-fetch over the same RPC pipe. Coalescing the concurrent
134
+ // misses for one id collapses them into a single load. The key is
135
+ // scope-bound so requesters from another runtime/agent never piggyback.
136
+ const key = `${scopeKey(scope)}\0${id}`;
137
+ const flight = this.originalFlights.get(key);
138
+ if (flight)
139
+ return flight;
140
+ const promise = this.recoverOriginal(scope, id, loadAuthoritative);
141
+ this.originalFlights.set(key, promise);
142
+ try {
143
+ return await promise;
144
+ }
145
+ finally {
146
+ this.originalFlights.delete(key);
147
+ }
130
148
  }
131
149
  async preview(scope, id, loadAuthoritative) {
132
150
  const cached = this.cachedVariant(scope, id, "preview");
@@ -1 +1 @@
1
- {"version":3,"file":"dashboard-images.js","sourceRoot":"","sources":["../../src/server/dashboard-images.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { DashboardImageReferenceDto } from \"../shared/protocol.js\";\nimport {\n\ttype GeneratedImagePreview,\n\ttype ImagePreviewGenerator,\n\tMAX_PREVIEW_BYTES,\n\tMAX_PREVIEW_HEIGHT,\n\tMAX_PREVIEW_WIDTH,\n} from \"./image-preview.js\";\n\nexport const DASHBOARD_IMAGE_CACHE_BYTES = 64 * 1024 * 1024;\nexport const DASHBOARD_IMAGE_CACHE_RECORDS = 2000;\nexport const DASHBOARD_IMAGE_ID_PATTERN = /^[0-9a-f]{64}$/;\nexport const DASHBOARD_IMAGE_MIME_TYPES = new Set<DashboardImageReferenceDto[\"mimeType\"]>([\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n]);\n\nexport interface DashboardImageScope {\n\truntimeKey: string;\n\tagentId?: string;\n}\n\nexport interface DashboardImageBinary {\n\tbytes: Uint8Array;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n}\n\nexport interface DashboardImageRepositoryOptions {\n\tmaxBytes?: number;\n\tmaxRecords?: number;\n}\n\ninterface CachedVariant extends DashboardImageBinary {\n\tlastUsed: number;\n}\n\ninterface CachedImage {\n\tid: string;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n\tsize: number;\n\tscopes: Set<string>;\n\toriginal?: CachedVariant;\n\tpreview?: CachedVariant;\n}\n\nconst DROP = Symbol(\"drop-dashboard-image\");\nconst JPEG_EOI = Buffer.from([0xff, 0xd9]);\n\nfunction scopeKey(scope: DashboardImageScope): string {\n\treturn `${scope.runtimeKey}\\0${scope.agentId ?? \"\"}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasRasterSignature(mimeType: DashboardImageReferenceDto[\"mimeType\"], bytes: Uint8Array): boolean {\n\tconst buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\tswitch (mimeType) {\n\t\tcase \"image/png\": {\n\t\t\tconst signature =\n\t\t\t\tbytes.length >= 24 &&\n\t\t\t\t[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every((byte, i) => bytes[i] === byte);\n\t\t\treturn (\n\t\t\t\tsignature &&\n\t\t\t\tbuffer.subarray(12, 16).toString(\"ascii\") === \"IHDR\" &&\n\t\t\t\tbuffer.readUInt32BE(16) > 0 &&\n\t\t\t\tbuffer.readUInt32BE(20) > 0 &&\n\t\t\t\tbuffer.indexOf(Buffer.from(\"IEND\"), 24) >= 0\n\t\t\t);\n\t\t}\n\t\tcase \"image/jpeg\": {\n\t\t\tif (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes[2] !== 0xff) return false;\n\t\t\t// EOI does not have to be the final byte. Phone JPEGs commonly append\n\t\t\t// auxiliary gain-map, motion-photo, or vendor metadata after the primary\n\t\t\t// image. Browsers and Photon decode the JPEG through EOI and preserve the\n\t\t\t// trailing bytes when the exact original is requested.\n\t\t\treturn buffer.lastIndexOf(JPEG_EOI) >= 2;\n\t\t}\n\t\tcase \"image/gif\": {\n\t\t\tconst header = buffer.subarray(0, 6).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbytes.length >= 14 &&\n\t\t\t\t(header === \"GIF87a\" || header === \"GIF89a\") &&\n\t\t\t\tbuffer.readUInt16LE(6) > 0 &&\n\t\t\t\tbuffer.readUInt16LE(8) > 0 &&\n\t\t\t\tbytes[bytes.length - 1] === 0x3b\n\t\t\t);\n\t\t}\n\t\tcase \"image/webp\": {\n\t\t\tif (\n\t\t\t\tbytes.length < 20 ||\n\t\t\t\tbuffer.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n\t\t\t\tbuffer.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst chunk = buffer.subarray(12, 16).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbuffer.readUInt32LE(4) + 8 <= bytes.length && (chunk === \"VP8 \" || chunk === \"VP8L\" || chunk === \"VP8X\")\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** Strict standard base64 decode: whitespace, data URLs, and non-canonical padding are rejected. */\nexport function decodeDashboardImage(value: unknown, mimeType: unknown): DashboardImageBinary | undefined {\n\tif (typeof value !== \"string\" || typeof mimeType !== \"string\") return undefined;\n\tif (!DASHBOARD_IMAGE_MIME_TYPES.has(mimeType as DashboardImageReferenceDto[\"mimeType\"])) return undefined;\n\tif (value.length === 0 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(value)) return undefined;\n\tconst bytes = Buffer.from(value, \"base64\");\n\tif (bytes.toString(\"base64\") !== value) return undefined;\n\tconst exactMimeType = mimeType as DashboardImageReferenceDto[\"mimeType\"];\n\tif (!hasRasterSignature(exactMimeType, bytes)) return undefined;\n\treturn { bytes, mimeType: exactMimeType };\n}\n\nexport function dashboardImageId(mimeType: string, bytes: Uint8Array): string {\n\treturn createHash(\"sha256\").update(mimeType).update(Uint8Array.of(0)).update(bytes).digest(\"hex\");\n}\n\nexport function isDashboardImageReference(value: unknown): value is DashboardImageReferenceDto {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\tvalue.type === \"image_reference\" &&\n\t\ttypeof value.id === \"string\" &&\n\t\tDASHBOARD_IMAGE_ID_PATTERN.test(value.id) &&\n\t\ttypeof value.mimeType === \"string\" &&\n\t\tDASHBOARD_IMAGE_MIME_TYPES.has(value.mimeType as DashboardImageReferenceDto[\"mimeType\"]) &&\n\t\ttypeof value.size === \"number\" &&\n\t\tNumber.isSafeInteger(value.size) &&\n\t\tvalue.size > 0\n\t);\n}\n\nexport class DashboardImageNotFoundError extends Error {}\nexport class DashboardImagePreviewError extends Error {}\n\n/** Synchronous projection + bounded original/preview repository. */\nexport class DashboardImageService {\n\tprivate readonly images = new Map<string, CachedImage>();\n\tprivate readonly previewFlights = new Map<string, Promise<DashboardImageBinary>>();\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRecords: number;\n\tprivate usedBytes = 0;\n\tprivate usedRecords = 0;\n\tprivate clock = 0;\n\n\tconstructor(\n\t\tprivate readonly previews: ImagePreviewGenerator,\n\t\toptions: DashboardImageRepositoryOptions = {},\n\t) {\n\t\tthis.maxBytes = options.maxBytes ?? DASHBOARD_IMAGE_CACHE_BYTES;\n\t\tthis.maxRecords = options.maxRecords ?? DASHBOARD_IMAGE_CACHE_RECORDS;\n\t}\n\n\tget byteSize(): number {\n\t\treturn this.usedBytes;\n\t}\n\n\tget recordCount(): number {\n\t\treturn this.usedRecords;\n\t}\n\n\t/** Project a browser-facing event without mutating the authoritative source. */\n\tprojectEvent(event: Record<string, unknown>, scope: DashboardImageScope): Record<string, unknown> {\n\t\treturn this.projectNode(event, scope) as Record<string, unknown>;\n\t}\n\n\t/** Project messages/snapshots before JSON serialization. */\n\tproject<T>(value: T, scope: DashboardImageScope): T {\n\t\tconst projected = this.projectNode(value, scope);\n\t\treturn (projected === DROP ? undefined : projected) as T;\n\t}\n\n\tasync original(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"original\");\n\t\tif (cached) return cached;\n\t\treturn this.recoverOriginal(scope, id, loadAuthoritative);\n\t}\n\n\tasync preview(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"preview\");\n\t\tif (cached) return cached;\n\t\t// Authorize/recover this scope before joining a content-global flight. A\n\t\t// guessed ID from another runtime must not piggyback its in-flight preview.\n\t\tconst original = await this.original(scope, id, loadAuthoritative);\n\t\tconst recoveredPreview = this.cachedVariant(scope, id, \"preview\");\n\t\tif (recoveredPreview) return recoveredPreview;\n\t\tconst flight = this.previewFlights.get(id);\n\t\tif (flight) return flight;\n\t\tconst promise = (async () => {\n\t\t\tlet generated: GeneratedImagePreview;\n\t\t\ttry {\n\t\t\t\tgenerated = await this.previews.generate(original.bytes, original.mimeType);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new DashboardImagePreviewError(\n\t\t\t\t\t`Preview generation failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tgenerated.bytes.byteLength > MAX_PREVIEW_BYTES ||\n\t\t\t\tgenerated.width < 1 ||\n\t\t\t\tgenerated.height < 1 ||\n\t\t\t\tgenerated.width > MAX_PREVIEW_WIDTH ||\n\t\t\t\tgenerated.height > MAX_PREVIEW_HEIGHT ||\n\t\t\t\t(generated.mimeType !== \"image/png\" && generated.mimeType !== \"image/jpeg\")\n\t\t\t) {\n\t\t\t\tthrow new DashboardImagePreviewError(\"Preview worker returned an invalid or over-budget image\");\n\t\t\t}\n\t\t\tconst binary: DashboardImageBinary = { bytes: generated.bytes, mimeType: generated.mimeType };\n\t\t\tthis.putVariant(id, scope, \"preview\", binary);\n\t\t\treturn binary;\n\t\t})();\n\t\tthis.previewFlights.set(id, promise);\n\t\ttry {\n\t\t\treturn await promise;\n\t\t} finally {\n\t\t\tthis.previewFlights.delete(id);\n\t\t}\n\t}\n\n\tremoveRuntime(runtimeKey: string): void {\n\t\tfor (const image of [...this.images.values()]) {\n\t\t\tfor (const key of image.scopes) {\n\t\t\t\tif (key === runtimeKey || key.startsWith(`${runtimeKey}\\0`)) image.scopes.delete(key);\n\t\t\t}\n\t\t\tif (image.scopes.size === 0) this.deleteImage(image);\n\t\t}\n\t}\n\n\tclose(): Promise<void> {\n\t\treturn this.previews.close();\n\t}\n\n\tprivate projectNode(value: unknown, scope: DashboardImageScope): unknown | typeof DROP {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst projected: unknown[] = [];\n\t\t\tfor (const item of value) {\n\t\t\t\tconst next = this.projectNode(item, scope);\n\t\t\t\tif (next !== DROP) projected.push(next);\n\t\t\t}\n\t\t\treturn projected;\n\t\t}\n\t\tif (!isRecord(value)) return value;\n\t\tif (value.type === \"image\") {\n\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\tif (!image) return DROP;\n\t\t\treturn this.insertOriginal(scope, image);\n\t\t}\n\t\tif (value.type === \"image_reference\") return isDashboardImageReference(value) ? { ...value } : DROP;\n\t\tconst childScope =\n\t\t\tvalue.type === \"background_agent_event\" && typeof value.agentId === \"string\"\n\t\t\t\t? { runtimeKey: scope.runtimeKey, agentId: value.agentId }\n\t\t\t\t: scope;\n\t\tconst copy: Record<string, unknown> = {};\n\t\tfor (const [key, item] of Object.entries(value)) {\n\t\t\tconst next = this.projectNode(item, key === \"event\" ? childScope : scope);\n\t\t\tif (next !== DROP) copy[key] = next;\n\t\t}\n\t\treturn copy;\n\t}\n\n\tprivate insertOriginal(scope: DashboardImageScope, binary: DashboardImageBinary): DashboardImageReferenceDto {\n\t\tconst id = dashboardImageId(binary.mimeType, binary.bytes);\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tif (!image.original) this.putVariant(id, scope, \"original\", binary);\n\t\telse image.original.lastUsed = ++this.clock;\n\t\treturn { type: \"image_reference\", id, mimeType: binary.mimeType, size: binary.bytes.byteLength };\n\t}\n\n\tprivate cachedVariant(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tvariant: \"original\" | \"preview\",\n\t): DashboardImageBinary | undefined {\n\t\tconst image = this.images.get(id);\n\t\tif (!image || !image.scopes.has(scopeKey(scope))) return undefined;\n\t\tconst cached = image[variant];\n\t\tif (!cached) return undefined;\n\t\tcached.lastUsed = ++this.clock;\n\t\treturn { bytes: cached.bytes, mimeType: cached.mimeType };\n\t}\n\n\tprivate async recoverOriginal(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst source = await loadAuthoritative();\n\t\tlet recovered: DashboardImageBinary | undefined;\n\t\tconst visit = (value: unknown): void => {\n\t\t\tif (recovered) return;\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const item of value) visit(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!isRecord(value)) return;\n\t\t\tif (value.type === \"image\") {\n\t\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\t\tif (image && dashboardImageId(image.mimeType, image.bytes) === id) recovered = image;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const item of Object.values(value)) visit(item);\n\t\t};\n\t\tvisit(source);\n\t\tif (!recovered) throw new DashboardImageNotFoundError(\"Image is no longer available from this transcript\");\n\t\tthis.insertOriginal(scope, recovered);\n\t\treturn recovered;\n\t}\n\n\tprivate putVariant(\n\t\tid: string,\n\t\tscope: DashboardImageScope,\n\t\tvariant: \"original\" | \"preview\",\n\t\tbinary: DashboardImageBinary,\n\t): void {\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tconst previous = image[variant];\n\t\tif (previous) {\n\t\t\tthis.usedBytes -= previous.bytes.byteLength;\n\t\t} else {\n\t\t\tthis.usedRecords += 1;\n\t\t}\n\t\timage[variant] = { bytes: binary.bytes, mimeType: binary.mimeType, lastUsed: ++this.clock };\n\t\tthis.usedBytes += binary.bytes.byteLength;\n\t\tthis.evict();\n\t}\n\n\tprivate evict(): void {\n\t\twhile (this.usedBytes > this.maxBytes || this.usedRecords > this.maxRecords) {\n\t\t\tlet oldest: { image: CachedImage; variant: \"original\" | \"preview\"; lastUsed: number } | undefined;\n\t\t\tfor (const image of this.images.values()) {\n\t\t\t\tfor (const variant of [\"original\", \"preview\"] as const) {\n\t\t\t\t\tconst candidate = image[variant];\n\t\t\t\t\tif (candidate && (!oldest || candidate.lastUsed < oldest.lastUsed)) {\n\t\t\t\t\t\toldest = { image, variant, lastUsed: candidate.lastUsed };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!oldest) break;\n\t\t\tconst removed = oldest.image[oldest.variant]!;\n\t\t\tthis.usedBytes -= removed.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t\tdelete oldest.image[oldest.variant];\n\t\t\tif (!oldest.image.original && !oldest.image.preview) this.images.delete(oldest.image.id);\n\t\t}\n\t}\n\n\tprivate deleteImage(image: CachedImage): void {\n\t\tfor (const variant of [image.original, image.preview]) {\n\t\t\tif (!variant) continue;\n\t\t\tthis.usedBytes -= variant.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t}\n\t\tthis.images.delete(image.id);\n\t}\n}\n"]}
1
+ {"version":3,"file":"dashboard-images.js","sourceRoot":"","sources":["../../src/server/dashboard-images.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { DashboardImageReferenceDto } from \"../shared/protocol.js\";\nimport {\n\ttype GeneratedImagePreview,\n\ttype ImagePreviewGenerator,\n\tMAX_PREVIEW_BYTES,\n\tMAX_PREVIEW_HEIGHT,\n\tMAX_PREVIEW_WIDTH,\n} from \"./image-preview.js\";\n\nexport const DASHBOARD_IMAGE_CACHE_BYTES = 64 * 1024 * 1024;\nexport const DASHBOARD_IMAGE_CACHE_RECORDS = 2000;\nexport const DASHBOARD_IMAGE_ID_PATTERN = /^[0-9a-f]{64}$/;\nexport const DASHBOARD_IMAGE_MIME_TYPES = new Set<DashboardImageReferenceDto[\"mimeType\"]>([\n\t\"image/png\",\n\t\"image/jpeg\",\n\t\"image/gif\",\n\t\"image/webp\",\n]);\n\nexport interface DashboardImageScope {\n\truntimeKey: string;\n\tagentId?: string;\n}\n\nexport interface DashboardImageBinary {\n\tbytes: Uint8Array;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n}\n\nexport interface DashboardImageRepositoryOptions {\n\tmaxBytes?: number;\n\tmaxRecords?: number;\n}\n\ninterface CachedVariant extends DashboardImageBinary {\n\tlastUsed: number;\n}\n\ninterface CachedImage {\n\tid: string;\n\tmimeType: DashboardImageReferenceDto[\"mimeType\"];\n\tsize: number;\n\tscopes: Set<string>;\n\toriginal?: CachedVariant;\n\tpreview?: CachedVariant;\n}\n\nconst DROP = Symbol(\"drop-dashboard-image\");\nconst JPEG_EOI = Buffer.from([0xff, 0xd9]);\n\nfunction scopeKey(scope: DashboardImageScope): string {\n\treturn `${scope.runtimeKey}\\0${scope.agentId ?? \"\"}`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction hasRasterSignature(mimeType: DashboardImageReferenceDto[\"mimeType\"], bytes: Uint8Array): boolean {\n\tconst buffer = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\tswitch (mimeType) {\n\t\tcase \"image/png\": {\n\t\t\tconst signature =\n\t\t\t\tbytes.length >= 24 &&\n\t\t\t\t[0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a].every((byte, i) => bytes[i] === byte);\n\t\t\treturn (\n\t\t\t\tsignature &&\n\t\t\t\tbuffer.subarray(12, 16).toString(\"ascii\") === \"IHDR\" &&\n\t\t\t\tbuffer.readUInt32BE(16) > 0 &&\n\t\t\t\tbuffer.readUInt32BE(20) > 0 &&\n\t\t\t\tbuffer.indexOf(Buffer.from(\"IEND\"), 24) >= 0\n\t\t\t);\n\t\t}\n\t\tcase \"image/jpeg\": {\n\t\t\tif (bytes.length < 4 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes[2] !== 0xff) return false;\n\t\t\t// EOI does not have to be the final byte. Phone JPEGs commonly append\n\t\t\t// auxiliary gain-map, motion-photo, or vendor metadata after the primary\n\t\t\t// image. Browsers and Photon decode the JPEG through EOI and preserve the\n\t\t\t// trailing bytes when the exact original is requested.\n\t\t\treturn buffer.lastIndexOf(JPEG_EOI) >= 2;\n\t\t}\n\t\tcase \"image/gif\": {\n\t\t\tconst header = buffer.subarray(0, 6).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbytes.length >= 14 &&\n\t\t\t\t(header === \"GIF87a\" || header === \"GIF89a\") &&\n\t\t\t\tbuffer.readUInt16LE(6) > 0 &&\n\t\t\t\tbuffer.readUInt16LE(8) > 0 &&\n\t\t\t\tbytes[bytes.length - 1] === 0x3b\n\t\t\t);\n\t\t}\n\t\tcase \"image/webp\": {\n\t\t\tif (\n\t\t\t\tbytes.length < 20 ||\n\t\t\t\tbuffer.subarray(0, 4).toString(\"ascii\") !== \"RIFF\" ||\n\t\t\t\tbuffer.subarray(8, 12).toString(\"ascii\") !== \"WEBP\"\n\t\t\t) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tconst chunk = buffer.subarray(12, 16).toString(\"ascii\");\n\t\t\treturn (\n\t\t\t\tbuffer.readUInt32LE(4) + 8 <= bytes.length && (chunk === \"VP8 \" || chunk === \"VP8L\" || chunk === \"VP8X\")\n\t\t\t);\n\t\t}\n\t}\n}\n\n/** Strict standard base64 decode: whitespace, data URLs, and non-canonical padding are rejected. */\nexport function decodeDashboardImage(value: unknown, mimeType: unknown): DashboardImageBinary | undefined {\n\tif (typeof value !== \"string\" || typeof mimeType !== \"string\") return undefined;\n\tif (!DASHBOARD_IMAGE_MIME_TYPES.has(mimeType as DashboardImageReferenceDto[\"mimeType\"])) return undefined;\n\tif (value.length === 0 || value.length % 4 !== 0 || !/^[A-Za-z0-9+/]+={0,2}$/.test(value)) return undefined;\n\tconst bytes = Buffer.from(value, \"base64\");\n\tif (bytes.toString(\"base64\") !== value) return undefined;\n\tconst exactMimeType = mimeType as DashboardImageReferenceDto[\"mimeType\"];\n\tif (!hasRasterSignature(exactMimeType, bytes)) return undefined;\n\treturn { bytes, mimeType: exactMimeType };\n}\n\nexport function dashboardImageId(mimeType: string, bytes: Uint8Array): string {\n\treturn createHash(\"sha256\").update(mimeType).update(Uint8Array.of(0)).update(bytes).digest(\"hex\");\n}\n\nexport function isDashboardImageReference(value: unknown): value is DashboardImageReferenceDto {\n\tif (!isRecord(value)) return false;\n\treturn (\n\t\tvalue.type === \"image_reference\" &&\n\t\ttypeof value.id === \"string\" &&\n\t\tDASHBOARD_IMAGE_ID_PATTERN.test(value.id) &&\n\t\ttypeof value.mimeType === \"string\" &&\n\t\tDASHBOARD_IMAGE_MIME_TYPES.has(value.mimeType as DashboardImageReferenceDto[\"mimeType\"]) &&\n\t\ttypeof value.size === \"number\" &&\n\t\tNumber.isSafeInteger(value.size) &&\n\t\tvalue.size > 0\n\t);\n}\n\nexport class DashboardImageNotFoundError extends Error {}\nexport class DashboardImagePreviewError extends Error {}\n\n/** Synchronous projection + bounded original/preview repository. */\nexport class DashboardImageService {\n\tprivate readonly images = new Map<string, CachedImage>();\n\tprivate readonly originalFlights = new Map<string, Promise<DashboardImageBinary>>();\n\tprivate readonly previewFlights = new Map<string, Promise<DashboardImageBinary>>();\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxRecords: number;\n\tprivate usedBytes = 0;\n\tprivate usedRecords = 0;\n\tprivate clock = 0;\n\n\tconstructor(\n\t\tprivate readonly previews: ImagePreviewGenerator,\n\t\toptions: DashboardImageRepositoryOptions = {},\n\t) {\n\t\tthis.maxBytes = options.maxBytes ?? DASHBOARD_IMAGE_CACHE_BYTES;\n\t\tthis.maxRecords = options.maxRecords ?? DASHBOARD_IMAGE_CACHE_RECORDS;\n\t}\n\n\tget byteSize(): number {\n\t\treturn this.usedBytes;\n\t}\n\n\tget recordCount(): number {\n\t\treturn this.usedRecords;\n\t}\n\n\t/** Project a browser-facing event without mutating the authoritative source. */\n\tprojectEvent(event: Record<string, unknown>, scope: DashboardImageScope): Record<string, unknown> {\n\t\treturn this.projectNode(event, scope) as Record<string, unknown>;\n\t}\n\n\t/** Project messages/snapshots before JSON serialization. */\n\tproject<T>(value: T, scope: DashboardImageScope): T {\n\t\tconst projected = this.projectNode(value, scope);\n\t\treturn (projected === DROP ? undefined : projected) as T;\n\t}\n\n\tasync original(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"original\");\n\t\tif (cached) return cached;\n\t\t// Single-flight authoritative recovery per scope+id. In originals display\n\t\t// mode the browser auto-fetches every tool-result image, so N concurrent\n\t\t// cache misses for distinct ids would each trigger a full authoritative\n\t\t// (getMessages) re-fetch over the same RPC pipe. Coalescing the concurrent\n\t\t// misses for one id collapses them into a single load. The key is\n\t\t// scope-bound so requesters from another runtime/agent never piggyback.\n\t\tconst key = `${scopeKey(scope)}\\0${id}`;\n\t\tconst flight = this.originalFlights.get(key);\n\t\tif (flight) return flight;\n\t\tconst promise = this.recoverOriginal(scope, id, loadAuthoritative);\n\t\tthis.originalFlights.set(key, promise);\n\t\ttry {\n\t\t\treturn await promise;\n\t\t} finally {\n\t\t\tthis.originalFlights.delete(key);\n\t\t}\n\t}\n\n\tasync preview(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst cached = this.cachedVariant(scope, id, \"preview\");\n\t\tif (cached) return cached;\n\t\t// Authorize/recover this scope before joining a content-global flight. A\n\t\t// guessed ID from another runtime must not piggyback its in-flight preview.\n\t\tconst original = await this.original(scope, id, loadAuthoritative);\n\t\tconst recoveredPreview = this.cachedVariant(scope, id, \"preview\");\n\t\tif (recoveredPreview) return recoveredPreview;\n\t\tconst flight = this.previewFlights.get(id);\n\t\tif (flight) return flight;\n\t\tconst promise = (async () => {\n\t\t\tlet generated: GeneratedImagePreview;\n\t\t\ttry {\n\t\t\t\tgenerated = await this.previews.generate(original.bytes, original.mimeType);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new DashboardImagePreviewError(\n\t\t\t\t\t`Preview generation failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (\n\t\t\t\tgenerated.bytes.byteLength > MAX_PREVIEW_BYTES ||\n\t\t\t\tgenerated.width < 1 ||\n\t\t\t\tgenerated.height < 1 ||\n\t\t\t\tgenerated.width > MAX_PREVIEW_WIDTH ||\n\t\t\t\tgenerated.height > MAX_PREVIEW_HEIGHT ||\n\t\t\t\t(generated.mimeType !== \"image/png\" && generated.mimeType !== \"image/jpeg\")\n\t\t\t) {\n\t\t\t\tthrow new DashboardImagePreviewError(\"Preview worker returned an invalid or over-budget image\");\n\t\t\t}\n\t\t\tconst binary: DashboardImageBinary = { bytes: generated.bytes, mimeType: generated.mimeType };\n\t\t\tthis.putVariant(id, scope, \"preview\", binary);\n\t\t\treturn binary;\n\t\t})();\n\t\tthis.previewFlights.set(id, promise);\n\t\ttry {\n\t\t\treturn await promise;\n\t\t} finally {\n\t\t\tthis.previewFlights.delete(id);\n\t\t}\n\t}\n\n\tremoveRuntime(runtimeKey: string): void {\n\t\tfor (const image of [...this.images.values()]) {\n\t\t\tfor (const key of image.scopes) {\n\t\t\t\tif (key === runtimeKey || key.startsWith(`${runtimeKey}\\0`)) image.scopes.delete(key);\n\t\t\t}\n\t\t\tif (image.scopes.size === 0) this.deleteImage(image);\n\t\t}\n\t}\n\n\tclose(): Promise<void> {\n\t\treturn this.previews.close();\n\t}\n\n\tprivate projectNode(value: unknown, scope: DashboardImageScope): unknown | typeof DROP {\n\t\tif (Array.isArray(value)) {\n\t\t\tconst projected: unknown[] = [];\n\t\t\tfor (const item of value) {\n\t\t\t\tconst next = this.projectNode(item, scope);\n\t\t\t\tif (next !== DROP) projected.push(next);\n\t\t\t}\n\t\t\treturn projected;\n\t\t}\n\t\tif (!isRecord(value)) return value;\n\t\tif (value.type === \"image\") {\n\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\tif (!image) return DROP;\n\t\t\treturn this.insertOriginal(scope, image);\n\t\t}\n\t\tif (value.type === \"image_reference\") return isDashboardImageReference(value) ? { ...value } : DROP;\n\t\tconst childScope =\n\t\t\tvalue.type === \"background_agent_event\" && typeof value.agentId === \"string\"\n\t\t\t\t? { runtimeKey: scope.runtimeKey, agentId: value.agentId }\n\t\t\t\t: scope;\n\t\tconst copy: Record<string, unknown> = {};\n\t\tfor (const [key, item] of Object.entries(value)) {\n\t\t\tconst next = this.projectNode(item, key === \"event\" ? childScope : scope);\n\t\t\tif (next !== DROP) copy[key] = next;\n\t\t}\n\t\treturn copy;\n\t}\n\n\tprivate insertOriginal(scope: DashboardImageScope, binary: DashboardImageBinary): DashboardImageReferenceDto {\n\t\tconst id = dashboardImageId(binary.mimeType, binary.bytes);\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tif (!image.original) this.putVariant(id, scope, \"original\", binary);\n\t\telse image.original.lastUsed = ++this.clock;\n\t\treturn { type: \"image_reference\", id, mimeType: binary.mimeType, size: binary.bytes.byteLength };\n\t}\n\n\tprivate cachedVariant(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tvariant: \"original\" | \"preview\",\n\t): DashboardImageBinary | undefined {\n\t\tconst image = this.images.get(id);\n\t\tif (!image || !image.scopes.has(scopeKey(scope))) return undefined;\n\t\tconst cached = image[variant];\n\t\tif (!cached) return undefined;\n\t\tcached.lastUsed = ++this.clock;\n\t\treturn { bytes: cached.bytes, mimeType: cached.mimeType };\n\t}\n\n\tprivate async recoverOriginal(\n\t\tscope: DashboardImageScope,\n\t\tid: string,\n\t\tloadAuthoritative: () => Promise<unknown>,\n\t): Promise<DashboardImageBinary> {\n\t\tconst source = await loadAuthoritative();\n\t\tlet recovered: DashboardImageBinary | undefined;\n\t\tconst visit = (value: unknown): void => {\n\t\t\tif (recovered) return;\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const item of value) visit(item);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!isRecord(value)) return;\n\t\t\tif (value.type === \"image\") {\n\t\t\t\tconst image = decodeDashboardImage(value.data, value.mimeType);\n\t\t\t\tif (image && dashboardImageId(image.mimeType, image.bytes) === id) recovered = image;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const item of Object.values(value)) visit(item);\n\t\t};\n\t\tvisit(source);\n\t\tif (!recovered) throw new DashboardImageNotFoundError(\"Image is no longer available from this transcript\");\n\t\tthis.insertOriginal(scope, recovered);\n\t\treturn recovered;\n\t}\n\n\tprivate putVariant(\n\t\tid: string,\n\t\tscope: DashboardImageScope,\n\t\tvariant: \"original\" | \"preview\",\n\t\tbinary: DashboardImageBinary,\n\t): void {\n\t\tlet image = this.images.get(id);\n\t\tif (!image) {\n\t\t\timage = { id, mimeType: binary.mimeType, size: binary.bytes.byteLength, scopes: new Set() };\n\t\t\tthis.images.set(id, image);\n\t\t}\n\t\timage.scopes.add(scopeKey(scope));\n\t\tconst previous = image[variant];\n\t\tif (previous) {\n\t\t\tthis.usedBytes -= previous.bytes.byteLength;\n\t\t} else {\n\t\t\tthis.usedRecords += 1;\n\t\t}\n\t\timage[variant] = { bytes: binary.bytes, mimeType: binary.mimeType, lastUsed: ++this.clock };\n\t\tthis.usedBytes += binary.bytes.byteLength;\n\t\tthis.evict();\n\t}\n\n\tprivate evict(): void {\n\t\twhile (this.usedBytes > this.maxBytes || this.usedRecords > this.maxRecords) {\n\t\t\tlet oldest: { image: CachedImage; variant: \"original\" | \"preview\"; lastUsed: number } | undefined;\n\t\t\tfor (const image of this.images.values()) {\n\t\t\t\tfor (const variant of [\"original\", \"preview\"] as const) {\n\t\t\t\t\tconst candidate = image[variant];\n\t\t\t\t\tif (candidate && (!oldest || candidate.lastUsed < oldest.lastUsed)) {\n\t\t\t\t\t\toldest = { image, variant, lastUsed: candidate.lastUsed };\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!oldest) break;\n\t\t\tconst removed = oldest.image[oldest.variant]!;\n\t\t\tthis.usedBytes -= removed.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t\tdelete oldest.image[oldest.variant];\n\t\t\tif (!oldest.image.original && !oldest.image.preview) this.images.delete(oldest.image.id);\n\t\t}\n\t}\n\n\tprivate deleteImage(image: CachedImage): void {\n\t\tfor (const variant of [image.original, image.preview]) {\n\t\t\tif (!variant) continue;\n\t\t\tthis.usedBytes -= variant.bytes.byteLength;\n\t\t\tthis.usedRecords -= 1;\n\t\t}\n\t\tthis.images.delete(image.id);\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-pool.d.ts","sourceRoot":"","sources":["../../src/server/runtime-pool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC runtime pool — one `dreb --mode rpc` child process per live session.\n *\n * dreb's RPC mode is strictly one-session-per-process (switch_session repoints\n * the same process; it never multiplexes), so the pool spawns N children keyed\n * by an opaque runtime key. The telegram bridge is the in-repo precedent.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { RpcClient, type RpcDashboardSnapshot, type RpcExitInfo } from \"@dreb/coding-agent/rpc\";\nimport {\n\ttype BackgroundAgentDto,\n\ttype FleetRuntimeSnapshotDto,\n\ttype FleetSnapshotEventDto,\n\tMAX_COMPLETED_BACKGROUND_AGENTS,\n\ttype RuntimeInfoDto,\n\ttype RuntimeStatsSummaryDto,\n\ttype SessionStateDto,\n\ttype SubagentArbitrationDto,\n} from \"../shared/protocol.js\";\n\n/** Resolve the absolute path to the dreb CLI (RpcClient defaults to a cwd-relative path). */\nexport function resolveDrebCliPath(): string {\n\tconst resolved = import.meta.resolve(\"@dreb/coding-agent\");\n\treturn join(dirname(fileURLToPath(resolved)), \"cli.js\");\n}\n\nfunction formatRpcExit(info: RpcExitInfo): string {\n\tif (info.error) return `RPC process failed: ${info.error.message}`;\n\treturn `RPC process exited (code ${info.code}, signal ${info.signal})`;\n}\n\nexport type RuntimeEventListener = (key: string, event: Record<string, unknown>) => void;\n\n/** Listener for coalesced, synchronous fleet runtime snapshots. */\nexport type FleetSnapshotListener = (event: FleetSnapshotEventDto) => void;\n\nexport { MAX_COMPLETED_BACKGROUND_AGENTS };\n\ntype DashboardSnapshotClient = RpcClient & { getDashboardSnapshot(): Promise<RpcDashboardSnapshot> };\n\nexport interface DashboardRuntimeSnapshot {\n\tkey: string;\n\tbarrierSeq: number;\n\tsnapshot: RpcDashboardSnapshot;\n}\n\nexport interface RuntimeHandle {\n\tkey: string;\n\tcwd: string;\n\tclient: RpcClient;\n\t/** Session start time (ms epoch) — stable tiebreak for deterministic fleet ordering. */\n\tcreatedAt: number;\n\tlastActivity: number;\n\t/** Needs-attention sources, keyed so they can be cleared independently. */\n\tattention: Map<string, string>;\n\t/** Last runtime-level error, persisted server-side so fleet refreshes stay honest. */\n\terror?: string;\n\t/** Provider error currently responsible for error/attention; retry may clear only this source. */\n\tproviderError?: string;\n\t/** Last authoritative state, patched only with event-derivable fields between RPC reads. */\n\tlastState?: SessionStateDto;\n\t/** Monotonic revision for confirmed model/thinking mutations. */\n\tsettingsRevision: number;\n\t/** Resume-path fallback; events must never invent or overwrite session identity. */\n\tsessionFileFallback?: string;\n\t/** Background agents seen via events (agentId → latest info). */\n\tbackgroundAgents: Map<string, BackgroundAgentDto>;\n}\n\nexport const DEFAULT_DASHBOARD_BARRIER_TTL_MS = 5 * 60_000;\nexport const DEFAULT_DASHBOARD_BARRIER_LIMIT = 1000;\nexport const DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS = 200;\n\n/** Events that mutate a field carried by the lightweight fleet snapshot. */\nconst FLEET_SNAPSHOT_EVENT_TYPES = new Set([\n\t\"agent_start\",\n\t\"agent_end\",\n\t\"auto_compaction_start\",\n\t\"auto_compaction_end\",\n\t\"auto_retry_start\",\n\t\"auto_retry_end\",\n\t\"background_agent_start\",\n\t\"background_agent_end\",\n\t\"subagent_arbitration\",\n\t\"extension_ui_request\",\n\t\"extension_ui_response_handled\",\n\t\"message_end\",\n\t\"message_start\",\n\t\"parent_paused_for_background_agents\",\n\t\"runtime_removed\",\n\t\"session_name_changed\",\n\t\"suggest_next\",\n\t\"tasks_update\",\n]);\n\nexport interface RuntimePoolOptions {\n\tcliPath?: string;\n\t/** Extra args for every runtime (e.g. --provider). */\n\tbaseArgs?: string[];\n\t/** RpcClient factory override for tests. */\n\tclientFactory?: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tlogger?: (line: string) => void;\n\t/** Bounds unclaimed RPC snapshot ordering records. */\n\tdashboardBarrierTtlMs?: number;\n\tdashboardBarrierLimit?: number;\n\t/** Injectable clock for deterministic barrier-expiry tests. */\n\tnow?: () => number;\n\t/** Coalescing delay for event-derived fleet snapshot emissions. */\n\tfleetSnapshotDebounceMs?: number;\n}\n\ninterface DashboardBarrier {\n\tseq: number;\n\trecordedAt: number;\n}\n\nexport class RuntimePool {\n\tprivate readonly runtimes = new Map<string, RuntimeHandle>();\n\tprivate readonly listeners: RuntimeEventListener[] = [];\n\tprivate readonly fleetSnapshotListeners: FleetSnapshotListener[] = [];\n\tprivate readonly cliPath: string;\n\tprivate readonly baseArgs: string[];\n\tprivate readonly clientFactory: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tprivate readonly logger: (line: string) => void;\n\t/**\n\t * A single lazily-spawned utility runtime used to service settings/model/\n\t * agent-type endpoints when no user session is live. Kept out of `runtimes`\n\t * (and therefore out of the fleet) so it never shows as a session card.\n\t */\n\tprivate readonly utilities = new Map<string, RuntimeHandle>();\n\tprivate readonly utilityPromises = new Map<string, Promise<RuntimeHandle>>();\n\tprivate readonly starting = new Set<RuntimeHandle>();\n\tprivate readonly startupPromises = new Set<Promise<unknown>>();\n\tprivate readonly exitedHandles = new WeakSet<RuntimeHandle>();\n\t/** Snapshot ordering records observed synchronously from RpcClient stdout. */\n\tprivate readonly dashboardBarriers = new Map<string, DashboardBarrier>();\n\tprivate readonly dashboardBarrierTtlMs: number;\n\tprivate readonly dashboardBarrierLimit: number;\n\tprivate readonly now: () => number;\n\tprivate readonly fleetSnapshotDebounceMs: number;\n\tprivate dashboardBarrierPruneTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate fleetSnapshotTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate closing = false;\n\n\tconstructor(options: RuntimePoolOptions = {}) {\n\t\tthis.cliPath = options.cliPath ?? resolveDrebCliPath();\n\t\tthis.baseArgs = options.baseArgs ?? [];\n\t\tthis.clientFactory =\n\t\t\toptions.clientFactory ?? ((o) => new RpcClient({ cliPath: o.cliPath, cwd: o.cwd, args: o.args }));\n\t\tthis.logger = options.logger ?? ((line) => console.warn(`[dashboard] ${line}`));\n\t\tthis.dashboardBarrierTtlMs = options.dashboardBarrierTtlMs ?? DEFAULT_DASHBOARD_BARRIER_TTL_MS;\n\t\tthis.dashboardBarrierLimit = options.dashboardBarrierLimit ?? DEFAULT_DASHBOARD_BARRIER_LIMIT;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.fleetSnapshotDebounceMs = options.fleetSnapshotDebounceMs ?? DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS;\n\t}\n\n\t/** Subscribe to events from every runtime, tagged with the runtime key. */\n\tonEvent(listener: RuntimeEventListener): () => void {\n\t\tthis.listeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.listeners.indexOf(listener);\n\t\t\tif (i !== -1) this.listeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/** Subscribe to debounced, in-memory fleet snapshots. */\n\tonFleetSnapshot(listener: FleetSnapshotListener): () => void {\n\t\tthis.fleetSnapshotListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.fleetSnapshotListeners.indexOf(listener);\n\t\t\tif (i !== -1) this.fleetSnapshotListeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/**\n\t * Build the fleet's live-runtime view without RPC or disk access. Map\n\t * insertion order is retained intentionally; the UI owns presentation order.\n\t */\n\tfleetSnapshot(): FleetRuntimeSnapshotDto[] {\n\t\treturn [...this.runtimes.values()].map((handle) => this.describeFleetRuntime(handle));\n\t}\n\n\tlist(): RuntimeHandle[] {\n\t\treturn [...this.runtimes.values()];\n\t}\n\n\tget(key: string): RuntimeHandle | undefined {\n\t\treturn this.runtimes.get(key);\n\t}\n\n\t/** Apply a confirmed model mutation to both the child and the pool snapshot. */\n\tasync setModel(\n\t\thandle: RuntimeHandle,\n\t\tprovider: string,\n\t\tmodelId: string,\n\t): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: string;\n\t\tavailableThinkingLevels: string[];\n\t\tsettingsRevision: number;\n\t}> {\n\t\tconst model = await handle.client.setModel(provider, modelId);\n\t\tconst state = await handle.client.getState();\n\t\thandle.lastState = {\n\t\t\t...this.fallbackState(handle),\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t};\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn {\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t};\n\t}\n\n\t/** Apply a confirmed thinking mutation to both the child and the pool snapshot. */\n\tasync setThinkingLevel(\n\t\thandle: RuntimeHandle,\n\t\tlevel: Parameters<RpcClient[\"setThinkingLevel\"]>[0],\n\t): Promise<{ ok: true; settingsRevision: number }> {\n\t\tawait handle.client.setThinkingLevel(level);\n\t\thandle.lastState = { ...this.fallbackState(handle), thinkingLevel: level };\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn { ok: true, settingsRevision: handle.settingsRevision };\n\t}\n\n\t/**\n\t * Record the EventHub sequence synchronously when the RPC snapshot marker\n\t * arrives. The marker line precedes its response on stdout, so this runs\n\t * before the RpcClient response continuation even across separate chunks.\n\t */\n\trecordDashboardBarrier(runtimeKey: string, snapshotId: string, seq: number): void {\n\t\tthis.pruneDashboardBarriers();\n\t\tthis.dashboardBarriers.set(this.dashboardBarrierKey(runtimeKey, snapshotId), { seq, recordedAt: this.now() });\n\t\tthis.pruneDashboardBarriers();\n\t}\n\n\t/**\n\t * Capture a parent-session recovery snapshot and pair it with the sequence\n\t * captured at its RPC marker. This deliberately does not infer ordering from\n\t * await: later EventHub publications naturally have higher sequence numbers.\n\t */\n\tasync snapshotDashboard(handle: RuntimeHandle): Promise<DashboardRuntimeSnapshot> {\n\t\tconst snapshot = await (handle.client as DashboardSnapshotClient).getDashboardSnapshot();\n\t\tthis.pruneDashboardBarriers();\n\t\tconst barrierKey = this.dashboardBarrierKey(handle.key, snapshot.snapshotId);\n\t\tconst barrier = this.dashboardBarriers.get(barrierKey);\n\t\tthis.dashboardBarriers.delete(barrierKey);\n\t\tthis.scheduleDashboardBarrierPrune();\n\t\tif (!barrier) {\n\t\t\tthrow new Error(`Dashboard snapshot ${snapshot.snapshotId} arrived without its ordering barrier`);\n\t\t}\n\t\t// This is an authoritative RPC baseline, so it may legitimately lower the\n\t\t// count after a fork/rewind instead of retaining an event-derived maximum.\n\t\thandle.lastState = snapshot.state;\n\t\tthis.scheduleFleetSnapshot();\n\t\treturn { key: handle.key, barrierSeq: barrier.seq, snapshot };\n\t}\n\n\tprivate dashboardBarrierKey(runtimeKey: string, snapshotId: string): string {\n\t\treturn `${runtimeKey}\\0${snapshotId}`;\n\t}\n\n\tprivate pruneDashboardBarriers(): void {\n\t\tconst oldestAllowed = this.now() - this.dashboardBarrierTtlMs;\n\t\tfor (const [snapshotId, barrier] of this.dashboardBarriers) {\n\t\t\tif (barrier.recordedAt < oldestAllowed) this.dashboardBarriers.delete(snapshotId);\n\t\t}\n\t\twhile (this.dashboardBarriers.size > this.dashboardBarrierLimit) {\n\t\t\tconst oldest = this.dashboardBarriers.keys().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis.dashboardBarriers.delete(oldest);\n\t\t}\n\t\tthis.scheduleDashboardBarrierPrune();\n\t}\n\n\tprivate scheduleDashboardBarrierPrune(): void {\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tlet oldest: DashboardBarrier | undefined;\n\t\tfor (const barrier of this.dashboardBarriers.values()) {\n\t\t\tif (!oldest || barrier.recordedAt < oldest.recordedAt) oldest = barrier;\n\t\t}\n\t\tif (!oldest) return;\n\t\tconst delay = Math.max(1, oldest.recordedAt + this.dashboardBarrierTtlMs - this.now() + 1);\n\t\tthis.dashboardBarrierPruneTimer = setTimeout(() => {\n\t\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\t\tthis.pruneDashboardBarriers();\n\t\t}, delay);\n\t\tthis.dashboardBarrierPruneTimer.unref?.();\n\t}\n\n\tprivate scheduleFleetSnapshot(): void {\n\t\tif (this.closing) return;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = setTimeout(() => {\n\t\t\tthis.fleetSnapshotTimer = undefined;\n\t\t\tif (this.closing) return;\n\t\t\tconst event: FleetSnapshotEventDto = { type: \"fleet_snapshot\", runtimes: this.fleetSnapshot() };\n\t\t\tfor (const listener of this.fleetSnapshotListeners) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(event);\n\t\t\t\t} catch {\n\t\t\t\t\t// An SSE bridge subscriber must not break the pool's event loop.\n\t\t\t\t}\n\t\t\t}\n\t\t}, this.fleetSnapshotDebounceMs);\n\t\tthis.fleetSnapshotTimer.unref?.();\n\t}\n\n\t/** Spawn a new runtime in `cwd`, optionally opening an existing session file. */\n\tasync create(cwd: string, sessionPath?: string): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst key = randomBytes(6).toString(\"hex\");\n\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\tif (sessionPath) args.push(\"--session\", sessionPath);\n\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\tconst handle: RuntimeHandle = {\n\t\t\tkey,\n\t\t\tcwd,\n\t\t\tclient,\n\t\t\tcreatedAt: this.now(),\n\t\t\tlastActivity: this.now(),\n\t\t\tattention: new Map(),\n\t\t\tsettingsRevision: 0,\n\t\t\tsessionFileFallback: sessionPath,\n\t\t\tbackgroundAgents: new Map(),\n\t\t};\n\t\tclient.onEvent((event) => this.handleEvent(handle, event as unknown as Record<string, unknown>));\n\t\tclient.onExit((info) => this.handleRuntimeExit(handle, info));\n\n\t\tconst startup = this.startSessionRuntime(handle);\n\t\tthis.startupPromises.add(startup);\n\t\ttry {\n\t\t\treturn await startup;\n\t\t} finally {\n\t\t\tthis.startupPromises.delete(startup);\n\t\t}\n\t}\n\n\tprivate async startSessionRuntime(handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tawait this.seedBackgroundAgents(handle);\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.runtimes.set(handle.key, handle);\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\t/** Stop a runtime and remove it from the pool. */\n\tasync stop(key: string): Promise<boolean> {\n\t\tconst handle = this.runtimes.get(key);\n\t\tif (!handle) return false;\n\t\tthis.handleEvent(handle, { type: \"runtime_removed\" });\n\t\tthis.runtimes.delete(key);\n\t\tthis.scheduleFleetSnapshot();\n\t\tawait handle.client.stop();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return any live runtime suitable for process-global settings work, spawning\n\t * a hidden utility runtime (in the home directory) if no user session exists.\n\t * This is what lets the settings page — models, agent types, defaults — work\n\t * with zero sessions open, instead of 503-ing.\n\t */\n\tasync ensureUtilityRuntime(cwd = homedir()): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst existing = this.utilities.get(cwd);\n\t\tif (existing) return existing;\n\t\tlet promise = this.utilityPromises.get(cwd);\n\t\tif (!promise) {\n\t\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\t\tconst handle: RuntimeHandle = {\n\t\t\t\tkey: `utility:${cwd}`,\n\t\t\t\tcwd,\n\t\t\t\tclient,\n\t\t\t\tcreatedAt: this.now(),\n\t\t\t\tlastActivity: this.now(),\n\t\t\t\tattention: new Map(),\n\t\t\t\tsettingsRevision: 0,\n\t\t\t\tbackgroundAgents: new Map(),\n\t\t\t};\n\t\t\tconst startup = this.startUtilityRuntime(cwd, handle);\n\t\t\tthis.startupPromises.add(startup);\n\t\t\tpromise = startup\n\t\t\t\t.catch((err) => {\n\t\t\t\t\t// Allow a retry on the next request instead of caching the failure.\n\t\t\t\t\tthis.utilityPromises.delete(cwd);\n\t\t\t\t\tthrow err;\n\t\t\t\t})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis.startupPromises.delete(startup);\n\t\t\t\t});\n\t\t\tthis.utilityPromises.set(cwd, promise);\n\t\t}\n\t\treturn promise;\n\t}\n\n\tprivate async startUtilityRuntime(cwd: string, handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.utilities.set(cwd, handle);\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\tasync stopAll(): Promise<void> {\n\t\tthis.closing = true;\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = undefined;\n\t\tthis.fleetSnapshotListeners.length = 0;\n\t\tthis.dashboardBarriers.clear();\n\t\tconst handles = new Set<RuntimeHandle>([\n\t\t\t...this.runtimes.values(),\n\t\t\t...this.utilities.values(),\n\t\t\t...this.starting.values(),\n\t\t]);\n\t\tconst startupPromises = new Set<Promise<unknown>>([...this.startupPromises, ...this.utilityPromises.values()]);\n\t\tthis.runtimes.clear();\n\t\tthis.utilities.clear();\n\t\tthis.utilityPromises.clear();\n\t\tawait Promise.allSettled([...handles].map((handle) => handle.client.stop()));\n\t\tawait Promise.allSettled([...startupPromises]);\n\t}\n\n\tprivate handleRuntimeExit(handle: RuntimeHandle, info: RpcExitInfo): void {\n\t\tif (this.closing || this.exitedHandles.has(handle) || !this.isLiveHandle(handle)) return;\n\t\tthis.exitedHandles.add(handle);\n\t\tconst message = formatRpcExit(info);\n\t\tthis.recordRuntimeError(handle, message);\n\t\tthis.logger(`runtime ${handle.key} ${message}`);\n\t\tthis.handleEvent(handle, { type: \"agent_end\", messages: [], aborted: true, errorMessage: message });\n\t}\n\n\tprivate isLiveHandle(handle: RuntimeHandle): boolean {\n\t\treturn (\n\t\t\tthis.runtimes.get(handle.key) === handle ||\n\t\t\tthis.utilities.get(handle.cwd) === handle ||\n\t\t\tthis.starting.has(handle)\n\t\t);\n\t}\n\n\tprivate handleEvent(handle: RuntimeHandle, event: Record<string, unknown>): void {\n\t\tconst type = event.type as string;\n\t\tif (type !== \"dashboard_snapshot_barrier\") {\n\t\t\thandle.lastActivity = this.now();\n\t\t\tthis.updateStateFromEvent(handle, event, type);\n\t\t}\n\n\t\t// Track needs-attention sources: extension UI requests, parent\n\t\t// paused, error states.\n\t\tif (type === \"extension_ui_request\") {\n\t\t\tconst method = event.method as string;\n\t\t\tif (\n\t\t\t\tmethod === \"select\" ||\n\t\t\t\tmethod === \"confirm\" ||\n\t\t\t\tmethod === \"input\" ||\n\t\t\t\tmethod === \"editor\" ||\n\t\t\t\tmethod === \"ask\"\n\t\t\t) {\n\t\t\t\thandle.attention.set(`ui:${event.id}`, `extension ${method} awaiting response`);\n\t\t\t}\n\t\t}\n\t\tif (type === \"extension_ui_response_handled\") {\n\t\t\thandle.attention.delete(`ui:${event.id}`);\n\t\t}\n\t\tif (type === \"agent_start\") {\n\t\t\t// A new turn clears prior UI-request attention (requests were resolved or timed out).\n\t\t\tfor (const k of [...handle.attention.keys()]) {\n\t\t\t\tif (k.startsWith(\"ui:\")) handle.attention.delete(k);\n\t\t\t}\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\thandle.attention.delete(\"suggest\");\n\t\t\thandle.attention.delete(\"error\");\n\t\t\thandle.error = undefined;\n\t\t\thandle.providerError = undefined;\n\t\t}\n\t\tif (type === \"suggest_next\") {\n\t\t\t// suggest_next as the ending action = \"your move\": mark needs-attention\n\t\t\t// so the fleet card doesn't read idle. Cleared on the next agent_start.\n\t\t\thandle.attention.set(\"suggest\", \"suggested command awaiting\");\n\t\t}\n\t\tif (type === \"parent_paused_for_background_agents\") {\n\t\t\thandle.attention.set(\"paused\", `paused — ${event.runningAgentCount} background agents running`);\n\t\t}\n\t\tif (type === \"agent_end\") {\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\tif (event.errorMessage) this.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\t\tif (type === \"message_end\") {\n\t\t\tconst message = event.message;\n\t\t\tif (message && typeof message === \"object\" && !Array.isArray(message)) {\n\t\t\t\tconst assistant = message as Record<string, unknown>;\n\t\t\t\tif (assistant.role === \"assistant\" && assistant.stopReason === \"error\") {\n\t\t\t\t\tconst rawError = assistant.errorMessage;\n\t\t\t\t\tconst error = typeof rawError === \"string\" && rawError.trim().length > 0 ? rawError : \"Unknown error\";\n\t\t\t\t\tthis.recordProviderError(handle, error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (type === \"auto_retry_start\") this.clearProviderError(handle);\n\t\tif (type === \"auto_compaction_start\" && event.reason === \"overflow\") this.clearProviderError(handle);\n\t\tif (type === \"auto_retry_end\" && event.success === false && event.finalError) {\n\t\t\tthis.recordProviderError(handle, String(event.finalError));\n\t\t} else if (type === \"auto_retry_end\" && event.success === true) {\n\t\t\tthis.clearProviderError(handle);\n\t\t}\n\t\tif (type === \"auto_compaction_end\" && event.errorMessage) {\n\t\t\tthis.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\n\t\t// Track background agents from lifecycle events.\n\t\tif (type === \"background_agent_start\") {\n\t\t\thandle.backgroundAgents.set(event.agentId as string, {\n\t\t\t\tagentId: event.agentId as string,\n\t\t\t\tagentType: event.agentType as string,\n\t\t\t\ttaskSummary: event.taskSummary as string,\n\t\t\t\tstartedAt: new Date().toISOString(),\n\t\t\t\tstatus: \"running\",\n\t\t\t\tsessionDir: event.sessionDir as string | undefined,\n\t\t\t});\n\t\t}\n\t\tif (type === \"subagent_arbitration\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\tconst record: SubagentArbitrationDto = {\n\t\t\t\t\tstatus: event.status as SubagentArbitrationDto[\"status\"],\n\t\t\t\t\tproposed: event.proposed as SubagentArbitrationDto[\"proposed\"],\n\t\t\t\t\tfinal: (event.final as SubagentArbitrationDto[\"final\"]) ?? null,\n\t\t\t\t\tchanged: (event.changed as SubagentArbitrationDto[\"changed\"]) ?? [],\n\t\t\t\t\tstep: event.step as number | undefined,\n\t\t\t\t\terrorCode: event.errorCode as string | undefined,\n\t\t\t\t\terrorMessage: event.errorMessage as string | undefined,\n\t\t\t\t};\n\t\t\t\texisting.arbitrations = [...(existing.arbitrations ?? []), record];\n\t\t\t\tif (record.status === \"success\" && record.final) existing.agentType = record.final.agent;\n\t\t\t}\n\t\t}\n\t\tif (type === \"background_agent_end\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\texisting.status = event.success ? \"completed\" : \"failed\";\n\t\t\t\texisting.sessionFile = (event.sessionFile as string | undefined) ?? existing.sessionFile;\n\t\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t\t}\n\t\t}\n\n\t\tfor (const listener of this.listeners) {\n\t\t\ttry {\n\t\t\t\tlistener(handle.key, event);\n\t\t\t} catch {\n\t\t\t\t// A broken SSE subscriber must not break event distribution.\n\t\t\t}\n\t\t}\n\t\tif (this.runtimes.get(handle.key) === handle && FLEET_SNAPSHOT_EVENT_TYPES.has(type)) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t}\n\n\t/**\n\t * Events intentionally patch only fields they can prove. Session identity,\n\t * session file, configuration, and context usage remain from the last RPC\n\t * baseline (or the stable creation fallback) until a later reconciliation.\n\t */\n\tprivate updateStateFromEvent(handle: RuntimeHandle, event: Record<string, unknown>, type: string): void {\n\t\tconst state = this.fallbackState(handle);\n\t\tswitch (type) {\n\t\t\tcase \"agent_start\": {\n\t\t\t\tconst model = event.model;\n\t\t\t\tif (\n\t\t\t\t\tmodel &&\n\t\t\t\t\ttypeof model === \"object\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).provider === \"string\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).id === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tconst nextModel = model as { provider: string; id: string };\n\t\t\t\t\tstate.model =\n\t\t\t\t\t\tstate.model?.provider === nextModel.provider && state.model.id === nextModel.id\n\t\t\t\t\t\t\t? { ...state.model, ...nextModel }\n\t\t\t\t\t\t\t: nextModel;\n\t\t\t\t}\n\t\t\t\tstate.isStreaming = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"agent_end\":\n\t\t\t\tstate.isStreaming = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_start\":\n\t\t\t\tstate.isCompacting = true;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_end\":\n\t\t\t\tstate.isCompacting = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_start\":\n\t\t\t\tstate.isRetrying = true;\n\t\t\t\tstate.retryAttempt = typeof event.attempt === \"number\" ? event.attempt : state.retryAttempt;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_end\":\n\t\t\t\tstate.isRetrying = false;\n\t\t\t\tstate.retryAttempt = 0;\n\t\t\t\tbreak;\n\t\t\tcase \"tasks_update\":\n\t\t\t\tif (Array.isArray(event.tasks)) state.tasks = [...event.tasks] as SessionStateDto[\"tasks\"];\n\t\t\t\tbreak;\n\t\t\tcase \"session_name_changed\":\n\t\t\t\tif (typeof event.name === \"string\") state.sessionName = event.name;\n\t\t\t\tbreak;\n\t\t\tcase \"message_start\":\n\t\t\t\tstate.messageCount += 1;\n\t\t\t\tbreak;\n\t\t}\n\t\thandle.lastState = state;\n\t}\n\n\tprivate recordRuntimeError(handle: RuntimeHandle, message: string): void {\n\t\thandle.error = message;\n\t\thandle.attention.set(\"error\", message);\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate recordProviderError(handle: RuntimeHandle, message: string): void {\n\t\thandle.providerError = message;\n\t\tthis.recordRuntimeError(handle, message);\n\t}\n\n\tprivate clearProviderError(handle: RuntimeHandle): void {\n\t\tconst providerError = handle.providerError;\n\t\tif (providerError === undefined) return;\n\t\thandle.providerError = undefined;\n\t\tif (handle.error === providerError) handle.error = undefined;\n\t\tif (handle.attention.get(\"error\") === providerError) handle.attention.delete(\"error\");\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate pruneCompletedBackgroundAgents(handle: RuntimeHandle): void {\n\t\tconst evictable = [...handle.backgroundAgents.values()]\n\t\t\t.map((agent, index) => {\n\t\t\t\tconst startedAtMs = Date.parse(agent.startedAt);\n\t\t\t\treturn { agent, index, startedAtMs: Number.isFinite(startedAtMs) ? startedAtMs : 0 };\n\t\t\t})\n\t\t\t.filter(({ agent }) => agent.status !== \"running\")\n\t\t\t.sort((a, b) => a.startedAtMs - b.startedAtMs || a.index - b.index);\n\t\tconst excess = evictable.length - MAX_COMPLETED_BACKGROUND_AGENTS;\n\t\tif (excess <= 0) return;\n\t\tfor (const { agent } of evictable.slice(0, excess)) {\n\t\t\thandle.backgroundAgents.delete(agent.agentId);\n\t\t}\n\t}\n\n\tprivate fallbackState(handle: RuntimeHandle): SessionStateDto {\n\t\tconst previous = handle.lastState;\n\t\treturn {\n\t\t\t...previous,\n\t\t\tsessionId: previous?.sessionId ?? handle.key,\n\t\t\ttasks: previous?.tasks ? [...previous.tasks] : [],\n\t\t\tthinkingLevel: previous?.thinkingLevel ?? \"off\",\n\t\t\tavailableThinkingLevels: previous?.availableThinkingLevels ? [...previous.availableThinkingLevels] : [\"off\"],\n\t\t\tisStreaming: previous?.isStreaming ?? false,\n\t\t\tisRetrying: previous?.isRetrying ?? false,\n\t\t\tretryAttempt: previous?.retryAttempt ?? 0,\n\t\t\tisCompacting: previous?.isCompacting ?? false,\n\t\t\tsteeringMode: previous?.steeringMode ?? \"all\",\n\t\t\tfollowUpMode: previous?.followUpMode ?? \"all\",\n\t\t\tsessionFile: previous?.sessionFile ?? handle.sessionFileFallback,\n\t\t\tautoCompactionEnabled: previous?.autoCompactionEnabled ?? false,\n\t\t\tmessageCount: previous?.messageCount ?? 0,\n\t\t\tpendingMessageCount: previous?.pendingMessageCount ?? 0,\n\t\t};\n\t}\n\n\tprivate describeFleetRuntime(handle: RuntimeHandle): FleetRuntimeSnapshotDto {\n\t\tconst state = this.fallbackState(handle);\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()].map((agent) => ({ ...agent })),\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n\n\tprivate async seedBackgroundAgents(handle: RuntimeHandle): Promise<void> {\n\t\ttry {\n\t\t\tconst agents = (await handle.client.listBackgroundAgents()) as unknown as BackgroundAgentDto[];\n\t\t\tfor (const agent of agents) {\n\t\t\t\thandle.backgroundAgents.set(agent.agentId, agent);\n\t\t\t}\n\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} background-agent registry unavailable: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Snapshot a runtime for the fleet endpoint. */\n\tasync describe(handle: RuntimeHandle): Promise<RuntimeInfoDto> {\n\t\tconst previousFleetRuntime =\n\t\t\tthis.runtimes.get(handle.key) === handle ? this.describeFleetRuntime(handle) : undefined;\n\t\tlet fleetRuntimeEnriched = false;\n\t\tlet state: SessionStateDto;\n\t\ttry {\n\t\t\tconst authoritative = (await handle.client.getState()) as unknown as SessionStateDto;\n\t\t\tconst fallback = this.fallbackState(handle);\n\t\t\tstate = {\n\t\t\t\t...fallback,\n\t\t\t\t...authoritative,\n\t\t\t\tsessionId: authoritative.sessionId ?? fallback.sessionId,\n\t\t\t\tsessionFile: authoritative.sessionFile ?? fallback.sessionFile,\n\t\t\t\ttasks: authoritative.tasks ?? fallback.tasks,\n\t\t\t};\n\t\t\thandle.lastState = state;\n\t\t\tfleetRuntimeEnriched = true;\n\t\t\tif (handle.error?.startsWith(\"RPC process\")) {\n\t\t\t\thandle.error = undefined;\n\t\t\t\thandle.attention.delete(\"error\");\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.recordRuntimeError(handle, message);\n\t\t\tthis.logger(`runtime ${handle.key} state unavailable for fleet card: ${message}`);\n\t\t\tstate = this.fallbackState(handle);\n\t\t}\n\t\tlet stats: RuntimeStatsSummaryDto | undefined;\n\t\ttry {\n\t\t\tconst sessionStats = await handle.client.getSessionStats();\n\t\t\tstats = { tokensTotal: sessionStats.tokens.total, cost: sessionStats.cost };\n\t\t\tif (sessionStats.contextUsage) {\n\t\t\t\thandle.lastState = { ...this.fallbackState(handle), contextUsage: sessionStats.contextUsage };\n\t\t\t\tfleetRuntimeEnriched = true;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} stats unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tlet lastAssistantText: string | undefined;\n\t\ttry {\n\t\t\tconst text = await handle.client.getLastAssistantText();\n\t\t\tlastAssistantText = text ? text.slice(0, 200) : undefined;\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} last assistant text unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tfleetRuntimeEnriched &&\n\t\t\tpreviousFleetRuntime &&\n\t\t\tthis.runtimes.get(handle.key) === handle &&\n\t\t\t!isDeepStrictEqual(previousFleetRuntime, this.describeFleetRuntime(handle))\n\t\t) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tstats,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()],\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tlastAssistantText,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"runtime-pool.d.ts","sourceRoot":"","sources":["../../src/server/runtime-pool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC runtime pool — one `dreb --mode rpc` child process per live session.\n *\n * dreb's RPC mode is strictly one-session-per-process (switch_session repoints\n * the same process; it never multiplexes), so the pool spawns N children keyed\n * by an opaque runtime key. The telegram bridge is the in-repo precedent.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { RpcClient, type RpcDashboardSnapshot, type RpcExitInfo } from \"@dreb/coding-agent/rpc\";\nimport {\n\ttype BackgroundAgentDto,\n\ttype FleetRuntimeSnapshotDto,\n\ttype FleetSnapshotEventDto,\n\tMAX_COMPLETED_BACKGROUND_AGENTS,\n\ttype RuntimeInfoDto,\n\ttype RuntimeStatsSummaryDto,\n\ttype SessionStateDto,\n\ttype SubagentArbitrationDto,\n} from \"../shared/protocol.js\";\n\n/** Resolve the absolute path to the dreb CLI (RpcClient defaults to a cwd-relative path). */\nexport function resolveDrebCliPath(): string {\n\tconst resolved = import.meta.resolve(\"@dreb/coding-agent\");\n\treturn join(dirname(fileURLToPath(resolved)), \"cli.js\");\n}\n\nfunction formatRpcExit(info: RpcExitInfo): string {\n\tif (info.error) return `RPC process failed: ${info.error.message}`;\n\tconst tail = info.stderrTail?.trim();\n\t// When the child aborted on its own (e.g. the stdout backpressure guard),\n\t// its stderr tail carries the actual reason — surface it instead of a bare\n\t// exit code. The tail may be multi-line; the existing UI already renders\n\t// multi-line error messages (e.g. timeouts embed full stderr).\n\treturn tail\n\t\t? `RPC process exited (code ${info.code}, signal ${info.signal}). Stderr tail: ${tail}`\n\t\t: `RPC process exited (code ${info.code}, signal ${info.signal})`;\n}\n\nexport type RuntimeEventListener = (key: string, event: Record<string, unknown>) => void;\n\n/** Listener for coalesced, synchronous fleet runtime snapshots. */\nexport type FleetSnapshotListener = (event: FleetSnapshotEventDto) => void;\n\nexport { MAX_COMPLETED_BACKGROUND_AGENTS };\n\ntype DashboardSnapshotClient = RpcClient & { getDashboardSnapshot(): Promise<RpcDashboardSnapshot> };\n\nexport interface DashboardRuntimeSnapshot {\n\tkey: string;\n\tbarrierSeq: number;\n\tsnapshot: RpcDashboardSnapshot;\n}\n\nexport interface RuntimeHandle {\n\tkey: string;\n\tcwd: string;\n\tclient: RpcClient;\n\t/** Session start time (ms epoch) — stable tiebreak for deterministic fleet ordering. */\n\tcreatedAt: number;\n\tlastActivity: number;\n\t/** Needs-attention sources, keyed so they can be cleared independently. */\n\tattention: Map<string, string>;\n\t/** Last runtime-level error, persisted server-side so fleet refreshes stay honest. */\n\terror?: string;\n\t/** Provider error currently responsible for error/attention; retry may clear only this source. */\n\tproviderError?: string;\n\t/** Last authoritative state, patched only with event-derivable fields between RPC reads. */\n\tlastState?: SessionStateDto;\n\t/** Monotonic revision for confirmed model/thinking mutations. */\n\tsettingsRevision: number;\n\t/** Resume-path fallback; events must never invent or overwrite session identity. */\n\tsessionFileFallback?: string;\n\t/** Background agents seen via events (agentId → latest info). */\n\tbackgroundAgents: Map<string, BackgroundAgentDto>;\n}\n\nexport const DEFAULT_DASHBOARD_BARRIER_TTL_MS = 5 * 60_000;\nexport const DEFAULT_DASHBOARD_BARRIER_LIMIT = 1000;\nexport const DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS = 200;\n\n/** Events that mutate a field carried by the lightweight fleet snapshot. */\nconst FLEET_SNAPSHOT_EVENT_TYPES = new Set([\n\t\"agent_start\",\n\t\"agent_end\",\n\t\"auto_compaction_start\",\n\t\"auto_compaction_end\",\n\t\"auto_retry_start\",\n\t\"auto_retry_end\",\n\t\"background_agent_start\",\n\t\"background_agent_end\",\n\t\"subagent_arbitration\",\n\t\"extension_ui_request\",\n\t\"extension_ui_response_handled\",\n\t\"message_end\",\n\t\"message_start\",\n\t\"parent_paused_for_background_agents\",\n\t\"runtime_removed\",\n\t\"session_name_changed\",\n\t\"suggest_next\",\n\t\"tasks_update\",\n]);\n\nexport interface RuntimePoolOptions {\n\tcliPath?: string;\n\t/** Extra args for every runtime (e.g. --provider). */\n\tbaseArgs?: string[];\n\t/** RpcClient factory override for tests. */\n\tclientFactory?: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tlogger?: (line: string) => void;\n\t/** Bounds unclaimed RPC snapshot ordering records. */\n\tdashboardBarrierTtlMs?: number;\n\tdashboardBarrierLimit?: number;\n\t/** Injectable clock for deterministic barrier-expiry tests. */\n\tnow?: () => number;\n\t/** Coalescing delay for event-derived fleet snapshot emissions. */\n\tfleetSnapshotDebounceMs?: number;\n}\n\ninterface DashboardBarrier {\n\tseq: number;\n\trecordedAt: number;\n}\n\nexport class RuntimePool {\n\tprivate readonly runtimes = new Map<string, RuntimeHandle>();\n\tprivate readonly listeners: RuntimeEventListener[] = [];\n\tprivate readonly fleetSnapshotListeners: FleetSnapshotListener[] = [];\n\tprivate readonly cliPath: string;\n\tprivate readonly baseArgs: string[];\n\tprivate readonly clientFactory: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tprivate readonly logger: (line: string) => void;\n\t/**\n\t * A single lazily-spawned utility runtime used to service settings/model/\n\t * agent-type endpoints when no user session is live. Kept out of `runtimes`\n\t * (and therefore out of the fleet) so it never shows as a session card.\n\t */\n\tprivate readonly utilities = new Map<string, RuntimeHandle>();\n\tprivate readonly utilityPromises = new Map<string, Promise<RuntimeHandle>>();\n\tprivate readonly starting = new Set<RuntimeHandle>();\n\tprivate readonly startupPromises = new Set<Promise<unknown>>();\n\tprivate readonly exitedHandles = new WeakSet<RuntimeHandle>();\n\t/** Snapshot ordering records observed synchronously from RpcClient stdout. */\n\tprivate readonly dashboardBarriers = new Map<string, DashboardBarrier>();\n\tprivate readonly dashboardBarrierTtlMs: number;\n\tprivate readonly dashboardBarrierLimit: number;\n\tprivate readonly now: () => number;\n\tprivate readonly fleetSnapshotDebounceMs: number;\n\tprivate dashboardBarrierPruneTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate fleetSnapshotTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate closing = false;\n\n\tconstructor(options: RuntimePoolOptions = {}) {\n\t\tthis.cliPath = options.cliPath ?? resolveDrebCliPath();\n\t\tthis.baseArgs = options.baseArgs ?? [];\n\t\tthis.clientFactory =\n\t\t\toptions.clientFactory ?? ((o) => new RpcClient({ cliPath: o.cliPath, cwd: o.cwd, args: o.args }));\n\t\tthis.logger = options.logger ?? ((line) => console.warn(`[dashboard] ${line}`));\n\t\tthis.dashboardBarrierTtlMs = options.dashboardBarrierTtlMs ?? DEFAULT_DASHBOARD_BARRIER_TTL_MS;\n\t\tthis.dashboardBarrierLimit = options.dashboardBarrierLimit ?? DEFAULT_DASHBOARD_BARRIER_LIMIT;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.fleetSnapshotDebounceMs = options.fleetSnapshotDebounceMs ?? DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS;\n\t}\n\n\t/** Subscribe to events from every runtime, tagged with the runtime key. */\n\tonEvent(listener: RuntimeEventListener): () => void {\n\t\tthis.listeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.listeners.indexOf(listener);\n\t\t\tif (i !== -1) this.listeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/** Subscribe to debounced, in-memory fleet snapshots. */\n\tonFleetSnapshot(listener: FleetSnapshotListener): () => void {\n\t\tthis.fleetSnapshotListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.fleetSnapshotListeners.indexOf(listener);\n\t\t\tif (i !== -1) this.fleetSnapshotListeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/**\n\t * Build the fleet's live-runtime view without RPC or disk access. Map\n\t * insertion order is retained intentionally; the UI owns presentation order.\n\t */\n\tfleetSnapshot(): FleetRuntimeSnapshotDto[] {\n\t\treturn [...this.runtimes.values()].map((handle) => this.describeFleetRuntime(handle));\n\t}\n\n\tlist(): RuntimeHandle[] {\n\t\treturn [...this.runtimes.values()];\n\t}\n\n\tget(key: string): RuntimeHandle | undefined {\n\t\treturn this.runtimes.get(key);\n\t}\n\n\t/** Apply a confirmed model mutation to both the child and the pool snapshot. */\n\tasync setModel(\n\t\thandle: RuntimeHandle,\n\t\tprovider: string,\n\t\tmodelId: string,\n\t): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: string;\n\t\tavailableThinkingLevels: string[];\n\t\tsettingsRevision: number;\n\t}> {\n\t\tconst model = await handle.client.setModel(provider, modelId);\n\t\tconst state = await handle.client.getState();\n\t\thandle.lastState = {\n\t\t\t...this.fallbackState(handle),\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t};\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn {\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t};\n\t}\n\n\t/** Apply a confirmed thinking mutation to both the child and the pool snapshot. */\n\tasync setThinkingLevel(\n\t\thandle: RuntimeHandle,\n\t\tlevel: Parameters<RpcClient[\"setThinkingLevel\"]>[0],\n\t): Promise<{ ok: true; settingsRevision: number }> {\n\t\tawait handle.client.setThinkingLevel(level);\n\t\thandle.lastState = { ...this.fallbackState(handle), thinkingLevel: level };\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn { ok: true, settingsRevision: handle.settingsRevision };\n\t}\n\n\t/**\n\t * Record the EventHub sequence synchronously when the RPC snapshot marker\n\t * arrives. The marker line precedes its response on stdout, so this runs\n\t * before the RpcClient response continuation even across separate chunks.\n\t */\n\trecordDashboardBarrier(runtimeKey: string, snapshotId: string, seq: number): void {\n\t\tthis.pruneDashboardBarriers();\n\t\tthis.dashboardBarriers.set(this.dashboardBarrierKey(runtimeKey, snapshotId), { seq, recordedAt: this.now() });\n\t\tthis.pruneDashboardBarriers();\n\t}\n\n\t/**\n\t * Capture a parent-session recovery snapshot and pair it with the sequence\n\t * captured at its RPC marker. This deliberately does not infer ordering from\n\t * await: later EventHub publications naturally have higher sequence numbers.\n\t */\n\tasync snapshotDashboard(handle: RuntimeHandle): Promise<DashboardRuntimeSnapshot> {\n\t\tconst snapshot = await (handle.client as DashboardSnapshotClient).getDashboardSnapshot();\n\t\tthis.pruneDashboardBarriers();\n\t\tconst barrierKey = this.dashboardBarrierKey(handle.key, snapshot.snapshotId);\n\t\tconst barrier = this.dashboardBarriers.get(barrierKey);\n\t\tthis.dashboardBarriers.delete(barrierKey);\n\t\tthis.scheduleDashboardBarrierPrune();\n\t\tif (!barrier) {\n\t\t\tthrow new Error(`Dashboard snapshot ${snapshot.snapshotId} arrived without its ordering barrier`);\n\t\t}\n\t\t// This is an authoritative RPC baseline, so it may legitimately lower the\n\t\t// count after a fork/rewind instead of retaining an event-derived maximum.\n\t\thandle.lastState = snapshot.state;\n\t\tthis.scheduleFleetSnapshot();\n\t\treturn { key: handle.key, barrierSeq: barrier.seq, snapshot };\n\t}\n\n\tprivate dashboardBarrierKey(runtimeKey: string, snapshotId: string): string {\n\t\treturn `${runtimeKey}\\0${snapshotId}`;\n\t}\n\n\tprivate pruneDashboardBarriers(): void {\n\t\tconst oldestAllowed = this.now() - this.dashboardBarrierTtlMs;\n\t\tfor (const [snapshotId, barrier] of this.dashboardBarriers) {\n\t\t\tif (barrier.recordedAt < oldestAllowed) this.dashboardBarriers.delete(snapshotId);\n\t\t}\n\t\twhile (this.dashboardBarriers.size > this.dashboardBarrierLimit) {\n\t\t\tconst oldest = this.dashboardBarriers.keys().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis.dashboardBarriers.delete(oldest);\n\t\t}\n\t\tthis.scheduleDashboardBarrierPrune();\n\t}\n\n\tprivate scheduleDashboardBarrierPrune(): void {\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tlet oldest: DashboardBarrier | undefined;\n\t\tfor (const barrier of this.dashboardBarriers.values()) {\n\t\t\tif (!oldest || barrier.recordedAt < oldest.recordedAt) oldest = barrier;\n\t\t}\n\t\tif (!oldest) return;\n\t\tconst delay = Math.max(1, oldest.recordedAt + this.dashboardBarrierTtlMs - this.now() + 1);\n\t\tthis.dashboardBarrierPruneTimer = setTimeout(() => {\n\t\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\t\tthis.pruneDashboardBarriers();\n\t\t}, delay);\n\t\tthis.dashboardBarrierPruneTimer.unref?.();\n\t}\n\n\tprivate scheduleFleetSnapshot(): void {\n\t\tif (this.closing) return;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = setTimeout(() => {\n\t\t\tthis.fleetSnapshotTimer = undefined;\n\t\t\tif (this.closing) return;\n\t\t\tconst event: FleetSnapshotEventDto = { type: \"fleet_snapshot\", runtimes: this.fleetSnapshot() };\n\t\t\tfor (const listener of this.fleetSnapshotListeners) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(event);\n\t\t\t\t} catch {\n\t\t\t\t\t// An SSE bridge subscriber must not break the pool's event loop.\n\t\t\t\t}\n\t\t\t}\n\t\t}, this.fleetSnapshotDebounceMs);\n\t\tthis.fleetSnapshotTimer.unref?.();\n\t}\n\n\t/** Spawn a new runtime in `cwd`, optionally opening an existing session file. */\n\tasync create(cwd: string, sessionPath?: string): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst key = randomBytes(6).toString(\"hex\");\n\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\tif (sessionPath) args.push(\"--session\", sessionPath);\n\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\tconst handle: RuntimeHandle = {\n\t\t\tkey,\n\t\t\tcwd,\n\t\t\tclient,\n\t\t\tcreatedAt: this.now(),\n\t\t\tlastActivity: this.now(),\n\t\t\tattention: new Map(),\n\t\t\tsettingsRevision: 0,\n\t\t\tsessionFileFallback: sessionPath,\n\t\t\tbackgroundAgents: new Map(),\n\t\t};\n\t\tclient.onEvent((event) => this.handleEvent(handle, event as unknown as Record<string, unknown>));\n\t\tclient.onExit((info) => this.handleRuntimeExit(handle, info));\n\n\t\tconst startup = this.startSessionRuntime(handle);\n\t\tthis.startupPromises.add(startup);\n\t\ttry {\n\t\t\treturn await startup;\n\t\t} finally {\n\t\t\tthis.startupPromises.delete(startup);\n\t\t}\n\t}\n\n\tprivate async startSessionRuntime(handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tawait this.seedBackgroundAgents(handle);\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.runtimes.set(handle.key, handle);\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\t/** Stop a runtime and remove it from the pool. */\n\tasync stop(key: string): Promise<boolean> {\n\t\tconst handle = this.runtimes.get(key);\n\t\tif (!handle) return false;\n\t\tthis.handleEvent(handle, { type: \"runtime_removed\" });\n\t\tthis.runtimes.delete(key);\n\t\tthis.scheduleFleetSnapshot();\n\t\tawait handle.client.stop();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return any live runtime suitable for process-global settings work, spawning\n\t * a hidden utility runtime (in the home directory) if no user session exists.\n\t * This is what lets the settings page — models, agent types, defaults — work\n\t * with zero sessions open, instead of 503-ing.\n\t */\n\tasync ensureUtilityRuntime(cwd = homedir()): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst existing = this.utilities.get(cwd);\n\t\tif (existing) return existing;\n\t\tlet promise = this.utilityPromises.get(cwd);\n\t\tif (!promise) {\n\t\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\t\tconst handle: RuntimeHandle = {\n\t\t\t\tkey: `utility:${cwd}`,\n\t\t\t\tcwd,\n\t\t\t\tclient,\n\t\t\t\tcreatedAt: this.now(),\n\t\t\t\tlastActivity: this.now(),\n\t\t\t\tattention: new Map(),\n\t\t\t\tsettingsRevision: 0,\n\t\t\t\tbackgroundAgents: new Map(),\n\t\t\t};\n\t\t\tconst startup = this.startUtilityRuntime(cwd, handle);\n\t\t\tthis.startupPromises.add(startup);\n\t\t\tpromise = startup\n\t\t\t\t.catch((err) => {\n\t\t\t\t\t// Allow a retry on the next request instead of caching the failure.\n\t\t\t\t\tthis.utilityPromises.delete(cwd);\n\t\t\t\t\tthrow err;\n\t\t\t\t})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis.startupPromises.delete(startup);\n\t\t\t\t});\n\t\t\tthis.utilityPromises.set(cwd, promise);\n\t\t}\n\t\treturn promise;\n\t}\n\n\tprivate async startUtilityRuntime(cwd: string, handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.utilities.set(cwd, handle);\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\tasync stopAll(): Promise<void> {\n\t\tthis.closing = true;\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = undefined;\n\t\tthis.fleetSnapshotListeners.length = 0;\n\t\tthis.dashboardBarriers.clear();\n\t\tconst handles = new Set<RuntimeHandle>([\n\t\t\t...this.runtimes.values(),\n\t\t\t...this.utilities.values(),\n\t\t\t...this.starting.values(),\n\t\t]);\n\t\tconst startupPromises = new Set<Promise<unknown>>([...this.startupPromises, ...this.utilityPromises.values()]);\n\t\tthis.runtimes.clear();\n\t\tthis.utilities.clear();\n\t\tthis.utilityPromises.clear();\n\t\tawait Promise.allSettled([...handles].map((handle) => handle.client.stop()));\n\t\tawait Promise.allSettled([...startupPromises]);\n\t}\n\n\tprivate handleRuntimeExit(handle: RuntimeHandle, info: RpcExitInfo): void {\n\t\tif (this.closing || this.exitedHandles.has(handle) || !this.isLiveHandle(handle)) return;\n\t\tthis.exitedHandles.add(handle);\n\t\tconst message = formatRpcExit(info);\n\t\tthis.recordRuntimeError(handle, message);\n\t\tthis.logger(`runtime ${handle.key} ${message}`);\n\t\tthis.handleEvent(handle, { type: \"agent_end\", messages: [], aborted: true, errorMessage: message });\n\t}\n\n\tprivate isLiveHandle(handle: RuntimeHandle): boolean {\n\t\treturn (\n\t\t\tthis.runtimes.get(handle.key) === handle ||\n\t\t\tthis.utilities.get(handle.cwd) === handle ||\n\t\t\tthis.starting.has(handle)\n\t\t);\n\t}\n\n\tprivate handleEvent(handle: RuntimeHandle, event: Record<string, unknown>): void {\n\t\tconst type = event.type as string;\n\t\tif (type !== \"dashboard_snapshot_barrier\") {\n\t\t\thandle.lastActivity = this.now();\n\t\t\tthis.updateStateFromEvent(handle, event, type);\n\t\t}\n\n\t\t// Track needs-attention sources: extension UI requests, parent\n\t\t// paused, error states.\n\t\tif (type === \"extension_ui_request\") {\n\t\t\tconst method = event.method as string;\n\t\t\tif (\n\t\t\t\tmethod === \"select\" ||\n\t\t\t\tmethod === \"confirm\" ||\n\t\t\t\tmethod === \"input\" ||\n\t\t\t\tmethod === \"editor\" ||\n\t\t\t\tmethod === \"ask\"\n\t\t\t) {\n\t\t\t\thandle.attention.set(`ui:${event.id}`, `extension ${method} awaiting response`);\n\t\t\t}\n\t\t}\n\t\tif (type === \"extension_ui_response_handled\") {\n\t\t\thandle.attention.delete(`ui:${event.id}`);\n\t\t}\n\t\tif (type === \"agent_start\") {\n\t\t\t// A new turn clears prior UI-request attention (requests were resolved or timed out).\n\t\t\tfor (const k of [...handle.attention.keys()]) {\n\t\t\t\tif (k.startsWith(\"ui:\")) handle.attention.delete(k);\n\t\t\t}\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\thandle.attention.delete(\"suggest\");\n\t\t\thandle.attention.delete(\"error\");\n\t\t\thandle.error = undefined;\n\t\t\thandle.providerError = undefined;\n\t\t}\n\t\tif (type === \"suggest_next\") {\n\t\t\t// suggest_next as the ending action = \"your move\": mark needs-attention\n\t\t\t// so the fleet card doesn't read idle. Cleared on the next agent_start.\n\t\t\thandle.attention.set(\"suggest\", \"suggested command awaiting\");\n\t\t}\n\t\tif (type === \"parent_paused_for_background_agents\") {\n\t\t\thandle.attention.set(\"paused\", `paused — ${event.runningAgentCount} background agents running`);\n\t\t}\n\t\tif (type === \"agent_end\") {\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\tif (event.errorMessage) this.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\t\tif (type === \"message_end\") {\n\t\t\tconst message = event.message;\n\t\t\tif (message && typeof message === \"object\" && !Array.isArray(message)) {\n\t\t\t\tconst assistant = message as Record<string, unknown>;\n\t\t\t\tif (assistant.role === \"assistant\" && assistant.stopReason === \"error\") {\n\t\t\t\t\tconst rawError = assistant.errorMessage;\n\t\t\t\t\tconst error = typeof rawError === \"string\" && rawError.trim().length > 0 ? rawError : \"Unknown error\";\n\t\t\t\t\tthis.recordProviderError(handle, error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (type === \"auto_retry_start\") this.clearProviderError(handle);\n\t\tif (type === \"auto_compaction_start\" && event.reason === \"overflow\") this.clearProviderError(handle);\n\t\tif (type === \"auto_retry_end\" && event.success === false && event.finalError) {\n\t\t\tthis.recordProviderError(handle, String(event.finalError));\n\t\t} else if (type === \"auto_retry_end\" && event.success === true) {\n\t\t\tthis.clearProviderError(handle);\n\t\t}\n\t\tif (type === \"auto_compaction_end\" && event.errorMessage) {\n\t\t\tthis.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\n\t\t// Track background agents from lifecycle events.\n\t\tif (type === \"background_agent_start\") {\n\t\t\thandle.backgroundAgents.set(event.agentId as string, {\n\t\t\t\tagentId: event.agentId as string,\n\t\t\t\tagentType: event.agentType as string,\n\t\t\t\ttaskSummary: event.taskSummary as string,\n\t\t\t\tstartedAt: new Date().toISOString(),\n\t\t\t\tstatus: \"running\",\n\t\t\t\tsessionDir: event.sessionDir as string | undefined,\n\t\t\t});\n\t\t}\n\t\tif (type === \"subagent_arbitration\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\tconst record: SubagentArbitrationDto = {\n\t\t\t\t\tstatus: event.status as SubagentArbitrationDto[\"status\"],\n\t\t\t\t\tproposed: event.proposed as SubagentArbitrationDto[\"proposed\"],\n\t\t\t\t\tfinal: (event.final as SubagentArbitrationDto[\"final\"]) ?? null,\n\t\t\t\t\tchanged: (event.changed as SubagentArbitrationDto[\"changed\"]) ?? [],\n\t\t\t\t\tstep: event.step as number | undefined,\n\t\t\t\t\terrorCode: event.errorCode as string | undefined,\n\t\t\t\t\terrorMessage: event.errorMessage as string | undefined,\n\t\t\t\t};\n\t\t\t\texisting.arbitrations = [...(existing.arbitrations ?? []), record];\n\t\t\t\tif (record.status === \"success\" && record.final) existing.agentType = record.final.agent;\n\t\t\t}\n\t\t}\n\t\tif (type === \"background_agent_end\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\texisting.status = event.success ? \"completed\" : \"failed\";\n\t\t\t\texisting.sessionFile = (event.sessionFile as string | undefined) ?? existing.sessionFile;\n\t\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t\t}\n\t\t}\n\n\t\tfor (const listener of this.listeners) {\n\t\t\ttry {\n\t\t\t\tlistener(handle.key, event);\n\t\t\t} catch {\n\t\t\t\t// A broken SSE subscriber must not break event distribution.\n\t\t\t}\n\t\t}\n\t\tif (this.runtimes.get(handle.key) === handle && FLEET_SNAPSHOT_EVENT_TYPES.has(type)) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t}\n\n\t/**\n\t * Events intentionally patch only fields they can prove. Session identity,\n\t * session file, configuration, and context usage remain from the last RPC\n\t * baseline (or the stable creation fallback) until a later reconciliation.\n\t */\n\tprivate updateStateFromEvent(handle: RuntimeHandle, event: Record<string, unknown>, type: string): void {\n\t\tconst state = this.fallbackState(handle);\n\t\tswitch (type) {\n\t\t\tcase \"agent_start\": {\n\t\t\t\tconst model = event.model;\n\t\t\t\tif (\n\t\t\t\t\tmodel &&\n\t\t\t\t\ttypeof model === \"object\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).provider === \"string\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).id === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tconst nextModel = model as { provider: string; id: string };\n\t\t\t\t\tstate.model =\n\t\t\t\t\t\tstate.model?.provider === nextModel.provider && state.model.id === nextModel.id\n\t\t\t\t\t\t\t? { ...state.model, ...nextModel }\n\t\t\t\t\t\t\t: nextModel;\n\t\t\t\t}\n\t\t\t\tstate.isStreaming = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"agent_end\":\n\t\t\t\tstate.isStreaming = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_start\":\n\t\t\t\tstate.isCompacting = true;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_end\":\n\t\t\t\tstate.isCompacting = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_start\":\n\t\t\t\tstate.isRetrying = true;\n\t\t\t\tstate.retryAttempt = typeof event.attempt === \"number\" ? event.attempt : state.retryAttempt;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_end\":\n\t\t\t\tstate.isRetrying = false;\n\t\t\t\tstate.retryAttempt = 0;\n\t\t\t\tbreak;\n\t\t\tcase \"tasks_update\":\n\t\t\t\tif (Array.isArray(event.tasks)) state.tasks = [...event.tasks] as SessionStateDto[\"tasks\"];\n\t\t\t\tbreak;\n\t\t\tcase \"session_name_changed\":\n\t\t\t\tif (typeof event.name === \"string\") state.sessionName = event.name;\n\t\t\t\tbreak;\n\t\t\tcase \"message_start\":\n\t\t\t\tstate.messageCount += 1;\n\t\t\t\tbreak;\n\t\t}\n\t\thandle.lastState = state;\n\t}\n\n\tprivate recordRuntimeError(handle: RuntimeHandle, message: string): void {\n\t\thandle.error = message;\n\t\thandle.attention.set(\"error\", message);\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate recordProviderError(handle: RuntimeHandle, message: string): void {\n\t\thandle.providerError = message;\n\t\tthis.recordRuntimeError(handle, message);\n\t}\n\n\tprivate clearProviderError(handle: RuntimeHandle): void {\n\t\tconst providerError = handle.providerError;\n\t\tif (providerError === undefined) return;\n\t\thandle.providerError = undefined;\n\t\tif (handle.error === providerError) handle.error = undefined;\n\t\tif (handle.attention.get(\"error\") === providerError) handle.attention.delete(\"error\");\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate pruneCompletedBackgroundAgents(handle: RuntimeHandle): void {\n\t\tconst evictable = [...handle.backgroundAgents.values()]\n\t\t\t.map((agent, index) => {\n\t\t\t\tconst startedAtMs = Date.parse(agent.startedAt);\n\t\t\t\treturn { agent, index, startedAtMs: Number.isFinite(startedAtMs) ? startedAtMs : 0 };\n\t\t\t})\n\t\t\t.filter(({ agent }) => agent.status !== \"running\")\n\t\t\t.sort((a, b) => a.startedAtMs - b.startedAtMs || a.index - b.index);\n\t\tconst excess = evictable.length - MAX_COMPLETED_BACKGROUND_AGENTS;\n\t\tif (excess <= 0) return;\n\t\tfor (const { agent } of evictable.slice(0, excess)) {\n\t\t\thandle.backgroundAgents.delete(agent.agentId);\n\t\t}\n\t}\n\n\tprivate fallbackState(handle: RuntimeHandle): SessionStateDto {\n\t\tconst previous = handle.lastState;\n\t\treturn {\n\t\t\t...previous,\n\t\t\tsessionId: previous?.sessionId ?? handle.key,\n\t\t\ttasks: previous?.tasks ? [...previous.tasks] : [],\n\t\t\tthinkingLevel: previous?.thinkingLevel ?? \"off\",\n\t\t\tavailableThinkingLevels: previous?.availableThinkingLevels ? [...previous.availableThinkingLevels] : [\"off\"],\n\t\t\tisStreaming: previous?.isStreaming ?? false,\n\t\t\tisRetrying: previous?.isRetrying ?? false,\n\t\t\tretryAttempt: previous?.retryAttempt ?? 0,\n\t\t\tisCompacting: previous?.isCompacting ?? false,\n\t\t\tsteeringMode: previous?.steeringMode ?? \"all\",\n\t\t\tfollowUpMode: previous?.followUpMode ?? \"all\",\n\t\t\tsessionFile: previous?.sessionFile ?? handle.sessionFileFallback,\n\t\t\tautoCompactionEnabled: previous?.autoCompactionEnabled ?? false,\n\t\t\tmessageCount: previous?.messageCount ?? 0,\n\t\t\tpendingMessageCount: previous?.pendingMessageCount ?? 0,\n\t\t};\n\t}\n\n\tprivate describeFleetRuntime(handle: RuntimeHandle): FleetRuntimeSnapshotDto {\n\t\tconst state = this.fallbackState(handle);\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()].map((agent) => ({ ...agent })),\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n\n\tprivate async seedBackgroundAgents(handle: RuntimeHandle): Promise<void> {\n\t\ttry {\n\t\t\tconst agents = (await handle.client.listBackgroundAgents()) as unknown as BackgroundAgentDto[];\n\t\t\tfor (const agent of agents) {\n\t\t\t\thandle.backgroundAgents.set(agent.agentId, agent);\n\t\t\t}\n\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} background-agent registry unavailable: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Snapshot a runtime for the fleet endpoint. */\n\tasync describe(handle: RuntimeHandle): Promise<RuntimeInfoDto> {\n\t\tconst previousFleetRuntime =\n\t\t\tthis.runtimes.get(handle.key) === handle ? this.describeFleetRuntime(handle) : undefined;\n\t\tlet fleetRuntimeEnriched = false;\n\t\tlet state: SessionStateDto;\n\t\ttry {\n\t\t\tconst authoritative = (await handle.client.getState()) as unknown as SessionStateDto;\n\t\t\tconst fallback = this.fallbackState(handle);\n\t\t\tstate = {\n\t\t\t\t...fallback,\n\t\t\t\t...authoritative,\n\t\t\t\tsessionId: authoritative.sessionId ?? fallback.sessionId,\n\t\t\t\tsessionFile: authoritative.sessionFile ?? fallback.sessionFile,\n\t\t\t\ttasks: authoritative.tasks ?? fallback.tasks,\n\t\t\t};\n\t\t\thandle.lastState = state;\n\t\t\tfleetRuntimeEnriched = true;\n\t\t\tif (handle.error?.startsWith(\"RPC process\")) {\n\t\t\t\thandle.error = undefined;\n\t\t\t\thandle.attention.delete(\"error\");\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.recordRuntimeError(handle, message);\n\t\t\tthis.logger(`runtime ${handle.key} state unavailable for fleet card: ${message}`);\n\t\t\tstate = this.fallbackState(handle);\n\t\t}\n\t\tlet stats: RuntimeStatsSummaryDto | undefined;\n\t\ttry {\n\t\t\tconst sessionStats = await handle.client.getSessionStats();\n\t\t\tstats = { tokensTotal: sessionStats.tokens.total, cost: sessionStats.cost };\n\t\t\tif (sessionStats.contextUsage) {\n\t\t\t\thandle.lastState = { ...this.fallbackState(handle), contextUsage: sessionStats.contextUsage };\n\t\t\t\tfleetRuntimeEnriched = true;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} stats unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tlet lastAssistantText: string | undefined;\n\t\ttry {\n\t\t\tconst text = await handle.client.getLastAssistantText();\n\t\t\tlastAssistantText = text ? text.slice(0, 200) : undefined;\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} last assistant text unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tfleetRuntimeEnriched &&\n\t\t\tpreviousFleetRuntime &&\n\t\t\tthis.runtimes.get(handle.key) === handle &&\n\t\t\t!isDeepStrictEqual(previousFleetRuntime, this.describeFleetRuntime(handle))\n\t\t) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tstats,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()],\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tlastAssistantText,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n}\n"]}
@@ -20,7 +20,14 @@ export function resolveDrebCliPath() {
20
20
  function formatRpcExit(info) {
21
21
  if (info.error)
22
22
  return `RPC process failed: ${info.error.message}`;
23
- return `RPC process exited (code ${info.code}, signal ${info.signal})`;
23
+ const tail = info.stderrTail?.trim();
24
+ // When the child aborted on its own (e.g. the stdout backpressure guard),
25
+ // its stderr tail carries the actual reason — surface it instead of a bare
26
+ // exit code. The tail may be multi-line; the existing UI already renders
27
+ // multi-line error messages (e.g. timeouts embed full stderr).
28
+ return tail
29
+ ? `RPC process exited (code ${info.code}, signal ${info.signal}). Stderr tail: ${tail}`
30
+ : `RPC process exited (code ${info.code}, signal ${info.signal})`;
24
31
  }
25
32
  export { MAX_COMPLETED_BACKGROUND_AGENTS };
26
33
  export const DEFAULT_DASHBOARD_BARRIER_TTL_MS = 5 * 60_000;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-pool.js","sourceRoot":"","sources":["../../src/server/runtime-pool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC runtime pool — one `dreb --mode rpc` child process per live session.\n *\n * dreb's RPC mode is strictly one-session-per-process (switch_session repoints\n * the same process; it never multiplexes), so the pool spawns N children keyed\n * by an opaque runtime key. The telegram bridge is the in-repo precedent.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { RpcClient, type RpcDashboardSnapshot, type RpcExitInfo } from \"@dreb/coding-agent/rpc\";\nimport {\n\ttype BackgroundAgentDto,\n\ttype FleetRuntimeSnapshotDto,\n\ttype FleetSnapshotEventDto,\n\tMAX_COMPLETED_BACKGROUND_AGENTS,\n\ttype RuntimeInfoDto,\n\ttype RuntimeStatsSummaryDto,\n\ttype SessionStateDto,\n\ttype SubagentArbitrationDto,\n} from \"../shared/protocol.js\";\n\n/** Resolve the absolute path to the dreb CLI (RpcClient defaults to a cwd-relative path). */\nexport function resolveDrebCliPath(): string {\n\tconst resolved = import.meta.resolve(\"@dreb/coding-agent\");\n\treturn join(dirname(fileURLToPath(resolved)), \"cli.js\");\n}\n\nfunction formatRpcExit(info: RpcExitInfo): string {\n\tif (info.error) return `RPC process failed: ${info.error.message}`;\n\treturn `RPC process exited (code ${info.code}, signal ${info.signal})`;\n}\n\nexport type RuntimeEventListener = (key: string, event: Record<string, unknown>) => void;\n\n/** Listener for coalesced, synchronous fleet runtime snapshots. */\nexport type FleetSnapshotListener = (event: FleetSnapshotEventDto) => void;\n\nexport { MAX_COMPLETED_BACKGROUND_AGENTS };\n\ntype DashboardSnapshotClient = RpcClient & { getDashboardSnapshot(): Promise<RpcDashboardSnapshot> };\n\nexport interface DashboardRuntimeSnapshot {\n\tkey: string;\n\tbarrierSeq: number;\n\tsnapshot: RpcDashboardSnapshot;\n}\n\nexport interface RuntimeHandle {\n\tkey: string;\n\tcwd: string;\n\tclient: RpcClient;\n\t/** Session start time (ms epoch) — stable tiebreak for deterministic fleet ordering. */\n\tcreatedAt: number;\n\tlastActivity: number;\n\t/** Needs-attention sources, keyed so they can be cleared independently. */\n\tattention: Map<string, string>;\n\t/** Last runtime-level error, persisted server-side so fleet refreshes stay honest. */\n\terror?: string;\n\t/** Provider error currently responsible for error/attention; retry may clear only this source. */\n\tproviderError?: string;\n\t/** Last authoritative state, patched only with event-derivable fields between RPC reads. */\n\tlastState?: SessionStateDto;\n\t/** Monotonic revision for confirmed model/thinking mutations. */\n\tsettingsRevision: number;\n\t/** Resume-path fallback; events must never invent or overwrite session identity. */\n\tsessionFileFallback?: string;\n\t/** Background agents seen via events (agentId → latest info). */\n\tbackgroundAgents: Map<string, BackgroundAgentDto>;\n}\n\nexport const DEFAULT_DASHBOARD_BARRIER_TTL_MS = 5 * 60_000;\nexport const DEFAULT_DASHBOARD_BARRIER_LIMIT = 1000;\nexport const DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS = 200;\n\n/** Events that mutate a field carried by the lightweight fleet snapshot. */\nconst FLEET_SNAPSHOT_EVENT_TYPES = new Set([\n\t\"agent_start\",\n\t\"agent_end\",\n\t\"auto_compaction_start\",\n\t\"auto_compaction_end\",\n\t\"auto_retry_start\",\n\t\"auto_retry_end\",\n\t\"background_agent_start\",\n\t\"background_agent_end\",\n\t\"subagent_arbitration\",\n\t\"extension_ui_request\",\n\t\"extension_ui_response_handled\",\n\t\"message_end\",\n\t\"message_start\",\n\t\"parent_paused_for_background_agents\",\n\t\"runtime_removed\",\n\t\"session_name_changed\",\n\t\"suggest_next\",\n\t\"tasks_update\",\n]);\n\nexport interface RuntimePoolOptions {\n\tcliPath?: string;\n\t/** Extra args for every runtime (e.g. --provider). */\n\tbaseArgs?: string[];\n\t/** RpcClient factory override for tests. */\n\tclientFactory?: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tlogger?: (line: string) => void;\n\t/** Bounds unclaimed RPC snapshot ordering records. */\n\tdashboardBarrierTtlMs?: number;\n\tdashboardBarrierLimit?: number;\n\t/** Injectable clock for deterministic barrier-expiry tests. */\n\tnow?: () => number;\n\t/** Coalescing delay for event-derived fleet snapshot emissions. */\n\tfleetSnapshotDebounceMs?: number;\n}\n\ninterface DashboardBarrier {\n\tseq: number;\n\trecordedAt: number;\n}\n\nexport class RuntimePool {\n\tprivate readonly runtimes = new Map<string, RuntimeHandle>();\n\tprivate readonly listeners: RuntimeEventListener[] = [];\n\tprivate readonly fleetSnapshotListeners: FleetSnapshotListener[] = [];\n\tprivate readonly cliPath: string;\n\tprivate readonly baseArgs: string[];\n\tprivate readonly clientFactory: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tprivate readonly logger: (line: string) => void;\n\t/**\n\t * A single lazily-spawned utility runtime used to service settings/model/\n\t * agent-type endpoints when no user session is live. Kept out of `runtimes`\n\t * (and therefore out of the fleet) so it never shows as a session card.\n\t */\n\tprivate readonly utilities = new Map<string, RuntimeHandle>();\n\tprivate readonly utilityPromises = new Map<string, Promise<RuntimeHandle>>();\n\tprivate readonly starting = new Set<RuntimeHandle>();\n\tprivate readonly startupPromises = new Set<Promise<unknown>>();\n\tprivate readonly exitedHandles = new WeakSet<RuntimeHandle>();\n\t/** Snapshot ordering records observed synchronously from RpcClient stdout. */\n\tprivate readonly dashboardBarriers = new Map<string, DashboardBarrier>();\n\tprivate readonly dashboardBarrierTtlMs: number;\n\tprivate readonly dashboardBarrierLimit: number;\n\tprivate readonly now: () => number;\n\tprivate readonly fleetSnapshotDebounceMs: number;\n\tprivate dashboardBarrierPruneTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate fleetSnapshotTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate closing = false;\n\n\tconstructor(options: RuntimePoolOptions = {}) {\n\t\tthis.cliPath = options.cliPath ?? resolveDrebCliPath();\n\t\tthis.baseArgs = options.baseArgs ?? [];\n\t\tthis.clientFactory =\n\t\t\toptions.clientFactory ?? ((o) => new RpcClient({ cliPath: o.cliPath, cwd: o.cwd, args: o.args }));\n\t\tthis.logger = options.logger ?? ((line) => console.warn(`[dashboard] ${line}`));\n\t\tthis.dashboardBarrierTtlMs = options.dashboardBarrierTtlMs ?? DEFAULT_DASHBOARD_BARRIER_TTL_MS;\n\t\tthis.dashboardBarrierLimit = options.dashboardBarrierLimit ?? DEFAULT_DASHBOARD_BARRIER_LIMIT;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.fleetSnapshotDebounceMs = options.fleetSnapshotDebounceMs ?? DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS;\n\t}\n\n\t/** Subscribe to events from every runtime, tagged with the runtime key. */\n\tonEvent(listener: RuntimeEventListener): () => void {\n\t\tthis.listeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.listeners.indexOf(listener);\n\t\t\tif (i !== -1) this.listeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/** Subscribe to debounced, in-memory fleet snapshots. */\n\tonFleetSnapshot(listener: FleetSnapshotListener): () => void {\n\t\tthis.fleetSnapshotListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.fleetSnapshotListeners.indexOf(listener);\n\t\t\tif (i !== -1) this.fleetSnapshotListeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/**\n\t * Build the fleet's live-runtime view without RPC or disk access. Map\n\t * insertion order is retained intentionally; the UI owns presentation order.\n\t */\n\tfleetSnapshot(): FleetRuntimeSnapshotDto[] {\n\t\treturn [...this.runtimes.values()].map((handle) => this.describeFleetRuntime(handle));\n\t}\n\n\tlist(): RuntimeHandle[] {\n\t\treturn [...this.runtimes.values()];\n\t}\n\n\tget(key: string): RuntimeHandle | undefined {\n\t\treturn this.runtimes.get(key);\n\t}\n\n\t/** Apply a confirmed model mutation to both the child and the pool snapshot. */\n\tasync setModel(\n\t\thandle: RuntimeHandle,\n\t\tprovider: string,\n\t\tmodelId: string,\n\t): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: string;\n\t\tavailableThinkingLevels: string[];\n\t\tsettingsRevision: number;\n\t}> {\n\t\tconst model = await handle.client.setModel(provider, modelId);\n\t\tconst state = await handle.client.getState();\n\t\thandle.lastState = {\n\t\t\t...this.fallbackState(handle),\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t};\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn {\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t};\n\t}\n\n\t/** Apply a confirmed thinking mutation to both the child and the pool snapshot. */\n\tasync setThinkingLevel(\n\t\thandle: RuntimeHandle,\n\t\tlevel: Parameters<RpcClient[\"setThinkingLevel\"]>[0],\n\t): Promise<{ ok: true; settingsRevision: number }> {\n\t\tawait handle.client.setThinkingLevel(level);\n\t\thandle.lastState = { ...this.fallbackState(handle), thinkingLevel: level };\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn { ok: true, settingsRevision: handle.settingsRevision };\n\t}\n\n\t/**\n\t * Record the EventHub sequence synchronously when the RPC snapshot marker\n\t * arrives. The marker line precedes its response on stdout, so this runs\n\t * before the RpcClient response continuation even across separate chunks.\n\t */\n\trecordDashboardBarrier(runtimeKey: string, snapshotId: string, seq: number): void {\n\t\tthis.pruneDashboardBarriers();\n\t\tthis.dashboardBarriers.set(this.dashboardBarrierKey(runtimeKey, snapshotId), { seq, recordedAt: this.now() });\n\t\tthis.pruneDashboardBarriers();\n\t}\n\n\t/**\n\t * Capture a parent-session recovery snapshot and pair it with the sequence\n\t * captured at its RPC marker. This deliberately does not infer ordering from\n\t * await: later EventHub publications naturally have higher sequence numbers.\n\t */\n\tasync snapshotDashboard(handle: RuntimeHandle): Promise<DashboardRuntimeSnapshot> {\n\t\tconst snapshot = await (handle.client as DashboardSnapshotClient).getDashboardSnapshot();\n\t\tthis.pruneDashboardBarriers();\n\t\tconst barrierKey = this.dashboardBarrierKey(handle.key, snapshot.snapshotId);\n\t\tconst barrier = this.dashboardBarriers.get(barrierKey);\n\t\tthis.dashboardBarriers.delete(barrierKey);\n\t\tthis.scheduleDashboardBarrierPrune();\n\t\tif (!barrier) {\n\t\t\tthrow new Error(`Dashboard snapshot ${snapshot.snapshotId} arrived without its ordering barrier`);\n\t\t}\n\t\t// This is an authoritative RPC baseline, so it may legitimately lower the\n\t\t// count after a fork/rewind instead of retaining an event-derived maximum.\n\t\thandle.lastState = snapshot.state;\n\t\tthis.scheduleFleetSnapshot();\n\t\treturn { key: handle.key, barrierSeq: barrier.seq, snapshot };\n\t}\n\n\tprivate dashboardBarrierKey(runtimeKey: string, snapshotId: string): string {\n\t\treturn `${runtimeKey}\\0${snapshotId}`;\n\t}\n\n\tprivate pruneDashboardBarriers(): void {\n\t\tconst oldestAllowed = this.now() - this.dashboardBarrierTtlMs;\n\t\tfor (const [snapshotId, barrier] of this.dashboardBarriers) {\n\t\t\tif (barrier.recordedAt < oldestAllowed) this.dashboardBarriers.delete(snapshotId);\n\t\t}\n\t\twhile (this.dashboardBarriers.size > this.dashboardBarrierLimit) {\n\t\t\tconst oldest = this.dashboardBarriers.keys().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis.dashboardBarriers.delete(oldest);\n\t\t}\n\t\tthis.scheduleDashboardBarrierPrune();\n\t}\n\n\tprivate scheduleDashboardBarrierPrune(): void {\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tlet oldest: DashboardBarrier | undefined;\n\t\tfor (const barrier of this.dashboardBarriers.values()) {\n\t\t\tif (!oldest || barrier.recordedAt < oldest.recordedAt) oldest = barrier;\n\t\t}\n\t\tif (!oldest) return;\n\t\tconst delay = Math.max(1, oldest.recordedAt + this.dashboardBarrierTtlMs - this.now() + 1);\n\t\tthis.dashboardBarrierPruneTimer = setTimeout(() => {\n\t\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\t\tthis.pruneDashboardBarriers();\n\t\t}, delay);\n\t\tthis.dashboardBarrierPruneTimer.unref?.();\n\t}\n\n\tprivate scheduleFleetSnapshot(): void {\n\t\tif (this.closing) return;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = setTimeout(() => {\n\t\t\tthis.fleetSnapshotTimer = undefined;\n\t\t\tif (this.closing) return;\n\t\t\tconst event: FleetSnapshotEventDto = { type: \"fleet_snapshot\", runtimes: this.fleetSnapshot() };\n\t\t\tfor (const listener of this.fleetSnapshotListeners) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(event);\n\t\t\t\t} catch {\n\t\t\t\t\t// An SSE bridge subscriber must not break the pool's event loop.\n\t\t\t\t}\n\t\t\t}\n\t\t}, this.fleetSnapshotDebounceMs);\n\t\tthis.fleetSnapshotTimer.unref?.();\n\t}\n\n\t/** Spawn a new runtime in `cwd`, optionally opening an existing session file. */\n\tasync create(cwd: string, sessionPath?: string): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst key = randomBytes(6).toString(\"hex\");\n\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\tif (sessionPath) args.push(\"--session\", sessionPath);\n\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\tconst handle: RuntimeHandle = {\n\t\t\tkey,\n\t\t\tcwd,\n\t\t\tclient,\n\t\t\tcreatedAt: this.now(),\n\t\t\tlastActivity: this.now(),\n\t\t\tattention: new Map(),\n\t\t\tsettingsRevision: 0,\n\t\t\tsessionFileFallback: sessionPath,\n\t\t\tbackgroundAgents: new Map(),\n\t\t};\n\t\tclient.onEvent((event) => this.handleEvent(handle, event as unknown as Record<string, unknown>));\n\t\tclient.onExit((info) => this.handleRuntimeExit(handle, info));\n\n\t\tconst startup = this.startSessionRuntime(handle);\n\t\tthis.startupPromises.add(startup);\n\t\ttry {\n\t\t\treturn await startup;\n\t\t} finally {\n\t\t\tthis.startupPromises.delete(startup);\n\t\t}\n\t}\n\n\tprivate async startSessionRuntime(handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tawait this.seedBackgroundAgents(handle);\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.runtimes.set(handle.key, handle);\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\t/** Stop a runtime and remove it from the pool. */\n\tasync stop(key: string): Promise<boolean> {\n\t\tconst handle = this.runtimes.get(key);\n\t\tif (!handle) return false;\n\t\tthis.handleEvent(handle, { type: \"runtime_removed\" });\n\t\tthis.runtimes.delete(key);\n\t\tthis.scheduleFleetSnapshot();\n\t\tawait handle.client.stop();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return any live runtime suitable for process-global settings work, spawning\n\t * a hidden utility runtime (in the home directory) if no user session exists.\n\t * This is what lets the settings page — models, agent types, defaults — work\n\t * with zero sessions open, instead of 503-ing.\n\t */\n\tasync ensureUtilityRuntime(cwd = homedir()): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst existing = this.utilities.get(cwd);\n\t\tif (existing) return existing;\n\t\tlet promise = this.utilityPromises.get(cwd);\n\t\tif (!promise) {\n\t\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\t\tconst handle: RuntimeHandle = {\n\t\t\t\tkey: `utility:${cwd}`,\n\t\t\t\tcwd,\n\t\t\t\tclient,\n\t\t\t\tcreatedAt: this.now(),\n\t\t\t\tlastActivity: this.now(),\n\t\t\t\tattention: new Map(),\n\t\t\t\tsettingsRevision: 0,\n\t\t\t\tbackgroundAgents: new Map(),\n\t\t\t};\n\t\t\tconst startup = this.startUtilityRuntime(cwd, handle);\n\t\t\tthis.startupPromises.add(startup);\n\t\t\tpromise = startup\n\t\t\t\t.catch((err) => {\n\t\t\t\t\t// Allow a retry on the next request instead of caching the failure.\n\t\t\t\t\tthis.utilityPromises.delete(cwd);\n\t\t\t\t\tthrow err;\n\t\t\t\t})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis.startupPromises.delete(startup);\n\t\t\t\t});\n\t\t\tthis.utilityPromises.set(cwd, promise);\n\t\t}\n\t\treturn promise;\n\t}\n\n\tprivate async startUtilityRuntime(cwd: string, handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.utilities.set(cwd, handle);\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\tasync stopAll(): Promise<void> {\n\t\tthis.closing = true;\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = undefined;\n\t\tthis.fleetSnapshotListeners.length = 0;\n\t\tthis.dashboardBarriers.clear();\n\t\tconst handles = new Set<RuntimeHandle>([\n\t\t\t...this.runtimes.values(),\n\t\t\t...this.utilities.values(),\n\t\t\t...this.starting.values(),\n\t\t]);\n\t\tconst startupPromises = new Set<Promise<unknown>>([...this.startupPromises, ...this.utilityPromises.values()]);\n\t\tthis.runtimes.clear();\n\t\tthis.utilities.clear();\n\t\tthis.utilityPromises.clear();\n\t\tawait Promise.allSettled([...handles].map((handle) => handle.client.stop()));\n\t\tawait Promise.allSettled([...startupPromises]);\n\t}\n\n\tprivate handleRuntimeExit(handle: RuntimeHandle, info: RpcExitInfo): void {\n\t\tif (this.closing || this.exitedHandles.has(handle) || !this.isLiveHandle(handle)) return;\n\t\tthis.exitedHandles.add(handle);\n\t\tconst message = formatRpcExit(info);\n\t\tthis.recordRuntimeError(handle, message);\n\t\tthis.logger(`runtime ${handle.key} ${message}`);\n\t\tthis.handleEvent(handle, { type: \"agent_end\", messages: [], aborted: true, errorMessage: message });\n\t}\n\n\tprivate isLiveHandle(handle: RuntimeHandle): boolean {\n\t\treturn (\n\t\t\tthis.runtimes.get(handle.key) === handle ||\n\t\t\tthis.utilities.get(handle.cwd) === handle ||\n\t\t\tthis.starting.has(handle)\n\t\t);\n\t}\n\n\tprivate handleEvent(handle: RuntimeHandle, event: Record<string, unknown>): void {\n\t\tconst type = event.type as string;\n\t\tif (type !== \"dashboard_snapshot_barrier\") {\n\t\t\thandle.lastActivity = this.now();\n\t\t\tthis.updateStateFromEvent(handle, event, type);\n\t\t}\n\n\t\t// Track needs-attention sources: extension UI requests, parent\n\t\t// paused, error states.\n\t\tif (type === \"extension_ui_request\") {\n\t\t\tconst method = event.method as string;\n\t\t\tif (\n\t\t\t\tmethod === \"select\" ||\n\t\t\t\tmethod === \"confirm\" ||\n\t\t\t\tmethod === \"input\" ||\n\t\t\t\tmethod === \"editor\" ||\n\t\t\t\tmethod === \"ask\"\n\t\t\t) {\n\t\t\t\thandle.attention.set(`ui:${event.id}`, `extension ${method} awaiting response`);\n\t\t\t}\n\t\t}\n\t\tif (type === \"extension_ui_response_handled\") {\n\t\t\thandle.attention.delete(`ui:${event.id}`);\n\t\t}\n\t\tif (type === \"agent_start\") {\n\t\t\t// A new turn clears prior UI-request attention (requests were resolved or timed out).\n\t\t\tfor (const k of [...handle.attention.keys()]) {\n\t\t\t\tif (k.startsWith(\"ui:\")) handle.attention.delete(k);\n\t\t\t}\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\thandle.attention.delete(\"suggest\");\n\t\t\thandle.attention.delete(\"error\");\n\t\t\thandle.error = undefined;\n\t\t\thandle.providerError = undefined;\n\t\t}\n\t\tif (type === \"suggest_next\") {\n\t\t\t// suggest_next as the ending action = \"your move\": mark needs-attention\n\t\t\t// so the fleet card doesn't read idle. Cleared on the next agent_start.\n\t\t\thandle.attention.set(\"suggest\", \"suggested command awaiting\");\n\t\t}\n\t\tif (type === \"parent_paused_for_background_agents\") {\n\t\t\thandle.attention.set(\"paused\", `paused — ${event.runningAgentCount} background agents running`);\n\t\t}\n\t\tif (type === \"agent_end\") {\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\tif (event.errorMessage) this.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\t\tif (type === \"message_end\") {\n\t\t\tconst message = event.message;\n\t\t\tif (message && typeof message === \"object\" && !Array.isArray(message)) {\n\t\t\t\tconst assistant = message as Record<string, unknown>;\n\t\t\t\tif (assistant.role === \"assistant\" && assistant.stopReason === \"error\") {\n\t\t\t\t\tconst rawError = assistant.errorMessage;\n\t\t\t\t\tconst error = typeof rawError === \"string\" && rawError.trim().length > 0 ? rawError : \"Unknown error\";\n\t\t\t\t\tthis.recordProviderError(handle, error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (type === \"auto_retry_start\") this.clearProviderError(handle);\n\t\tif (type === \"auto_compaction_start\" && event.reason === \"overflow\") this.clearProviderError(handle);\n\t\tif (type === \"auto_retry_end\" && event.success === false && event.finalError) {\n\t\t\tthis.recordProviderError(handle, String(event.finalError));\n\t\t} else if (type === \"auto_retry_end\" && event.success === true) {\n\t\t\tthis.clearProviderError(handle);\n\t\t}\n\t\tif (type === \"auto_compaction_end\" && event.errorMessage) {\n\t\t\tthis.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\n\t\t// Track background agents from lifecycle events.\n\t\tif (type === \"background_agent_start\") {\n\t\t\thandle.backgroundAgents.set(event.agentId as string, {\n\t\t\t\tagentId: event.agentId as string,\n\t\t\t\tagentType: event.agentType as string,\n\t\t\t\ttaskSummary: event.taskSummary as string,\n\t\t\t\tstartedAt: new Date().toISOString(),\n\t\t\t\tstatus: \"running\",\n\t\t\t\tsessionDir: event.sessionDir as string | undefined,\n\t\t\t});\n\t\t}\n\t\tif (type === \"subagent_arbitration\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\tconst record: SubagentArbitrationDto = {\n\t\t\t\t\tstatus: event.status as SubagentArbitrationDto[\"status\"],\n\t\t\t\t\tproposed: event.proposed as SubagentArbitrationDto[\"proposed\"],\n\t\t\t\t\tfinal: (event.final as SubagentArbitrationDto[\"final\"]) ?? null,\n\t\t\t\t\tchanged: (event.changed as SubagentArbitrationDto[\"changed\"]) ?? [],\n\t\t\t\t\tstep: event.step as number | undefined,\n\t\t\t\t\terrorCode: event.errorCode as string | undefined,\n\t\t\t\t\terrorMessage: event.errorMessage as string | undefined,\n\t\t\t\t};\n\t\t\t\texisting.arbitrations = [...(existing.arbitrations ?? []), record];\n\t\t\t\tif (record.status === \"success\" && record.final) existing.agentType = record.final.agent;\n\t\t\t}\n\t\t}\n\t\tif (type === \"background_agent_end\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\texisting.status = event.success ? \"completed\" : \"failed\";\n\t\t\t\texisting.sessionFile = (event.sessionFile as string | undefined) ?? existing.sessionFile;\n\t\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t\t}\n\t\t}\n\n\t\tfor (const listener of this.listeners) {\n\t\t\ttry {\n\t\t\t\tlistener(handle.key, event);\n\t\t\t} catch {\n\t\t\t\t// A broken SSE subscriber must not break event distribution.\n\t\t\t}\n\t\t}\n\t\tif (this.runtimes.get(handle.key) === handle && FLEET_SNAPSHOT_EVENT_TYPES.has(type)) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t}\n\n\t/**\n\t * Events intentionally patch only fields they can prove. Session identity,\n\t * session file, configuration, and context usage remain from the last RPC\n\t * baseline (or the stable creation fallback) until a later reconciliation.\n\t */\n\tprivate updateStateFromEvent(handle: RuntimeHandle, event: Record<string, unknown>, type: string): void {\n\t\tconst state = this.fallbackState(handle);\n\t\tswitch (type) {\n\t\t\tcase \"agent_start\": {\n\t\t\t\tconst model = event.model;\n\t\t\t\tif (\n\t\t\t\t\tmodel &&\n\t\t\t\t\ttypeof model === \"object\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).provider === \"string\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).id === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tconst nextModel = model as { provider: string; id: string };\n\t\t\t\t\tstate.model =\n\t\t\t\t\t\tstate.model?.provider === nextModel.provider && state.model.id === nextModel.id\n\t\t\t\t\t\t\t? { ...state.model, ...nextModel }\n\t\t\t\t\t\t\t: nextModel;\n\t\t\t\t}\n\t\t\t\tstate.isStreaming = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"agent_end\":\n\t\t\t\tstate.isStreaming = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_start\":\n\t\t\t\tstate.isCompacting = true;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_end\":\n\t\t\t\tstate.isCompacting = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_start\":\n\t\t\t\tstate.isRetrying = true;\n\t\t\t\tstate.retryAttempt = typeof event.attempt === \"number\" ? event.attempt : state.retryAttempt;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_end\":\n\t\t\t\tstate.isRetrying = false;\n\t\t\t\tstate.retryAttempt = 0;\n\t\t\t\tbreak;\n\t\t\tcase \"tasks_update\":\n\t\t\t\tif (Array.isArray(event.tasks)) state.tasks = [...event.tasks] as SessionStateDto[\"tasks\"];\n\t\t\t\tbreak;\n\t\t\tcase \"session_name_changed\":\n\t\t\t\tif (typeof event.name === \"string\") state.sessionName = event.name;\n\t\t\t\tbreak;\n\t\t\tcase \"message_start\":\n\t\t\t\tstate.messageCount += 1;\n\t\t\t\tbreak;\n\t\t}\n\t\thandle.lastState = state;\n\t}\n\n\tprivate recordRuntimeError(handle: RuntimeHandle, message: string): void {\n\t\thandle.error = message;\n\t\thandle.attention.set(\"error\", message);\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate recordProviderError(handle: RuntimeHandle, message: string): void {\n\t\thandle.providerError = message;\n\t\tthis.recordRuntimeError(handle, message);\n\t}\n\n\tprivate clearProviderError(handle: RuntimeHandle): void {\n\t\tconst providerError = handle.providerError;\n\t\tif (providerError === undefined) return;\n\t\thandle.providerError = undefined;\n\t\tif (handle.error === providerError) handle.error = undefined;\n\t\tif (handle.attention.get(\"error\") === providerError) handle.attention.delete(\"error\");\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate pruneCompletedBackgroundAgents(handle: RuntimeHandle): void {\n\t\tconst evictable = [...handle.backgroundAgents.values()]\n\t\t\t.map((agent, index) => {\n\t\t\t\tconst startedAtMs = Date.parse(agent.startedAt);\n\t\t\t\treturn { agent, index, startedAtMs: Number.isFinite(startedAtMs) ? startedAtMs : 0 };\n\t\t\t})\n\t\t\t.filter(({ agent }) => agent.status !== \"running\")\n\t\t\t.sort((a, b) => a.startedAtMs - b.startedAtMs || a.index - b.index);\n\t\tconst excess = evictable.length - MAX_COMPLETED_BACKGROUND_AGENTS;\n\t\tif (excess <= 0) return;\n\t\tfor (const { agent } of evictable.slice(0, excess)) {\n\t\t\thandle.backgroundAgents.delete(agent.agentId);\n\t\t}\n\t}\n\n\tprivate fallbackState(handle: RuntimeHandle): SessionStateDto {\n\t\tconst previous = handle.lastState;\n\t\treturn {\n\t\t\t...previous,\n\t\t\tsessionId: previous?.sessionId ?? handle.key,\n\t\t\ttasks: previous?.tasks ? [...previous.tasks] : [],\n\t\t\tthinkingLevel: previous?.thinkingLevel ?? \"off\",\n\t\t\tavailableThinkingLevels: previous?.availableThinkingLevels ? [...previous.availableThinkingLevels] : [\"off\"],\n\t\t\tisStreaming: previous?.isStreaming ?? false,\n\t\t\tisRetrying: previous?.isRetrying ?? false,\n\t\t\tretryAttempt: previous?.retryAttempt ?? 0,\n\t\t\tisCompacting: previous?.isCompacting ?? false,\n\t\t\tsteeringMode: previous?.steeringMode ?? \"all\",\n\t\t\tfollowUpMode: previous?.followUpMode ?? \"all\",\n\t\t\tsessionFile: previous?.sessionFile ?? handle.sessionFileFallback,\n\t\t\tautoCompactionEnabled: previous?.autoCompactionEnabled ?? false,\n\t\t\tmessageCount: previous?.messageCount ?? 0,\n\t\t\tpendingMessageCount: previous?.pendingMessageCount ?? 0,\n\t\t};\n\t}\n\n\tprivate describeFleetRuntime(handle: RuntimeHandle): FleetRuntimeSnapshotDto {\n\t\tconst state = this.fallbackState(handle);\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()].map((agent) => ({ ...agent })),\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n\n\tprivate async seedBackgroundAgents(handle: RuntimeHandle): Promise<void> {\n\t\ttry {\n\t\t\tconst agents = (await handle.client.listBackgroundAgents()) as unknown as BackgroundAgentDto[];\n\t\t\tfor (const agent of agents) {\n\t\t\t\thandle.backgroundAgents.set(agent.agentId, agent);\n\t\t\t}\n\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} background-agent registry unavailable: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Snapshot a runtime for the fleet endpoint. */\n\tasync describe(handle: RuntimeHandle): Promise<RuntimeInfoDto> {\n\t\tconst previousFleetRuntime =\n\t\t\tthis.runtimes.get(handle.key) === handle ? this.describeFleetRuntime(handle) : undefined;\n\t\tlet fleetRuntimeEnriched = false;\n\t\tlet state: SessionStateDto;\n\t\ttry {\n\t\t\tconst authoritative = (await handle.client.getState()) as unknown as SessionStateDto;\n\t\t\tconst fallback = this.fallbackState(handle);\n\t\t\tstate = {\n\t\t\t\t...fallback,\n\t\t\t\t...authoritative,\n\t\t\t\tsessionId: authoritative.sessionId ?? fallback.sessionId,\n\t\t\t\tsessionFile: authoritative.sessionFile ?? fallback.sessionFile,\n\t\t\t\ttasks: authoritative.tasks ?? fallback.tasks,\n\t\t\t};\n\t\t\thandle.lastState = state;\n\t\t\tfleetRuntimeEnriched = true;\n\t\t\tif (handle.error?.startsWith(\"RPC process\")) {\n\t\t\t\thandle.error = undefined;\n\t\t\t\thandle.attention.delete(\"error\");\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.recordRuntimeError(handle, message);\n\t\t\tthis.logger(`runtime ${handle.key} state unavailable for fleet card: ${message}`);\n\t\t\tstate = this.fallbackState(handle);\n\t\t}\n\t\tlet stats: RuntimeStatsSummaryDto | undefined;\n\t\ttry {\n\t\t\tconst sessionStats = await handle.client.getSessionStats();\n\t\t\tstats = { tokensTotal: sessionStats.tokens.total, cost: sessionStats.cost };\n\t\t\tif (sessionStats.contextUsage) {\n\t\t\t\thandle.lastState = { ...this.fallbackState(handle), contextUsage: sessionStats.contextUsage };\n\t\t\t\tfleetRuntimeEnriched = true;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} stats unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tlet lastAssistantText: string | undefined;\n\t\ttry {\n\t\t\tconst text = await handle.client.getLastAssistantText();\n\t\t\tlastAssistantText = text ? text.slice(0, 200) : undefined;\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} last assistant text unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tfleetRuntimeEnriched &&\n\t\t\tpreviousFleetRuntime &&\n\t\t\tthis.runtimes.get(handle.key) === handle &&\n\t\t\t!isDeepStrictEqual(previousFleetRuntime, this.describeFleetRuntime(handle))\n\t\t) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tstats,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()],\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tlastAssistantText,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"runtime-pool.js","sourceRoot":"","sources":["../../src/server/runtime-pool.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * RPC runtime pool — one `dreb --mode rpc` child process per live session.\n *\n * dreb's RPC mode is strictly one-session-per-process (switch_session repoints\n * the same process; it never multiplexes), so the pool spawns N children keyed\n * by an opaque runtime key. The telegram bridge is the in-repo precedent.\n */\n\nimport { randomBytes } from \"node:crypto\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { isDeepStrictEqual } from \"node:util\";\nimport { RpcClient, type RpcDashboardSnapshot, type RpcExitInfo } from \"@dreb/coding-agent/rpc\";\nimport {\n\ttype BackgroundAgentDto,\n\ttype FleetRuntimeSnapshotDto,\n\ttype FleetSnapshotEventDto,\n\tMAX_COMPLETED_BACKGROUND_AGENTS,\n\ttype RuntimeInfoDto,\n\ttype RuntimeStatsSummaryDto,\n\ttype SessionStateDto,\n\ttype SubagentArbitrationDto,\n} from \"../shared/protocol.js\";\n\n/** Resolve the absolute path to the dreb CLI (RpcClient defaults to a cwd-relative path). */\nexport function resolveDrebCliPath(): string {\n\tconst resolved = import.meta.resolve(\"@dreb/coding-agent\");\n\treturn join(dirname(fileURLToPath(resolved)), \"cli.js\");\n}\n\nfunction formatRpcExit(info: RpcExitInfo): string {\n\tif (info.error) return `RPC process failed: ${info.error.message}`;\n\tconst tail = info.stderrTail?.trim();\n\t// When the child aborted on its own (e.g. the stdout backpressure guard),\n\t// its stderr tail carries the actual reason — surface it instead of a bare\n\t// exit code. The tail may be multi-line; the existing UI already renders\n\t// multi-line error messages (e.g. timeouts embed full stderr).\n\treturn tail\n\t\t? `RPC process exited (code ${info.code}, signal ${info.signal}). Stderr tail: ${tail}`\n\t\t: `RPC process exited (code ${info.code}, signal ${info.signal})`;\n}\n\nexport type RuntimeEventListener = (key: string, event: Record<string, unknown>) => void;\n\n/** Listener for coalesced, synchronous fleet runtime snapshots. */\nexport type FleetSnapshotListener = (event: FleetSnapshotEventDto) => void;\n\nexport { MAX_COMPLETED_BACKGROUND_AGENTS };\n\ntype DashboardSnapshotClient = RpcClient & { getDashboardSnapshot(): Promise<RpcDashboardSnapshot> };\n\nexport interface DashboardRuntimeSnapshot {\n\tkey: string;\n\tbarrierSeq: number;\n\tsnapshot: RpcDashboardSnapshot;\n}\n\nexport interface RuntimeHandle {\n\tkey: string;\n\tcwd: string;\n\tclient: RpcClient;\n\t/** Session start time (ms epoch) — stable tiebreak for deterministic fleet ordering. */\n\tcreatedAt: number;\n\tlastActivity: number;\n\t/** Needs-attention sources, keyed so they can be cleared independently. */\n\tattention: Map<string, string>;\n\t/** Last runtime-level error, persisted server-side so fleet refreshes stay honest. */\n\terror?: string;\n\t/** Provider error currently responsible for error/attention; retry may clear only this source. */\n\tproviderError?: string;\n\t/** Last authoritative state, patched only with event-derivable fields between RPC reads. */\n\tlastState?: SessionStateDto;\n\t/** Monotonic revision for confirmed model/thinking mutations. */\n\tsettingsRevision: number;\n\t/** Resume-path fallback; events must never invent or overwrite session identity. */\n\tsessionFileFallback?: string;\n\t/** Background agents seen via events (agentId → latest info). */\n\tbackgroundAgents: Map<string, BackgroundAgentDto>;\n}\n\nexport const DEFAULT_DASHBOARD_BARRIER_TTL_MS = 5 * 60_000;\nexport const DEFAULT_DASHBOARD_BARRIER_LIMIT = 1000;\nexport const DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS = 200;\n\n/** Events that mutate a field carried by the lightweight fleet snapshot. */\nconst FLEET_SNAPSHOT_EVENT_TYPES = new Set([\n\t\"agent_start\",\n\t\"agent_end\",\n\t\"auto_compaction_start\",\n\t\"auto_compaction_end\",\n\t\"auto_retry_start\",\n\t\"auto_retry_end\",\n\t\"background_agent_start\",\n\t\"background_agent_end\",\n\t\"subagent_arbitration\",\n\t\"extension_ui_request\",\n\t\"extension_ui_response_handled\",\n\t\"message_end\",\n\t\"message_start\",\n\t\"parent_paused_for_background_agents\",\n\t\"runtime_removed\",\n\t\"session_name_changed\",\n\t\"suggest_next\",\n\t\"tasks_update\",\n]);\n\nexport interface RuntimePoolOptions {\n\tcliPath?: string;\n\t/** Extra args for every runtime (e.g. --provider). */\n\tbaseArgs?: string[];\n\t/** RpcClient factory override for tests. */\n\tclientFactory?: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tlogger?: (line: string) => void;\n\t/** Bounds unclaimed RPC snapshot ordering records. */\n\tdashboardBarrierTtlMs?: number;\n\tdashboardBarrierLimit?: number;\n\t/** Injectable clock for deterministic barrier-expiry tests. */\n\tnow?: () => number;\n\t/** Coalescing delay for event-derived fleet snapshot emissions. */\n\tfleetSnapshotDebounceMs?: number;\n}\n\ninterface DashboardBarrier {\n\tseq: number;\n\trecordedAt: number;\n}\n\nexport class RuntimePool {\n\tprivate readonly runtimes = new Map<string, RuntimeHandle>();\n\tprivate readonly listeners: RuntimeEventListener[] = [];\n\tprivate readonly fleetSnapshotListeners: FleetSnapshotListener[] = [];\n\tprivate readonly cliPath: string;\n\tprivate readonly baseArgs: string[];\n\tprivate readonly clientFactory: (options: { cliPath: string; cwd: string; args: string[] }) => RpcClient;\n\tprivate readonly logger: (line: string) => void;\n\t/**\n\t * A single lazily-spawned utility runtime used to service settings/model/\n\t * agent-type endpoints when no user session is live. Kept out of `runtimes`\n\t * (and therefore out of the fleet) so it never shows as a session card.\n\t */\n\tprivate readonly utilities = new Map<string, RuntimeHandle>();\n\tprivate readonly utilityPromises = new Map<string, Promise<RuntimeHandle>>();\n\tprivate readonly starting = new Set<RuntimeHandle>();\n\tprivate readonly startupPromises = new Set<Promise<unknown>>();\n\tprivate readonly exitedHandles = new WeakSet<RuntimeHandle>();\n\t/** Snapshot ordering records observed synchronously from RpcClient stdout. */\n\tprivate readonly dashboardBarriers = new Map<string, DashboardBarrier>();\n\tprivate readonly dashboardBarrierTtlMs: number;\n\tprivate readonly dashboardBarrierLimit: number;\n\tprivate readonly now: () => number;\n\tprivate readonly fleetSnapshotDebounceMs: number;\n\tprivate dashboardBarrierPruneTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate fleetSnapshotTimer: ReturnType<typeof setTimeout> | undefined;\n\tprivate closing = false;\n\n\tconstructor(options: RuntimePoolOptions = {}) {\n\t\tthis.cliPath = options.cliPath ?? resolveDrebCliPath();\n\t\tthis.baseArgs = options.baseArgs ?? [];\n\t\tthis.clientFactory =\n\t\t\toptions.clientFactory ?? ((o) => new RpcClient({ cliPath: o.cliPath, cwd: o.cwd, args: o.args }));\n\t\tthis.logger = options.logger ?? ((line) => console.warn(`[dashboard] ${line}`));\n\t\tthis.dashboardBarrierTtlMs = options.dashboardBarrierTtlMs ?? DEFAULT_DASHBOARD_BARRIER_TTL_MS;\n\t\tthis.dashboardBarrierLimit = options.dashboardBarrierLimit ?? DEFAULT_DASHBOARD_BARRIER_LIMIT;\n\t\tthis.now = options.now ?? Date.now;\n\t\tthis.fleetSnapshotDebounceMs = options.fleetSnapshotDebounceMs ?? DEFAULT_FLEET_SNAPSHOT_DEBOUNCE_MS;\n\t}\n\n\t/** Subscribe to events from every runtime, tagged with the runtime key. */\n\tonEvent(listener: RuntimeEventListener): () => void {\n\t\tthis.listeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.listeners.indexOf(listener);\n\t\t\tif (i !== -1) this.listeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/** Subscribe to debounced, in-memory fleet snapshots. */\n\tonFleetSnapshot(listener: FleetSnapshotListener): () => void {\n\t\tthis.fleetSnapshotListeners.push(listener);\n\t\treturn () => {\n\t\t\tconst i = this.fleetSnapshotListeners.indexOf(listener);\n\t\t\tif (i !== -1) this.fleetSnapshotListeners.splice(i, 1);\n\t\t};\n\t}\n\n\t/**\n\t * Build the fleet's live-runtime view without RPC or disk access. Map\n\t * insertion order is retained intentionally; the UI owns presentation order.\n\t */\n\tfleetSnapshot(): FleetRuntimeSnapshotDto[] {\n\t\treturn [...this.runtimes.values()].map((handle) => this.describeFleetRuntime(handle));\n\t}\n\n\tlist(): RuntimeHandle[] {\n\t\treturn [...this.runtimes.values()];\n\t}\n\n\tget(key: string): RuntimeHandle | undefined {\n\t\treturn this.runtimes.get(key);\n\t}\n\n\t/** Apply a confirmed model mutation to both the child and the pool snapshot. */\n\tasync setModel(\n\t\thandle: RuntimeHandle,\n\t\tprovider: string,\n\t\tmodelId: string,\n\t): Promise<{\n\t\tmodel: { provider: string; id: string };\n\t\tthinkingLevel: string;\n\t\tavailableThinkingLevels: string[];\n\t\tsettingsRevision: number;\n\t}> {\n\t\tconst model = await handle.client.setModel(provider, modelId);\n\t\tconst state = await handle.client.getState();\n\t\thandle.lastState = {\n\t\t\t...this.fallbackState(handle),\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t};\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn {\n\t\t\tmodel,\n\t\t\tthinkingLevel: state.thinkingLevel,\n\t\t\tavailableThinkingLevels: state.availableThinkingLevels,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t};\n\t}\n\n\t/** Apply a confirmed thinking mutation to both the child and the pool snapshot. */\n\tasync setThinkingLevel(\n\t\thandle: RuntimeHandle,\n\t\tlevel: Parameters<RpcClient[\"setThinkingLevel\"]>[0],\n\t): Promise<{ ok: true; settingsRevision: number }> {\n\t\tawait handle.client.setThinkingLevel(level);\n\t\thandle.lastState = { ...this.fallbackState(handle), thinkingLevel: level };\n\t\thandle.settingsRevision += 1;\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t\treturn { ok: true, settingsRevision: handle.settingsRevision };\n\t}\n\n\t/**\n\t * Record the EventHub sequence synchronously when the RPC snapshot marker\n\t * arrives. The marker line precedes its response on stdout, so this runs\n\t * before the RpcClient response continuation even across separate chunks.\n\t */\n\trecordDashboardBarrier(runtimeKey: string, snapshotId: string, seq: number): void {\n\t\tthis.pruneDashboardBarriers();\n\t\tthis.dashboardBarriers.set(this.dashboardBarrierKey(runtimeKey, snapshotId), { seq, recordedAt: this.now() });\n\t\tthis.pruneDashboardBarriers();\n\t}\n\n\t/**\n\t * Capture a parent-session recovery snapshot and pair it with the sequence\n\t * captured at its RPC marker. This deliberately does not infer ordering from\n\t * await: later EventHub publications naturally have higher sequence numbers.\n\t */\n\tasync snapshotDashboard(handle: RuntimeHandle): Promise<DashboardRuntimeSnapshot> {\n\t\tconst snapshot = await (handle.client as DashboardSnapshotClient).getDashboardSnapshot();\n\t\tthis.pruneDashboardBarriers();\n\t\tconst barrierKey = this.dashboardBarrierKey(handle.key, snapshot.snapshotId);\n\t\tconst barrier = this.dashboardBarriers.get(barrierKey);\n\t\tthis.dashboardBarriers.delete(barrierKey);\n\t\tthis.scheduleDashboardBarrierPrune();\n\t\tif (!barrier) {\n\t\t\tthrow new Error(`Dashboard snapshot ${snapshot.snapshotId} arrived without its ordering barrier`);\n\t\t}\n\t\t// This is an authoritative RPC baseline, so it may legitimately lower the\n\t\t// count after a fork/rewind instead of retaining an event-derived maximum.\n\t\thandle.lastState = snapshot.state;\n\t\tthis.scheduleFleetSnapshot();\n\t\treturn { key: handle.key, barrierSeq: barrier.seq, snapshot };\n\t}\n\n\tprivate dashboardBarrierKey(runtimeKey: string, snapshotId: string): string {\n\t\treturn `${runtimeKey}\\0${snapshotId}`;\n\t}\n\n\tprivate pruneDashboardBarriers(): void {\n\t\tconst oldestAllowed = this.now() - this.dashboardBarrierTtlMs;\n\t\tfor (const [snapshotId, barrier] of this.dashboardBarriers) {\n\t\t\tif (barrier.recordedAt < oldestAllowed) this.dashboardBarriers.delete(snapshotId);\n\t\t}\n\t\twhile (this.dashboardBarriers.size > this.dashboardBarrierLimit) {\n\t\t\tconst oldest = this.dashboardBarriers.keys().next().value;\n\t\t\tif (oldest === undefined) break;\n\t\t\tthis.dashboardBarriers.delete(oldest);\n\t\t}\n\t\tthis.scheduleDashboardBarrierPrune();\n\t}\n\n\tprivate scheduleDashboardBarrierPrune(): void {\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tlet oldest: DashboardBarrier | undefined;\n\t\tfor (const barrier of this.dashboardBarriers.values()) {\n\t\t\tif (!oldest || barrier.recordedAt < oldest.recordedAt) oldest = barrier;\n\t\t}\n\t\tif (!oldest) return;\n\t\tconst delay = Math.max(1, oldest.recordedAt + this.dashboardBarrierTtlMs - this.now() + 1);\n\t\tthis.dashboardBarrierPruneTimer = setTimeout(() => {\n\t\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\t\tthis.pruneDashboardBarriers();\n\t\t}, delay);\n\t\tthis.dashboardBarrierPruneTimer.unref?.();\n\t}\n\n\tprivate scheduleFleetSnapshot(): void {\n\t\tif (this.closing) return;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = setTimeout(() => {\n\t\t\tthis.fleetSnapshotTimer = undefined;\n\t\t\tif (this.closing) return;\n\t\t\tconst event: FleetSnapshotEventDto = { type: \"fleet_snapshot\", runtimes: this.fleetSnapshot() };\n\t\t\tfor (const listener of this.fleetSnapshotListeners) {\n\t\t\t\ttry {\n\t\t\t\t\tlistener(event);\n\t\t\t\t} catch {\n\t\t\t\t\t// An SSE bridge subscriber must not break the pool's event loop.\n\t\t\t\t}\n\t\t\t}\n\t\t}, this.fleetSnapshotDebounceMs);\n\t\tthis.fleetSnapshotTimer.unref?.();\n\t}\n\n\t/** Spawn a new runtime in `cwd`, optionally opening an existing session file. */\n\tasync create(cwd: string, sessionPath?: string): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst key = randomBytes(6).toString(\"hex\");\n\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\tif (sessionPath) args.push(\"--session\", sessionPath);\n\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\tconst handle: RuntimeHandle = {\n\t\t\tkey,\n\t\t\tcwd,\n\t\t\tclient,\n\t\t\tcreatedAt: this.now(),\n\t\t\tlastActivity: this.now(),\n\t\t\tattention: new Map(),\n\t\t\tsettingsRevision: 0,\n\t\t\tsessionFileFallback: sessionPath,\n\t\t\tbackgroundAgents: new Map(),\n\t\t};\n\t\tclient.onEvent((event) => this.handleEvent(handle, event as unknown as Record<string, unknown>));\n\t\tclient.onExit((info) => this.handleRuntimeExit(handle, info));\n\n\t\tconst startup = this.startSessionRuntime(handle);\n\t\tthis.startupPromises.add(startup);\n\t\ttry {\n\t\t\treturn await startup;\n\t\t} finally {\n\t\t\tthis.startupPromises.delete(startup);\n\t\t}\n\t}\n\n\tprivate async startSessionRuntime(handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tawait this.seedBackgroundAgents(handle);\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.runtimes.set(handle.key, handle);\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\t/** Stop a runtime and remove it from the pool. */\n\tasync stop(key: string): Promise<boolean> {\n\t\tconst handle = this.runtimes.get(key);\n\t\tif (!handle) return false;\n\t\tthis.handleEvent(handle, { type: \"runtime_removed\" });\n\t\tthis.runtimes.delete(key);\n\t\tthis.scheduleFleetSnapshot();\n\t\tawait handle.client.stop();\n\t\treturn true;\n\t}\n\n\t/**\n\t * Return any live runtime suitable for process-global settings work, spawning\n\t * a hidden utility runtime (in the home directory) if no user session exists.\n\t * This is what lets the settings page — models, agent types, defaults — work\n\t * with zero sessions open, instead of 503-ing.\n\t */\n\tasync ensureUtilityRuntime(cwd = homedir()): Promise<RuntimeHandle> {\n\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\tconst existing = this.utilities.get(cwd);\n\t\tif (existing) return existing;\n\t\tlet promise = this.utilityPromises.get(cwd);\n\t\tif (!promise) {\n\t\t\tconst args = [\"--ui\", \"dashboard\", ...this.baseArgs];\n\t\t\tconst client = this.clientFactory({ cliPath: this.cliPath, cwd, args });\n\t\t\tconst handle: RuntimeHandle = {\n\t\t\t\tkey: `utility:${cwd}`,\n\t\t\t\tcwd,\n\t\t\t\tclient,\n\t\t\t\tcreatedAt: this.now(),\n\t\t\t\tlastActivity: this.now(),\n\t\t\t\tattention: new Map(),\n\t\t\t\tsettingsRevision: 0,\n\t\t\t\tbackgroundAgents: new Map(),\n\t\t\t};\n\t\t\tconst startup = this.startUtilityRuntime(cwd, handle);\n\t\t\tthis.startupPromises.add(startup);\n\t\t\tpromise = startup\n\t\t\t\t.catch((err) => {\n\t\t\t\t\t// Allow a retry on the next request instead of caching the failure.\n\t\t\t\t\tthis.utilityPromises.delete(cwd);\n\t\t\t\t\tthrow err;\n\t\t\t\t})\n\t\t\t\t.finally(() => {\n\t\t\t\t\tthis.startupPromises.delete(startup);\n\t\t\t\t});\n\t\t\tthis.utilityPromises.set(cwd, promise);\n\t\t}\n\t\treturn promise;\n\t}\n\n\tprivate async startUtilityRuntime(cwd: string, handle: RuntimeHandle): Promise<RuntimeHandle> {\n\t\tthis.starting.add(handle);\n\t\ttry {\n\t\t\tif (this.closing) throw new Error(\"Runtime pool is closing\");\n\t\t\tawait handle.client.start();\n\t\t\tif (this.closing) {\n\t\t\t\tawait handle.client.stop();\n\t\t\t\tthrow new Error(\"Runtime pool is closing\");\n\t\t\t}\n\t\t\tthis.utilities.set(cwd, handle);\n\t\t\treturn handle;\n\t\t} finally {\n\t\t\tthis.starting.delete(handle);\n\t\t}\n\t}\n\n\tasync stopAll(): Promise<void> {\n\t\tthis.closing = true;\n\t\tif (this.dashboardBarrierPruneTimer) clearTimeout(this.dashboardBarrierPruneTimer);\n\t\tthis.dashboardBarrierPruneTimer = undefined;\n\t\tif (this.fleetSnapshotTimer) clearTimeout(this.fleetSnapshotTimer);\n\t\tthis.fleetSnapshotTimer = undefined;\n\t\tthis.fleetSnapshotListeners.length = 0;\n\t\tthis.dashboardBarriers.clear();\n\t\tconst handles = new Set<RuntimeHandle>([\n\t\t\t...this.runtimes.values(),\n\t\t\t...this.utilities.values(),\n\t\t\t...this.starting.values(),\n\t\t]);\n\t\tconst startupPromises = new Set<Promise<unknown>>([...this.startupPromises, ...this.utilityPromises.values()]);\n\t\tthis.runtimes.clear();\n\t\tthis.utilities.clear();\n\t\tthis.utilityPromises.clear();\n\t\tawait Promise.allSettled([...handles].map((handle) => handle.client.stop()));\n\t\tawait Promise.allSettled([...startupPromises]);\n\t}\n\n\tprivate handleRuntimeExit(handle: RuntimeHandle, info: RpcExitInfo): void {\n\t\tif (this.closing || this.exitedHandles.has(handle) || !this.isLiveHandle(handle)) return;\n\t\tthis.exitedHandles.add(handle);\n\t\tconst message = formatRpcExit(info);\n\t\tthis.recordRuntimeError(handle, message);\n\t\tthis.logger(`runtime ${handle.key} ${message}`);\n\t\tthis.handleEvent(handle, { type: \"agent_end\", messages: [], aborted: true, errorMessage: message });\n\t}\n\n\tprivate isLiveHandle(handle: RuntimeHandle): boolean {\n\t\treturn (\n\t\t\tthis.runtimes.get(handle.key) === handle ||\n\t\t\tthis.utilities.get(handle.cwd) === handle ||\n\t\t\tthis.starting.has(handle)\n\t\t);\n\t}\n\n\tprivate handleEvent(handle: RuntimeHandle, event: Record<string, unknown>): void {\n\t\tconst type = event.type as string;\n\t\tif (type !== \"dashboard_snapshot_barrier\") {\n\t\t\thandle.lastActivity = this.now();\n\t\t\tthis.updateStateFromEvent(handle, event, type);\n\t\t}\n\n\t\t// Track needs-attention sources: extension UI requests, parent\n\t\t// paused, error states.\n\t\tif (type === \"extension_ui_request\") {\n\t\t\tconst method = event.method as string;\n\t\t\tif (\n\t\t\t\tmethod === \"select\" ||\n\t\t\t\tmethod === \"confirm\" ||\n\t\t\t\tmethod === \"input\" ||\n\t\t\t\tmethod === \"editor\" ||\n\t\t\t\tmethod === \"ask\"\n\t\t\t) {\n\t\t\t\thandle.attention.set(`ui:${event.id}`, `extension ${method} awaiting response`);\n\t\t\t}\n\t\t}\n\t\tif (type === \"extension_ui_response_handled\") {\n\t\t\thandle.attention.delete(`ui:${event.id}`);\n\t\t}\n\t\tif (type === \"agent_start\") {\n\t\t\t// A new turn clears prior UI-request attention (requests were resolved or timed out).\n\t\t\tfor (const k of [...handle.attention.keys()]) {\n\t\t\t\tif (k.startsWith(\"ui:\")) handle.attention.delete(k);\n\t\t\t}\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\thandle.attention.delete(\"suggest\");\n\t\t\thandle.attention.delete(\"error\");\n\t\t\thandle.error = undefined;\n\t\t\thandle.providerError = undefined;\n\t\t}\n\t\tif (type === \"suggest_next\") {\n\t\t\t// suggest_next as the ending action = \"your move\": mark needs-attention\n\t\t\t// so the fleet card doesn't read idle. Cleared on the next agent_start.\n\t\t\thandle.attention.set(\"suggest\", \"suggested command awaiting\");\n\t\t}\n\t\tif (type === \"parent_paused_for_background_agents\") {\n\t\t\thandle.attention.set(\"paused\", `paused — ${event.runningAgentCount} background agents running`);\n\t\t}\n\t\tif (type === \"agent_end\") {\n\t\t\thandle.attention.delete(\"paused\");\n\t\t\tif (event.errorMessage) this.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\t\tif (type === \"message_end\") {\n\t\t\tconst message = event.message;\n\t\t\tif (message && typeof message === \"object\" && !Array.isArray(message)) {\n\t\t\t\tconst assistant = message as Record<string, unknown>;\n\t\t\t\tif (assistant.role === \"assistant\" && assistant.stopReason === \"error\") {\n\t\t\t\t\tconst rawError = assistant.errorMessage;\n\t\t\t\t\tconst error = typeof rawError === \"string\" && rawError.trim().length > 0 ? rawError : \"Unknown error\";\n\t\t\t\t\tthis.recordProviderError(handle, error);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (type === \"auto_retry_start\") this.clearProviderError(handle);\n\t\tif (type === \"auto_compaction_start\" && event.reason === \"overflow\") this.clearProviderError(handle);\n\t\tif (type === \"auto_retry_end\" && event.success === false && event.finalError) {\n\t\t\tthis.recordProviderError(handle, String(event.finalError));\n\t\t} else if (type === \"auto_retry_end\" && event.success === true) {\n\t\t\tthis.clearProviderError(handle);\n\t\t}\n\t\tif (type === \"auto_compaction_end\" && event.errorMessage) {\n\t\t\tthis.recordRuntimeError(handle, String(event.errorMessage));\n\t\t}\n\n\t\t// Track background agents from lifecycle events.\n\t\tif (type === \"background_agent_start\") {\n\t\t\thandle.backgroundAgents.set(event.agentId as string, {\n\t\t\t\tagentId: event.agentId as string,\n\t\t\t\tagentType: event.agentType as string,\n\t\t\t\ttaskSummary: event.taskSummary as string,\n\t\t\t\tstartedAt: new Date().toISOString(),\n\t\t\t\tstatus: \"running\",\n\t\t\t\tsessionDir: event.sessionDir as string | undefined,\n\t\t\t});\n\t\t}\n\t\tif (type === \"subagent_arbitration\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\tconst record: SubagentArbitrationDto = {\n\t\t\t\t\tstatus: event.status as SubagentArbitrationDto[\"status\"],\n\t\t\t\t\tproposed: event.proposed as SubagentArbitrationDto[\"proposed\"],\n\t\t\t\t\tfinal: (event.final as SubagentArbitrationDto[\"final\"]) ?? null,\n\t\t\t\t\tchanged: (event.changed as SubagentArbitrationDto[\"changed\"]) ?? [],\n\t\t\t\t\tstep: event.step as number | undefined,\n\t\t\t\t\terrorCode: event.errorCode as string | undefined,\n\t\t\t\t\terrorMessage: event.errorMessage as string | undefined,\n\t\t\t\t};\n\t\t\t\texisting.arbitrations = [...(existing.arbitrations ?? []), record];\n\t\t\t\tif (record.status === \"success\" && record.final) existing.agentType = record.final.agent;\n\t\t\t}\n\t\t}\n\t\tif (type === \"background_agent_end\") {\n\t\t\tconst existing = handle.backgroundAgents.get(event.agentId as string);\n\t\t\tif (existing) {\n\t\t\t\texisting.status = event.success ? \"completed\" : \"failed\";\n\t\t\t\texisting.sessionFile = (event.sessionFile as string | undefined) ?? existing.sessionFile;\n\t\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t\t}\n\t\t}\n\n\t\tfor (const listener of this.listeners) {\n\t\t\ttry {\n\t\t\t\tlistener(handle.key, event);\n\t\t\t} catch {\n\t\t\t\t// A broken SSE subscriber must not break event distribution.\n\t\t\t}\n\t\t}\n\t\tif (this.runtimes.get(handle.key) === handle && FLEET_SNAPSHOT_EVENT_TYPES.has(type)) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t}\n\n\t/**\n\t * Events intentionally patch only fields they can prove. Session identity,\n\t * session file, configuration, and context usage remain from the last RPC\n\t * baseline (or the stable creation fallback) until a later reconciliation.\n\t */\n\tprivate updateStateFromEvent(handle: RuntimeHandle, event: Record<string, unknown>, type: string): void {\n\t\tconst state = this.fallbackState(handle);\n\t\tswitch (type) {\n\t\t\tcase \"agent_start\": {\n\t\t\t\tconst model = event.model;\n\t\t\t\tif (\n\t\t\t\t\tmodel &&\n\t\t\t\t\ttypeof model === \"object\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).provider === \"string\" &&\n\t\t\t\t\ttypeof (model as Record<string, unknown>).id === \"string\"\n\t\t\t\t) {\n\t\t\t\t\tconst nextModel = model as { provider: string; id: string };\n\t\t\t\t\tstate.model =\n\t\t\t\t\t\tstate.model?.provider === nextModel.provider && state.model.id === nextModel.id\n\t\t\t\t\t\t\t? { ...state.model, ...nextModel }\n\t\t\t\t\t\t\t: nextModel;\n\t\t\t\t}\n\t\t\t\tstate.isStreaming = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"agent_end\":\n\t\t\t\tstate.isStreaming = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_start\":\n\t\t\t\tstate.isCompacting = true;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_compaction_end\":\n\t\t\t\tstate.isCompacting = false;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_start\":\n\t\t\t\tstate.isRetrying = true;\n\t\t\t\tstate.retryAttempt = typeof event.attempt === \"number\" ? event.attempt : state.retryAttempt;\n\t\t\t\tbreak;\n\t\t\tcase \"auto_retry_end\":\n\t\t\t\tstate.isRetrying = false;\n\t\t\t\tstate.retryAttempt = 0;\n\t\t\t\tbreak;\n\t\t\tcase \"tasks_update\":\n\t\t\t\tif (Array.isArray(event.tasks)) state.tasks = [...event.tasks] as SessionStateDto[\"tasks\"];\n\t\t\t\tbreak;\n\t\t\tcase \"session_name_changed\":\n\t\t\t\tif (typeof event.name === \"string\") state.sessionName = event.name;\n\t\t\t\tbreak;\n\t\t\tcase \"message_start\":\n\t\t\t\tstate.messageCount += 1;\n\t\t\t\tbreak;\n\t\t}\n\t\thandle.lastState = state;\n\t}\n\n\tprivate recordRuntimeError(handle: RuntimeHandle, message: string): void {\n\t\thandle.error = message;\n\t\thandle.attention.set(\"error\", message);\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate recordProviderError(handle: RuntimeHandle, message: string): void {\n\t\thandle.providerError = message;\n\t\tthis.recordRuntimeError(handle, message);\n\t}\n\n\tprivate clearProviderError(handle: RuntimeHandle): void {\n\t\tconst providerError = handle.providerError;\n\t\tif (providerError === undefined) return;\n\t\thandle.providerError = undefined;\n\t\tif (handle.error === providerError) handle.error = undefined;\n\t\tif (handle.attention.get(\"error\") === providerError) handle.attention.delete(\"error\");\n\t\tif (this.runtimes.get(handle.key) === handle) this.scheduleFleetSnapshot();\n\t}\n\n\tprivate pruneCompletedBackgroundAgents(handle: RuntimeHandle): void {\n\t\tconst evictable = [...handle.backgroundAgents.values()]\n\t\t\t.map((agent, index) => {\n\t\t\t\tconst startedAtMs = Date.parse(agent.startedAt);\n\t\t\t\treturn { agent, index, startedAtMs: Number.isFinite(startedAtMs) ? startedAtMs : 0 };\n\t\t\t})\n\t\t\t.filter(({ agent }) => agent.status !== \"running\")\n\t\t\t.sort((a, b) => a.startedAtMs - b.startedAtMs || a.index - b.index);\n\t\tconst excess = evictable.length - MAX_COMPLETED_BACKGROUND_AGENTS;\n\t\tif (excess <= 0) return;\n\t\tfor (const { agent } of evictable.slice(0, excess)) {\n\t\t\thandle.backgroundAgents.delete(agent.agentId);\n\t\t}\n\t}\n\n\tprivate fallbackState(handle: RuntimeHandle): SessionStateDto {\n\t\tconst previous = handle.lastState;\n\t\treturn {\n\t\t\t...previous,\n\t\t\tsessionId: previous?.sessionId ?? handle.key,\n\t\t\ttasks: previous?.tasks ? [...previous.tasks] : [],\n\t\t\tthinkingLevel: previous?.thinkingLevel ?? \"off\",\n\t\t\tavailableThinkingLevels: previous?.availableThinkingLevels ? [...previous.availableThinkingLevels] : [\"off\"],\n\t\t\tisStreaming: previous?.isStreaming ?? false,\n\t\t\tisRetrying: previous?.isRetrying ?? false,\n\t\t\tretryAttempt: previous?.retryAttempt ?? 0,\n\t\t\tisCompacting: previous?.isCompacting ?? false,\n\t\t\tsteeringMode: previous?.steeringMode ?? \"all\",\n\t\t\tfollowUpMode: previous?.followUpMode ?? \"all\",\n\t\t\tsessionFile: previous?.sessionFile ?? handle.sessionFileFallback,\n\t\t\tautoCompactionEnabled: previous?.autoCompactionEnabled ?? false,\n\t\t\tmessageCount: previous?.messageCount ?? 0,\n\t\t\tpendingMessageCount: previous?.pendingMessageCount ?? 0,\n\t\t};\n\t}\n\n\tprivate describeFleetRuntime(handle: RuntimeHandle): FleetRuntimeSnapshotDto {\n\t\tconst state = this.fallbackState(handle);\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()].map((agent) => ({ ...agent })),\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n\n\tprivate async seedBackgroundAgents(handle: RuntimeHandle): Promise<void> {\n\t\ttry {\n\t\t\tconst agents = (await handle.client.listBackgroundAgents()) as unknown as BackgroundAgentDto[];\n\t\t\tfor (const agent of agents) {\n\t\t\t\thandle.backgroundAgents.set(agent.agentId, agent);\n\t\t\t}\n\t\t\tthis.pruneCompletedBackgroundAgents(handle);\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} background-agent registry unavailable: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** Snapshot a runtime for the fleet endpoint. */\n\tasync describe(handle: RuntimeHandle): Promise<RuntimeInfoDto> {\n\t\tconst previousFleetRuntime =\n\t\t\tthis.runtimes.get(handle.key) === handle ? this.describeFleetRuntime(handle) : undefined;\n\t\tlet fleetRuntimeEnriched = false;\n\t\tlet state: SessionStateDto;\n\t\ttry {\n\t\t\tconst authoritative = (await handle.client.getState()) as unknown as SessionStateDto;\n\t\t\tconst fallback = this.fallbackState(handle);\n\t\t\tstate = {\n\t\t\t\t...fallback,\n\t\t\t\t...authoritative,\n\t\t\t\tsessionId: authoritative.sessionId ?? fallback.sessionId,\n\t\t\t\tsessionFile: authoritative.sessionFile ?? fallback.sessionFile,\n\t\t\t\ttasks: authoritative.tasks ?? fallback.tasks,\n\t\t\t};\n\t\t\thandle.lastState = state;\n\t\t\tfleetRuntimeEnriched = true;\n\t\t\tif (handle.error?.startsWith(\"RPC process\")) {\n\t\t\t\thandle.error = undefined;\n\t\t\t\thandle.attention.delete(\"error\");\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.recordRuntimeError(handle, message);\n\t\t\tthis.logger(`runtime ${handle.key} state unavailable for fleet card: ${message}`);\n\t\t\tstate = this.fallbackState(handle);\n\t\t}\n\t\tlet stats: RuntimeStatsSummaryDto | undefined;\n\t\ttry {\n\t\t\tconst sessionStats = await handle.client.getSessionStats();\n\t\t\tstats = { tokensTotal: sessionStats.tokens.total, cost: sessionStats.cost };\n\t\t\tif (sessionStats.contextUsage) {\n\t\t\t\thandle.lastState = { ...this.fallbackState(handle), contextUsage: sessionStats.contextUsage };\n\t\t\t\tfleetRuntimeEnriched = true;\n\t\t\t}\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} stats unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tlet lastAssistantText: string | undefined;\n\t\ttry {\n\t\t\tconst text = await handle.client.getLastAssistantText();\n\t\t\tlastAssistantText = text ? text.slice(0, 200) : undefined;\n\t\t} catch (err) {\n\t\t\tthis.logger(\n\t\t\t\t`runtime ${handle.key} last assistant text unavailable for fleet card: ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tfleetRuntimeEnriched &&\n\t\t\tpreviousFleetRuntime &&\n\t\t\tthis.runtimes.get(handle.key) === handle &&\n\t\t\t!isDeepStrictEqual(previousFleetRuntime, this.describeFleetRuntime(handle))\n\t\t) {\n\t\t\tthis.scheduleFleetSnapshot();\n\t\t}\n\t\treturn {\n\t\t\tkey: handle.key,\n\t\t\tcwd: handle.cwd,\n\t\t\tstate,\n\t\t\tsettingsRevision: handle.settingsRevision,\n\t\t\tstats,\n\t\t\tbackgroundAgents: [...handle.backgroundAgents.values()],\n\t\t\tneedsAttention: handle.attention.size > 0,\n\t\t\terror: handle.error,\n\t\t\tlastAssistantText,\n\t\t\tcreatedAt: new Date(handle.createdAt).toISOString(),\n\t\t\tlastActivity: new Date(handle.lastActivity).toISOString(),\n\t\t};\n\t}\n}\n"]}
package/dist/static/sw.js CHANGED
@@ -14,7 +14,7 @@
14
14
  */
15
15
 
16
16
  // Replaced at build time; see vite.config.ts generateBundle hook.
17
- const SW_CACHE_VERSION = "2.64.0";
17
+ const SW_CACHE_VERSION = "2.64.1";
18
18
  const SHELL_CACHE = `dreb-dashboard-shell-v${SW_CACHE_VERSION}`;
19
19
 
20
20
  // Shell assets (HTML, JS, CSS) get a network-first strategy. The dashboard
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dreb/dashboard",
3
- "version": "2.64.0",
3
+ "version": "2.64.1",
4
4
  "description": "Web dashboard for dreb — fleet overview, chat parity, subagent observability",
5
5
  "license": "MIT",
6
6
  "type": "module",