@narumitw/pi-subagents 3.3.3 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +73 -24
  2. package/dist/child-communication-bridge.ts +3 -2
  3. package/dist/child-communication-bridge.ts.map +1 -1
  4. package/dist/child-readiness-probe.ts +114 -17
  5. package/dist/child-readiness-probe.ts.map +2 -2
  6. package/dist/chunks/{chunk-FY5HIU6Y.ts → chunk-5OXDVXXO.ts} +1 -1
  7. package/dist/chunks/{chunk-FY5HIU6Y.ts.map → chunk-5OXDVXXO.ts.map} +1 -1
  8. package/dist/chunks/chunk-B3RWNGDX.ts +192 -0
  9. package/dist/chunks/chunk-B3RWNGDX.ts.map +7 -0
  10. package/dist/chunks/{chunk-ZOAFWLDJ.ts → chunk-PRIDTAJL.ts} +4 -16
  11. package/dist/chunks/chunk-PRIDTAJL.ts.map +7 -0
  12. package/dist/chunks/{chunk-YMVSJ5GE.ts → chunk-YV2P6XJX.ts} +46 -17
  13. package/dist/chunks/chunk-YV2P6XJX.ts.map +7 -0
  14. package/dist/chunks/{menu-KAIUEWL7.ts → menu-2UH4ICLL.ts} +74 -3
  15. package/dist/chunks/menu-2UH4ICLL.ts.map +7 -0
  16. package/dist/index.ts +553 -292
  17. package/dist/index.ts.map +3 -3
  18. package/docs/attachments.md +9 -3
  19. package/docs/design-principles.md +3 -1
  20. package/docs/tools.md +15 -1
  21. package/package.json +2 -2
  22. package/src/broker-credentials.ts +44 -13
  23. package/src/child-communication-tools.ts +2 -19
  24. package/src/child-readiness-probe.ts +144 -18
  25. package/src/child-readiness.ts +118 -0
  26. package/src/menu.ts +82 -3
  27. package/src/message-broker.ts +23 -10
  28. package/src/process.ts +59 -167
  29. package/src/resource-attachments.ts +1 -3
  30. package/src/rpc-line-decoder.ts +61 -0
  31. package/src/runtime.ts +21 -9
  32. package/src/settings.ts +2 -2
  33. package/src/subagents.ts +110 -18
  34. package/src/tools.ts +83 -37
  35. package/src/types.ts +1 -0
  36. package/src/widget-renderer.ts +119 -0
  37. package/src/widget.ts +245 -121
  38. package/dist/chunks/chunk-3FCHXUKZ.ts +0 -98
  39. package/dist/chunks/chunk-3FCHXUKZ.ts.map +0 -7
  40. package/dist/chunks/chunk-YMVSJ5GE.ts.map +0 -7
  41. package/dist/chunks/chunk-ZOAFWLDJ.ts.map +0 -7
  42. package/dist/chunks/menu-KAIUEWL7.ts.map +0 -7
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/message-broker.ts", "../../src/broker-credentials.ts"],
4
- "sourcesContent": ["import { randomBytes, randomUUID } from \"node:crypto\";\nimport net, { type AddressInfo, type Server, type Socket } from \"node:net\";\nimport type { BrokerCredentials } from \"./types.js\";\n\nexport const BROKER_HOST = \"127.0.0.1\" as const;\nexport const MAX_MESSAGE_BYTES = 48 * 1024;\nexport const MAX_MESSAGE_LINES = 1_992;\nexport const MAX_FRAME_BYTES = 384 * 1024;\nexport const MAX_ERROR_BYTES = 8 * 1024;\nexport const MAX_OUTSTANDING_REQUESTS = 4;\nexport const MAX_IDENTIFIER_LENGTH = 128;\n\nconst MAX_CONNECTIONS = 32;\nconst REQUEST_FRAME_TIMEOUT_MS = 2_000;\nconst MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_RETAINED_CONSUMED_REQUESTS = 4;\nconst CHILD_WAIT_INTERRUPTED_ERROR =\n \"Subagent wait was interrupted by an incoming main-agent request. The original request remains active.\";\n\nexport type BrokerRequestOrigin = \"main\" | \"child\";\n\nexport interface BrokerInboundMessage {\n kind: \"request\" | \"response\";\n requestId: string;\n jobId: string;\n message: string;\n}\n\nexport interface BrokerSendAcknowledgement {\n requestId: string;\n accepted: boolean;\n duplicate: boolean;\n}\n\nexport interface MessageBrokerOptions {\n onMessage(message: BrokerInboundMessage): void;\n createServer?: (listener: (socket: Socket) => void) => Server;\n now?: () => number;\n requestFrameTimeoutMs?: number;\n}\n\ninterface JobRecord {\n jobId: string;\n generation: number;\n token: string;\n}\n\ninterface RequestWaiter {\n socket: Socket;\n timer?: NodeJS.Timeout;\n}\n\ninterface RequestRecord {\n requestId: string;\n jobId: string;\n generation: number;\n origin: BrokerRequestOrigin;\n expectedResponder: BrokerRequestOrigin;\n message: string;\n createdAt: number;\n response?: string;\n consumedAt?: number;\n deliveryQueued?: boolean;\n waiter?: RequestWaiter;\n}\n\ntype BrokerRequest =\n | {\n type: \"send\";\n token: string;\n recipient?: string;\n requestId?: string;\n message: string;\n }\n | { type: \"wait\"; token: string; requestId: string; timeoutMs?: number };\n\n/** Session-scoped authenticated loopback transport for bidirectional requests and responses. */\nexport class MessageBroker {\n private server?: Server;\n private starting?: Promise<void>;\n private address?: { host: typeof BROKER_HOST; port: number };\n private failure?: string;\n private generation = 0;\n private readonly sockets = new Set<Socket>();\n private readonly jobsByToken = new Map<string, JobRecord>();\n private readonly tokenByJob = new Map<string, string>();\n private readonly requests = new Map<string, RequestRecord>();\n private readonly inboundMessageListeners = new Set<() => void>();\n private pendingInboundResponse = false;\n private readonly createServer: (listener: (socket: Socket) => void) => Server;\n private readonly now: () => number;\n private readonly requestFrameTimeoutMs: number;\n\n constructor(private readonly options: MessageBrokerOptions) {\n this.createServer = options.createServer ?? ((listener) => net.createServer(listener));\n this.now = options.now ?? Date.now;\n this.requestFrameTimeoutMs = options.requestFrameTimeoutMs ?? REQUEST_FRAME_TIMEOUT_MS;\n if (!Number.isFinite(this.requestFrameTimeoutMs) || this.requestFrameTimeoutMs <= 0) {\n throw new Error(\"Subagent broker frame timeout must be positive.\");\n }\n }\n\n async start(): Promise<void> {\n if (this.server && this.address && !this.failure) return;\n if (this.starting) return this.starting;\n const ownerGeneration = ++this.generation;\n this.failure = undefined;\n this.starting = new Promise<void>((resolve, reject) => {\n const server = this.createServer((socket) => this.accept(socket));\n server.maxConnections = MAX_CONNECTIONS;\n const onStartError = (error: Error) => {\n server.close(() => undefined);\n reject(error);\n };\n server.once(\"error\", onStartError);\n server.listen({ host: BROKER_HOST, port: 0 }, () => {\n server.off(\"error\", onStartError);\n if (ownerGeneration !== this.generation) {\n server.close(() => undefined);\n reject(new Error(\"Subagent message broker start was superseded.\"));\n return;\n }\n const address = server.address();\n if (!isLoopbackAddress(address)) {\n server.close(() => undefined);\n reject(new Error(\"Subagent message broker did not bind to loopback.\"));\n return;\n }\n this.server = server;\n this.address = { host: BROKER_HOST, port: address.port };\n server.on(\"error\", (error) => this.fail(error));\n server.unref();\n resolve();\n });\n })\n .catch((error) => {\n const message = truncateError(error instanceof Error ? error.message : String(error));\n this.failure = message;\n throw new Error(`Subagent message broker failed to start: ${message}`);\n })\n .finally(() => {\n this.starting = undefined;\n });\n return this.starting;\n }\n\n assertReady(): void {\n if (this.server && this.address && !this.failure) return;\n throw new Error(\n this.failure\n ? `Subagent messaging is unavailable: ${this.failure}`\n : \"Subagent messaging is unavailable because the session broker is not ready.\",\n );\n }\n\n issueCredentials(input: { jobId: string; generation: number }): BrokerCredentials {\n this.assertReady();\n if (this.tokenByJob.has(input.jobId)) {\n throw new Error(`Subagent messaging credentials already exist for ${input.jobId}.`);\n }\n const token = randomBytes(32).toString(\"hex\");\n const record: JobRecord = { ...input, token };\n this.jobsByToken.set(token, record);\n this.tokenByJob.set(input.jobId, token);\n return { host: BROKER_HOST, port: this.address?.port ?? 0, token };\n }\n\n createMainRequest(jobId: string, message: string): BrokerSendAcknowledgement {\n this.assertReady();\n const job = this.requireJob(jobId);\n return this.createRequest(job, \"main\", message);\n }\n\n replyFromMain(requestId: string, message: string): BrokerSendAcknowledgement {\n this.assertReady();\n return this.acceptResponse(\"main\", undefined, requestId, message);\n }\n\n rollbackMainRequest(requestId: string): void {\n const request = this.requests.get(requestId);\n if (request?.origin === \"main\" && request.response === undefined) {\n this.clearWaiter(request);\n this.requests.delete(requestId);\n }\n }\n\n revokeJob(jobId: string, reason = \"Subagent job is no longer active.\"): void {\n const token = this.tokenByJob.get(jobId);\n if (token) {\n this.tokenByJob.delete(jobId);\n this.jobsByToken.delete(token);\n }\n for (const request of [...this.requests.values()]) {\n if (request.jobId !== jobId) continue;\n if (request.waiter) this.respondError(request.waiter.socket, reason);\n this.clearWaiter(request);\n this.requests.delete(request.requestId);\n }\n }\n\n hasPendingMainRequest(): boolean {\n return [...this.requests.values()].some((request) => request.origin === \"child\" && request.response === undefined);\n }\n\n takePendingInboundResponse(): boolean {\n const pending = this.pendingInboundResponse;\n this.pendingInboundResponse = false;\n return pending;\n }\n\n markMainRequestQueued(requestId: string): boolean {\n const request = this.requests.get(requestId);\n if (request?.origin !== \"main\") {\n throw new Error(\"Unknown or expired main-agent subagent request.\");\n }\n request.deliveryQueued = true;\n return request.response === undefined;\n }\n\n interruptChildWaits(jobId: string): number {\n let interrupted = 0;\n for (const request of this.requests.values()) {\n if (request.jobId !== jobId || request.origin !== \"child\" || !request.waiter) continue;\n const socket = request.waiter.socket;\n this.clearWaiter(request);\n this.respondError(socket, CHILD_WAIT_INTERRUPTED_ERROR);\n interrupted++;\n }\n return interrupted;\n }\n\n subscribeInboundMessage(listener: () => void): () => void {\n this.inboundMessageListeners.add(listener);\n if (this.hasPendingMainRequest()) listener();\n return () => this.inboundMessageListeners.delete(listener);\n }\n\n async shutdown(): Promise<void> {\n ++this.generation;\n const starting = this.starting;\n if (starting) await starting.catch(() => undefined);\n for (const jobId of [...this.tokenByJob.keys()]) {\n this.revokeJob(jobId, \"Subagent session shut down.\");\n }\n this.requests.clear();\n this.inboundMessageListeners.clear();\n this.pendingInboundResponse = false;\n for (const socket of this.sockets) socket.destroy();\n this.sockets.clear();\n const server = this.server;\n this.server = undefined;\n this.address = undefined;\n this.failure = undefined;\n if (!server?.listening) return;\n await new Promise<void>((resolve) => server.close(() => resolve()));\n }\n\n private requireJob(jobId: string): JobRecord {\n const token = this.tokenByJob.get(jobId);\n const job = token ? this.jobsByToken.get(token) : undefined;\n if (!job) throw new Error(\"Unknown or inactive subagent job.\");\n return job;\n }\n\n private hasQueuedRequestForChild(jobId: string): boolean {\n return [...this.requests.values()].some(\n (request) =>\n request.jobId === jobId &&\n request.origin === \"main\" &&\n request.deliveryQueued === true &&\n request.response === undefined,\n );\n }\n\n private createRequest(job: JobRecord, origin: BrokerRequestOrigin, message: string): BrokerSendAcknowledgement {\n validateMessage(message, \"Subagent request\");\n const outstanding = [...this.requests.values()].filter(\n (request) => request.jobId === job.jobId && request.consumedAt === undefined,\n ).length;\n if (outstanding >= MAX_OUTSTANDING_REQUESTS) {\n throw new Error(`Subagent job may have at most ${MAX_OUTSTANDING_REQUESTS} outstanding requests.`);\n }\n const request: RequestRecord = {\n requestId: `req_${randomUUID()}`,\n jobId: job.jobId,\n generation: job.generation,\n origin,\n expectedResponder: origin === \"main\" ? \"child\" : \"main\",\n message,\n createdAt: this.now(),\n };\n this.requests.set(request.requestId, request);\n if (origin === \"child\") {\n try {\n this.deliverInbound({\n kind: \"request\",\n requestId: request.requestId,\n jobId: request.jobId,\n message: request.message,\n });\n } catch (error) {\n this.requests.delete(request.requestId);\n throw error;\n }\n }\n return { requestId: request.requestId, accepted: true, duplicate: false };\n }\n\n private acceptResponse(\n responder: BrokerRequestOrigin,\n job: JobRecord | undefined,\n requestId: string,\n message: string,\n ): BrokerSendAcknowledgement {\n validateRequestId(requestId);\n validateMessage(message, \"Subagent response\");\n const request = this.requests.get(requestId);\n if (\n !request ||\n request.expectedResponder !== responder ||\n (job && (request.jobId !== job.jobId || request.generation !== job.generation))\n ) {\n throw new Error(\"Unknown, expired, or unauthorized subagent request.\");\n }\n if (request.response !== undefined) {\n return { requestId, accepted: false, duplicate: true };\n }\n request.response = message;\n if (responder === \"child\") {\n try {\n this.deliverInbound({\n kind: \"response\",\n requestId,\n jobId: request.jobId,\n message,\n });\n this.markConsumed(request);\n } catch (error) {\n request.response = undefined;\n throw error;\n }\n } else if (request.waiter) {\n const socket = request.waiter.socket;\n this.clearWaiter(request);\n this.respond(socket, { ok: true, response: message }, () => this.markConsumed(request));\n }\n return { requestId, accepted: true, duplicate: false };\n }\n\n private deliverInbound(message: BrokerInboundMessage): void {\n this.options.onMessage(message);\n if (message.kind === \"response\" && this.inboundMessageListeners.size === 0) {\n this.pendingInboundResponse = true;\n }\n for (const listener of [...this.inboundMessageListeners]) {\n try {\n listener();\n } catch {\n // Runtime wait observers cannot interrupt broker delivery.\n }\n }\n }\n\n private accept(socket: Socket): void {\n if (!this.server || this.failure || this.sockets.size >= MAX_CONNECTIONS) {\n socket.destroy();\n return;\n }\n this.sockets.add(socket);\n socket.setNoDelay(true);\n let frame = Buffer.alloc(0);\n let handled = false;\n const frameTimer = setTimeout(() => {\n if (handled) return;\n handled = true;\n this.respondError(socket, \"Subagent broker request frame timed out.\");\n }, this.requestFrameTimeoutMs);\n frameTimer.unref();\n const cleanup = () => {\n clearTimeout(frameTimer);\n this.sockets.delete(socket);\n for (const request of this.requests.values()) {\n if (request.waiter?.socket === socket) this.clearWaiter(request);\n }\n };\n socket.on(\"data\", (chunk: Buffer) => {\n if (handled) return;\n frame = Buffer.concat([frame, chunk]);\n if (frame.byteLength > MAX_FRAME_BYTES) {\n handled = true;\n clearTimeout(frameTimer);\n this.respondError(socket, \"Subagent broker request exceeded its size limit.\");\n return;\n }\n const newline = frame.indexOf(0x0a);\n if (newline < 0) return;\n handled = true;\n clearTimeout(frameTimer);\n socket.removeAllListeners(\"data\");\n const trailing = frame\n .subarray(newline + 1)\n .toString(\"utf8\")\n .trim();\n if (trailing) {\n this.respondError(socket, \"Subagent broker accepts one request per connection.\");\n return;\n }\n this.handleFrame(socket, frame.subarray(0, newline).toString(\"utf8\"));\n });\n socket.once(\"close\", cleanup);\n socket.once(\"error\", cleanup);\n }\n\n private handleFrame(socket: Socket, frame: string): void {\n let request: BrokerRequest;\n try {\n const parsed = JSON.parse(frame) as unknown;\n if (!isRecord(parsed)) throw new Error();\n request = parsed as BrokerRequest;\n } catch {\n this.respondError(socket, \"Malformed subagent broker request.\");\n return;\n }\n const job = typeof request.token === \"string\" ? this.jobsByToken.get(request.token) : undefined;\n if (!job) {\n this.respondError(socket, \"Unauthenticated subagent broker request.\");\n return;\n }\n try {\n if (request.type === \"send\") {\n this.handleSend(socket, job, request);\n return;\n }\n if (request.type === \"wait\") {\n this.handleWait(socket, job, request);\n return;\n }\n throw new Error(\"Unsupported subagent broker request.\");\n } catch (error) {\n this.respondError(socket, error instanceof Error ? error.message : String(error));\n }\n }\n\n private handleSend(socket: Socket, job: JobRecord, request: Extract<BrokerRequest, { type: \"send\" }>): void {\n if (typeof request.message !== \"string\") {\n throw new Error(\"subagent_send requires a message string.\");\n }\n const hasRecipient = typeof request.recipient === \"string\";\n const hasRequestId = typeof request.requestId === \"string\";\n if (hasRecipient === hasRequestId) {\n throw new Error(\"subagent_send requires exactly one of recipient or requestId.\");\n }\n const acknowledgement = hasRecipient\n ? request.recipient === \"main\"\n ? this.createRequest(job, \"child\", request.message)\n : (() => {\n throw new Error('A subagent may send new requests only to recipient \"main\".');\n })()\n : this.acceptResponse(\"child\", job, request.requestId ?? \"\", request.message);\n this.respond(socket, { ok: true, ...acknowledgement });\n }\n\n private handleWait(socket: Socket, job: JobRecord, request: Extract<BrokerRequest, { type: \"wait\" }>): void {\n if (typeof request.requestId !== \"string\") {\n throw new Error(\"Subagent wait requires a request ID.\");\n }\n validateRequestId(request.requestId);\n if (request.timeoutMs !== undefined) validateTimeout(request.timeoutMs);\n const record = this.requests.get(request.requestId);\n if (record?.origin !== \"child\" || record.jobId !== job.jobId || record.generation !== job.generation) {\n throw new Error(\"Unknown or expired subagent request.\");\n }\n if (record.consumedAt !== undefined && record.response !== undefined) {\n this.respond(socket, { ok: true, response: record.response });\n return;\n }\n if (record.response !== undefined) {\n this.respond(socket, { ok: true, response: record.response }, () => this.markConsumed(record));\n return;\n }\n if (this.hasQueuedRequestForChild(job.jobId)) {\n this.respondError(socket, CHILD_WAIT_INTERRUPTED_ERROR);\n return;\n }\n if (record.waiter) {\n throw new Error(`A wait is already active for subagent request ${request.requestId}.`);\n }\n const waiter: RequestWaiter = { socket };\n record.waiter = waiter;\n if (request.timeoutMs !== undefined) {\n waiter.timer = setTimeout(() => {\n if (record.waiter !== waiter) return;\n this.clearWaiter(record);\n this.respondError(socket, \"Subagent response wait timed out.\");\n }, request.timeoutMs);\n waiter.timer.unref();\n }\n }\n\n private markConsumed(request: RequestRecord): void {\n if (this.requests.get(request.requestId) !== request || request.response === undefined) return;\n request.consumedAt ??= this.now();\n const consumed = [...this.requests.values()]\n .filter((candidate) => candidate.jobId === request.jobId && candidate.consumedAt !== undefined)\n .sort((left, right) => (left.consumedAt ?? 0) - (right.consumedAt ?? 0));\n for (const expired of consumed.slice(0, Math.max(0, consumed.length - MAX_RETAINED_CONSUMED_REQUESTS))) {\n this.requests.delete(expired.requestId);\n }\n }\n\n private clearWaiter(request: RequestRecord): void {\n if (request.waiter?.timer) clearTimeout(request.waiter.timer);\n request.waiter = undefined;\n }\n\n private respondError(socket: Socket, error: string): void {\n this.respond(socket, { ok: false, error: truncateError(error) });\n }\n\n private respond(socket: Socket, value: Record<string, unknown>, onFlushed?: () => void): void {\n if (socket.destroyed) return;\n let content = `${JSON.stringify(value)}\\n`;\n if (Buffer.byteLength(content, \"utf8\") > MAX_FRAME_BYTES) {\n content = `${JSON.stringify({ ok: false, error: \"Subagent broker response exceeded its size limit.\" })}\\n`;\n }\n socket.end(content, onFlushed);\n }\n\n private fail(error: Error): void {\n this.failure = truncateError(error.message);\n for (const jobId of [...this.tokenByJob.keys()]) {\n this.revokeJob(jobId, \"Subagent message broker failed.\");\n }\n for (const socket of this.sockets) socket.destroy();\n this.sockets.clear();\n this.address = undefined;\n }\n}\n\nexport function validateMessage(message: string, label: string): void {\n if (!message.trim()) throw new Error(`${label} is required.`);\n if (message.includes(\"\\0\")) throw new Error(`${label} must not contain NUL bytes.`);\n if (Buffer.byteLength(message, \"utf8\") > MAX_MESSAGE_BYTES) {\n throw new Error(`${label} must be at most ${MAX_MESSAGE_BYTES} UTF-8 bytes.`);\n }\n if (lineCount(message) > MAX_MESSAGE_LINES) {\n throw new Error(`${label} must contain at most ${MAX_MESSAGE_LINES} lines.`);\n }\n}\n\nexport function sanitizeTerminalText(value: string): string {\n return [...value]\n .filter((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n if (character === \"\\n\" || character === \"\\t\") return true;\n if (codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f)) return false;\n return !((codePoint >= 0x202a && codePoint <= 0x202e) || (codePoint >= 0x2066 && codePoint <= 0x2069));\n })\n .join(\"\");\n}\n\nfunction validateRequestId(requestId: string): void {\n if (\n requestId.length > MAX_IDENTIFIER_LENGTH ||\n !/^req_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u.test(requestId)\n ) {\n throw new Error(\"Invalid subagent request ID.\");\n }\n}\n\nfunction validateTimeout(timeoutMs: number): void {\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0 || timeoutMs > MAX_TIMEOUT_MS) {\n throw new Error(\"Subagent wait timeout is outside the supported range.\");\n }\n}\n\nfunction lineCount(value: string): number {\n let count = 1;\n for (const character of value) if (character === \"\\n\") count++;\n return count;\n}\n\nfunction truncateError(error: string): string {\n const bytes = Buffer.from(error, \"utf8\");\n if (bytes.length <= MAX_ERROR_BYTES) return error;\n return `${bytes\n .subarray(0, Math.max(0, MAX_ERROR_BYTES - 18))\n .toString(\"utf8\")\n .replace(/\uFFFD+$/gu, \"\")}\\n\u2026 [truncated]`;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isLoopbackAddress(address: AddressInfo | string | null): address is AddressInfo {\n return Boolean(address && typeof address !== \"string\" && address.address === BROKER_HOST);\n}\n", "import * as fs from \"node:fs\";\nimport type { BrokerCredentials } from \"./types.js\";\n\nexport const BROKER_CREDENTIAL_FD = 3;\nexport const BROKER_CREDENTIAL_FD_ENV = \"PI_SUBAGENT_BROKER_FD\";\nexport const CHILD_READINESS_FD = 4;\nexport const CHILD_READINESS_FD_ENV = \"PI_SUBAGENT_READINESS_FD\";\nexport const MAX_READINESS_FRAME_BYTES = 16 * 1024;\n\nconst MAX_BOOTSTRAP_BYTES = 16 * 1024;\nconst MAX_EXPECTED_TOOLS = 66;\nconst MAX_TOOL_NAME_LENGTH = 128;\nconst READINESS_STATE_KEY = Symbol.for(\"@narumitw/pi-subagents/child-readiness\");\n\nexport interface ChildBootstrap {\n communication: BrokerCredentials;\n expectedTools: string[];\n}\n\nexport interface CapturedChildBootstrap extends ChildBootstrap {\n readinessFd?: number;\n}\n\nexport function childBootstrapEnvironment(expectReadiness: boolean): NodeJS.ProcessEnv {\n return {\n [BROKER_CREDENTIAL_FD_ENV]: String(BROKER_CREDENTIAL_FD),\n ...(expectReadiness ? { [CHILD_READINESS_FD_ENV]: String(CHILD_READINESS_FD) } : {}),\n };\n}\n\nexport function serializeChildBootstrap(bootstrap: ChildBootstrap): string {\n return JSON.stringify(bootstrap);\n}\n\nexport function assertChildBootstrapCapacity(expectedTools: string[]): void {\n const serialized = serializeChildBootstrap({\n communication: { host: \"127.0.0.1\", port: 65_535, token: \"f\".repeat(64) },\n expectedTools,\n });\n if (Buffer.byteLength(serialized, \"utf8\") > MAX_BOOTSTRAP_BYTES) {\n throw new Error(`Subagent selected tool names exceed the ${MAX_BOOTSTRAP_BYTES}-byte child bootstrap size limit.`);\n }\n}\n\nexport function captureChildBootstrap(\n readBootstrap: () => string = readBootstrapPipe,\n): CapturedChildBootstrap | undefined {\n const credentialDescriptor = process.env[BROKER_CREDENTIAL_FD_ENV];\n const readinessDescriptor = process.env[CHILD_READINESS_FD_ENV];\n delete process.env[BROKER_CREDENTIAL_FD_ENV];\n delete process.env[CHILD_READINESS_FD_ENV];\n setCapturedReadiness(undefined);\n if (credentialDescriptor === undefined) {\n if (readinessDescriptor !== undefined) throw new Error(\"Unexpected pi-subagents readiness descriptor.\");\n return undefined;\n }\n if (credentialDescriptor !== String(BROKER_CREDENTIAL_FD)) {\n throw new Error(\"Invalid pi-subagents broker credential descriptor.\");\n }\n let serialized: string;\n try {\n serialized = readBootstrap();\n } catch {\n throw new Error(\"Unable to read pi-subagents child bootstrap.\");\n }\n if (Buffer.byteLength(serialized, \"utf8\") > MAX_BOOTSTRAP_BYTES) {\n throw new Error(\"Invalid pi-subagents child bootstrap.\");\n }\n let value: unknown;\n try {\n value = JSON.parse(serialized);\n } catch {\n throw new Error(\"Invalid pi-subagents child bootstrap.\");\n }\n if (!isChildBootstrap(value)) throw new Error(\"Invalid pi-subagents child bootstrap.\");\n\n if (value.expectedTools.length > 0) {\n if (readinessDescriptor !== String(CHILD_READINESS_FD)) {\n throw new Error(\"Invalid pi-subagents readiness descriptor.\");\n }\n setCapturedReadiness({ fd: CHILD_READINESS_FD, expectedTools: [...value.expectedTools] });\n return { ...value, readinessFd: CHILD_READINESS_FD };\n }\n if (readinessDescriptor !== undefined) throw new Error(\"Unexpected pi-subagents readiness descriptor.\");\n setCapturedReadiness(undefined);\n return value;\n}\n\nexport function takeCapturedReadiness(): { fd: number; expectedTools: string[] } | undefined {\n const store = globalThis as unknown as Record<symbol, { fd: number; expectedTools: string[] } | undefined>;\n const readiness = store[READINESS_STATE_KEY];\n delete store[READINESS_STATE_KEY];\n return readiness ? { fd: readiness.fd, expectedTools: [...readiness.expectedTools] } : undefined;\n}\n\nfunction setCapturedReadiness(readiness: { fd: number; expectedTools: string[] } | undefined): void {\n const store = globalThis as unknown as Record<symbol, { fd: number; expectedTools: string[] } | undefined>;\n if (readiness) store[READINESS_STATE_KEY] = readiness;\n else delete store[READINESS_STATE_KEY];\n}\n\nfunction readBootstrapPipe(): string {\n try {\n return fs.readFileSync(BROKER_CREDENTIAL_FD, \"utf8\");\n } finally {\n try {\n fs.closeSync(BROKER_CREDENTIAL_FD);\n } catch {\n // The descriptor may already be closed after a failed read.\n }\n }\n}\n\nfunction isChildBootstrap(value: unknown): value is ChildBootstrap {\n if (!isRecord(value) || Object.keys(value).length !== 2) return false;\n if (!isBrokerCredentials(value.communication)) return false;\n if (!Array.isArray(value.expectedTools) || value.expectedTools.length > MAX_EXPECTED_TOOLS) return false;\n return value.expectedTools.every(\n (tool) =>\n typeof tool === \"string\" &&\n tool.length > 0 &&\n tool.length <= MAX_TOOL_NAME_LENGTH &&\n !tool.includes(\",\") &&\n !hasControlCharacter(tool),\n );\n}\n\nfunction isBrokerCredentials(value: unknown): value is BrokerCredentials {\n if (!isRecord(value) || Object.keys(value).length !== 3) return false;\n return (\n value.host === \"127.0.0.1\" &&\n Number.isSafeInteger(value.port) &&\n (value.port as number) >= 1 &&\n (value.port as number) <= 65_535 &&\n typeof value.token === \"string\" &&\n /^[a-f0-9]{64}$/u.test(value.token)\n );\n}\n\nfunction hasControlCharacter(value: string): boolean {\n return [...value].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f);\n });\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n"],
5
- "mappings": "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",
6
- "names": ["request", "isRecord"]
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/child-communication-tools.ts", "../../src/timeout.ts"],
4
- "sourcesContent": ["import type { ExtensionFactory } from \"@earendil-works/pi-coding-agent\";\nimport { type Static, Type } from \"typebox\";\nimport {\n type BrokerSendAcknowledgement,\n MAX_IDENTIFIER_LENGTH,\n MAX_MESSAGE_BYTES,\n sanitizeTerminalText,\n validateMessage,\n} from \"./message-broker.js\";\nimport { prepareTimeoutArguments, resolveTimeoutMs } from \"./timeout.js\";\n\nexport const CHILD_COMMUNICATION_TOOL_NAMES = [\"subagent_send\", \"subagent_wait\"] as const;\n\nconst SendParameters = Type.Object(\n {\n requestId: Type.Optional(\n Type.String({\n description: \"Pending main-agent request to answer. Omit when starting a new request.\",\n minLength: 1,\n maxLength: MAX_IDENTIFIER_LENGTH,\n }),\n ),\n message: Type.String({\n description: \"Plain-text request or response. Maximum 48 KiB of UTF-8 text and 1,992 lines.\",\n minLength: 1,\n maxLength: MAX_MESSAGE_BYTES,\n }),\n },\n { additionalProperties: false },\n);\n\nconst WaitParameters = Type.Object(\n {\n requestId: Type.String({\n description: \"Request ID returned by subagent_send.\",\n minLength: 1,\n maxLength: MAX_IDENTIFIER_LENGTH,\n }),\n timeout: Type.Optional(Type.Number({ description: \"Timeout in seconds (optional, no default timeout)\" })),\n },\n { additionalProperties: false },\n);\n\ntype ChildBrokerSendArguments = { recipient: \"main\"; message: string } | { requestId: string; message: string };\n\ntype WaitArguments = Static<typeof WaitParameters>;\n\nexport interface ChildCommunicationClient {\n send(params: ChildBrokerSendArguments, signal?: AbortSignal): Promise<BrokerSendAcknowledgement>;\n wait(requestId: string, timeoutMs: number | undefined, signal?: AbortSignal): Promise<string>;\n}\n\nexport function createChildCommunicationExtension(client: ChildCommunicationClient): ExtensionFactory {\n return (pi) => {\n pi.registerTool({\n name: \"subagent_send\",\n label: \"Subagent \u00B7 Send to Main\",\n description:\n \"Use subagent_send to send one request to the main agent or answer one pending main-agent request. Omit requestId to start a request. Provide requestId to answer that request.\",\n promptSnippet: \"Use subagent_send to send or answer one main-agent message\",\n parameters: SendParameters,\n async execute(_toolCallId, params, signal) {\n validateMessage(params.message, \"Subagent message\");\n const requestId = optionalIdentifier(params.requestId, \"requestId\");\n const acknowledgement = await client.send(\n requestId === undefined\n ? { recipient: \"main\", message: params.message }\n : { requestId, message: params.message },\n signal,\n );\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(acknowledgement) }],\n details: acknowledgement,\n };\n },\n });\n\n pi.registerTool({\n name: \"subagent_wait\",\n label: \"Subagent \u00B7 Wait for Main Agent\",\n description:\n \"Use subagent_wait with a request ID from subagent_send to wait for the main agent's plain-text response. A timeout, caller cancellation, or incoming main-agent request stops only this wait and does not cancel the original request. Retry the wait when its response is still needed.\",\n promptSnippet: \"Use subagent_wait to receive a requested main-agent response\",\n parameters: WaitParameters,\n prepareArguments: prepareWaitArguments,\n async execute(_toolCallId, params, signal) {\n const requestId = requiredIdentifier(params.requestId, \"requestId\");\n const response = await client.wait(requestId, resolveTimeoutMs(params.timeout), signal);\n return {\n content: [{ type: \"text\" as const, text: sanitizeTerminalText(response) }],\n details: { requestId },\n };\n },\n });\n };\n}\n\nfunction prepareWaitArguments(args: unknown): WaitArguments {\n return prepareTimeoutArguments(args) as WaitArguments;\n}\n\nfunction optionalIdentifier(value: unknown, field: string): string | undefined {\n return value === undefined ? undefined : requiredIdentifier(value, field);\n}\n\nfunction requiredIdentifier(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value.trim()) throw new Error(`Subagent ${field} is required.`);\n const identifier = value.trim();\n if (\n identifier.length > MAX_IDENTIFIER_LENGTH ||\n [...identifier].some((character) => {\n const codePoint = character.codePointAt(0) ?? 0;\n return codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f);\n })\n ) {\n throw new Error(`Subagent ${field} is invalid.`);\n }\n return identifier;\n}\n", "const MAX_TIMEOUT_MS = 2_147_483_647;\nconst MAX_TIMEOUT_SECONDS = MAX_TIMEOUT_MS / 1000;\n\nexport function resolveTimeoutMs(timeout: number | undefined): number | undefined {\n if (timeout === undefined) return undefined;\n if (!Number.isFinite(timeout) || timeout <= 0) {\n throw new Error(\"Invalid timeout: must be a finite number of seconds\");\n }\n const timeoutMs = timeout * 1000;\n if (timeoutMs > MAX_TIMEOUT_MS) {\n throw new Error(`Invalid timeout: maximum is ${MAX_TIMEOUT_SECONDS} seconds`);\n }\n return timeoutMs;\n}\n\nexport function prepareTimeoutArguments(args: unknown): Record<string, unknown> {\n if (!args || typeof args !== \"object\") return args as Record<string, unknown>;\n if (!Object.hasOwn(args, \"timeoutMs\")) return args as Record<string, unknown>;\n const record = args as Record<string, unknown>;\n if (typeof record.timeoutMs !== \"number\") return record;\n const { timeoutMs, ...prepared } = record;\n if (prepared.timeout === undefined) return { ...prepared, timeout: timeoutMs / 1000 };\n return prepared;\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../src/menu.ts"],
4
- "sourcesContent": ["import type { ExtensionCommandContext } from \"@earendil-works/pi-coding-agent\";\nimport { defineMenu, runConfirmation, runMenu, runTask, sanitizeTerminalText } from \"@narumitw/pi-tui-kit\";\nimport type { SubagentSettings } from \"./settings.js\";\nimport { JOB_STATES, type JobSummary } from \"./types.js\";\n\ninterface SubagentsMenuState {\n settings: SubagentSettings;\n settingsPath: string;\n jobs: JobSummary[];\n omitted: number;\n}\n\ninterface SubagentsMenuOptions {\n signal: AbortSignal;\n isCurrent(): boolean;\n getState(): SubagentsMenuState;\n cancelJob(jobId: string, signal: AbortSignal): Promise<void>;\n showSettings(signal: AbortSignal): Promise<\"back\" | \"close\" | \"stale\">;\n}\n\nexport async function showSubagentsMenu(ctx: ExtensionCommandContext, options: SubagentsMenuOptions): Promise<void> {\n if (options.signal.aborted || !options.isCurrent()) return;\n let selectedJobId: string | undefined;\n const current = (signal: AbortSignal) => !signal.aborted && options.isCurrent();\n const menu = defineMenu<\n SubagentsMenuState,\n \"main\" | \"jobs\" | \"job\" | \"status\" | \"help\",\n \"selectJob\" | \"cancelJob\" | \"settings\"\n >({\n start: \"main\",\n screens: {\n main: ({ state }) => ({\n kind: \"actions\",\n title: \"Subagents\",\n lines: [jobCounts(state)],\n items: [\n { id: \"jobs\", label: \"Jobs\", to: \"jobs\" },\n { id: \"settings\", label: \"Settings\", action: \"settings\" },\n { id: \"status\", label: \"Status\", to: \"status\" },\n { id: \"help\", label: \"Help\", to: \"help\" },\n { id: \"close\", label: \"Close\", close: true },\n ],\n hint: \"close\",\n }),\n jobs: ({ state }) => ({\n kind: \"choice\",\n title: \"Subagent Jobs\",\n lines: [jobCounts(state), ...(state.jobs.length === 0 ? [\"No jobs in this session.\"] : [])],\n items: state.jobs.map((job) => ({\n id: job.jobId,\n label: sanitizeTerminalText(job.jobId),\n description: sanitizeTerminalText(job.state),\n })),\n action: \"selectJob\",\n hint: \"back\",\n }),\n job: ({ state }) => {\n const job = state.jobs.find((candidate) => candidate.jobId === selectedJobId);\n return {\n kind: \"actions\",\n title: \"Subagent Job\",\n lines: job ? jobLines(job) : [\"This job is no longer available.\"],\n items: job && isActive(job) ? [{ id: \"cancel\", label: \"Cancel job\u2026\", action: \"cancelJob\" }] : [],\n hint: \"back\",\n };\n },\n status: ({ state }) => ({\n kind: \"detail\",\n title: \"Subagents Status\",\n lines: [\n \"Runtime: active for this session\",\n `Retained jobs: ${state.jobs.length}`,\n `Active jobs: ${state.jobs.filter(isActive).length}`,\n `Omitted jobs: ${state.omitted}`,\n ...JOB_STATES.map((status) => `${status}: ${state.jobs.filter((job) => job.state === status).length}`),\n `Show widget: ${state.settings.showWidget}`,\n `Show job ID: ${state.settings.showJobId}`,\n `Show tools: ${state.settings.showTools}`,\n `Show timing: ${state.settings.showTiming}`,\n `User settings: ${sanitizeTerminalText(state.settingsPath)}`,\n ],\n hint: \"back\",\n }),\n help: () => ({\n kind: \"detail\",\n title: \"Subagents Help\",\n lines: [\n \"/subagents opens the job manager.\",\n \"/subagents settings opens the same settings screen directly.\",\n \"Jobs shows this session's job summaries. Only queued or running jobs can be cancelled, after confirmation.\",\n \"The model uses subagent_spawn to start jobs, subagent_inspect to check them, and subagent_wait to wait for results.\",\n \"subagent_send sends a message; subagent_cancel cancels a job.\",\n \"Jobs are session-only. The runtime retains up to 32 terminal jobs for up to 24 hours.\",\n \"Settings changes display preferences only. All four settings default to true.\",\n \"Successful saves apply immediately. Use /reload after manual settings edits.\",\n \"In RPC mode, Settings reports the user settings file path.\",\n ],\n hint: \"back\",\n }),\n },\n actions: {\n selectJob: ({ itemId, signal }) => {\n if (!current(signal)) return { kind: \"close\" };\n if (!options.getState().jobs.some((job) => job.jobId === itemId)) return { kind: \"stay\" };\n selectedJobId = itemId;\n return { kind: \"to\", screen: \"job\" };\n },\n settings: async ({ signal }) => {\n if (!current(signal)) return { kind: \"close\" };\n const reason = await options.showSettings(signal);\n return { kind: current(signal) && reason === \"back\" ? \"stay\" : \"close\" };\n },\n cancelJob: async ({ signal }) => {\n if (!current(signal)) return { kind: \"close\" };\n const jobId = selectedJobId;\n const job = options.getState().jobs.find((candidate) => candidate.jobId === jobId);\n if (!job || !isActive(job)) return { kind: \"stay\" };\n const confirmation = await runConfirmation(ctx, {\n title: \"Cancel subagent job?\",\n message: `Cancel job ${sanitizeTerminalText(job.jobId)} (${sanitizeTerminalText(job.state)})?`,\n confirmLabel: \"Cancel job\",\n cancelLabel: \"Keep job\",\n signal,\n isCurrent: options.isCurrent,\n onError: () => undefined,\n });\n if (!current(signal)) return { kind: \"close\" };\n if (confirmation.kind === \"closed\") {\n return { kind: confirmation.reason === \"close\" ? \"close\" : \"stay\" };\n }\n if (confirmation.kind === \"error\") throw confirmation.error;\n if (confirmation.kind !== \"confirmed\") return { kind: \"close\" };\n // The runtime can finish or remove a job while its confirmation is open.\n const latest = options.getState().jobs.find((candidate) => candidate.jobId === jobId);\n if (selectedJobId !== jobId || !latest || !isActive(latest)) return { kind: \"stay\" };\n const result = await runTask(ctx, {\n label: \"Cancelling subagent job\u2026\",\n signal,\n isCurrent: options.isCurrent,\n task: ({ signal: taskSignal }) => options.cancelJob(latest.jobId, taskSignal),\n onError: () => undefined,\n });\n if (!current(signal)) return { kind: \"close\" };\n if (result.kind === \"error\") throw result.error;\n if (result.kind === \"stale\") return { kind: \"close\" };\n if (result.kind === \"cancelled\") return { kind: \"close\" };\n return { kind: \"stay\" };\n },\n },\n });\n await runMenu(ctx, menu, {\n signal: options.signal,\n isCurrent: options.isCurrent,\n getState: options.getState,\n onError: (_ctx, error) => {\n if (!options.signal.aborted && options.isCurrent() && ctx.hasUI) {\n ctx.ui.notify(\n sanitizeTerminalText(`Subagents menu failed: ${error instanceof Error ? error.message : String(error)}`),\n \"error\",\n );\n }\n },\n });\n}\n\nfunction isActive(job: JobSummary): boolean {\n return job.state === \"queued\" || job.state === \"running\";\n}\n\nfunction jobCounts(state: SubagentsMenuState): string {\n return `Jobs: ${state.jobs.length} shown, ${state.jobs.filter(isActive).length} active, ${state.omitted} omitted`;\n}\n\nfunction jobLines(job: JobSummary): string[] {\n return [\n `Job ID: ${sanitizeTerminalText(job.jobId)}`,\n `State: ${sanitizeTerminalText(job.state)}`,\n `Created: ${timestamp(job.createdAt)}`,\n ...(job.startedAt === undefined ? [] : [`Started: ${timestamp(job.startedAt)}`]),\n ...(job.finishedAt === undefined ? [] : [`Finished: ${timestamp(job.finishedAt)}`]),\n ...(job.timeout === undefined ? [] : [`Timeout: ${job.timeout} seconds`]),\n ];\n}\n\nfunction timestamp(value: number): string {\n const date = new Date(value);\n return Number.isFinite(date.getTime()) ? date.toISOString() : \"unknown\";\n}\n"],
5
- "mappings": ";;;;;;;AACA,SAAS,YAAY,iBAAiB,SAAS,SAAS,4BAA4B;AAmBpF,eAAsB,kBAAkB,KAA8B,SAA8C;AAClH,MAAI,QAAQ,OAAO,WAAW,CAAC,QAAQ,UAAU,EAAG;AACpD,MAAI;AACJ,QAAM,UAAU,CAAC,WAAwB,CAAC,OAAO,WAAW,QAAQ,UAAU;AAC9E,QAAM,OAAO,WAIX;AAAA,IACA,OAAO;AAAA,IACP,SAAS;AAAA,MACP,MAAM,CAAC,EAAE,MAAM,OAAO;AAAA,QACpB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,CAAC,UAAU,KAAK,CAAC;AAAA,QACxB,OAAO;AAAA,UACL,EAAE,IAAI,QAAQ,OAAO,QAAQ,IAAI,OAAO;AAAA,UACxC,EAAE,IAAI,YAAY,OAAO,YAAY,QAAQ,WAAW;AAAA,UACxD,EAAE,IAAI,UAAU,OAAO,UAAU,IAAI,SAAS;AAAA,UAC9C,EAAE,IAAI,QAAQ,OAAO,QAAQ,IAAI,OAAO;AAAA,UACxC,EAAE,IAAI,SAAS,OAAO,SAAS,OAAO,KAAK;AAAA,QAC7C;AAAA,QACA,MAAM;AAAA,MACR;AAAA,MACA,MAAM,CAAC,EAAE,MAAM,OAAO;AAAA,QACpB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO,CAAC,UAAU,KAAK,GAAG,GAAI,MAAM,KAAK,WAAW,IAAI,CAAC,0BAA0B,IAAI,CAAC,CAAE;AAAA,QAC1F,OAAO,MAAM,KAAK,IAAI,CAAC,SAAS;AAAA,UAC9B,IAAI,IAAI;AAAA,UACR,OAAO,qBAAqB,IAAI,KAAK;AAAA,UACrC,aAAa,qBAAqB,IAAI,KAAK;AAAA,QAC7C,EAAE;AAAA,QACF,QAAQ;AAAA,QACR,MAAM;AAAA,MACR;AAAA,MACA,KAAK,CAAC,EAAE,MAAM,MAAM;AAClB,cAAM,MAAM,MAAM,KAAK,KAAK,CAAC,cAAc,UAAU,UAAU,aAAa;AAC5E,eAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,UACP,OAAO,MAAM,SAAS,GAAG,IAAI,CAAC,kCAAkC;AAAA,UAChE,OAAO,OAAO,SAAS,GAAG,IAAI,CAAC,EAAE,IAAI,UAAU,OAAO,oBAAe,QAAQ,YAAY,CAAC,IAAI,CAAC;AAAA,UAC/F,MAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,QAAQ,CAAC,EAAE,MAAM,OAAO;AAAA,QACtB,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,UACL;AAAA,UACA,kBAAkB,MAAM,KAAK,MAAM;AAAA,UACnC,gBAAgB,MAAM,KAAK,OAAO,QAAQ,EAAE,MAAM;AAAA,UAClD,iBAAiB,MAAM,OAAO;AAAA,UAC9B,GAAG,WAAW,IAAI,CAAC,WAAW,GAAG,MAAM,KAAK,MAAM,KAAK,OAAO,CAAC,QAAQ,IAAI,UAAU,MAAM,EAAE,MAAM,EAAE;AAAA,UACrG,gBAAgB,MAAM,SAAS,UAAU;AAAA,UACzC,gBAAgB,MAAM,SAAS,SAAS;AAAA,UACxC,eAAe,MAAM,SAAS,SAAS;AAAA,UACvC,gBAAgB,MAAM,SAAS,UAAU;AAAA,UACzC,kBAAkB,qBAAqB,MAAM,YAAY,CAAC;AAAA,QAC5D;AAAA,QACA,MAAM;AAAA,MACR;AAAA,MACA,MAAM,OAAO;AAAA,QACX,MAAM;AAAA,QACN,OAAO;AAAA,QACP,OAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QACA,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,WAAW,CAAC,EAAE,QAAQ,OAAO,MAAM;AACjC,YAAI,CAAC,QAAQ,MAAM,EAAG,QAAO,EAAE,MAAM,QAAQ;AAC7C,YAAI,CAAC,QAAQ,SAAS,EAAE,KAAK,KAAK,CAAC,QAAQ,IAAI,UAAU,MAAM,EAAG,QAAO,EAAE,MAAM,OAAO;AACxF,wBAAgB;AAChB,eAAO,EAAE,MAAM,MAAM,QAAQ,MAAM;AAAA,MACrC;AAAA,MACA,UAAU,OAAO,EAAE,OAAO,MAAM;AAC9B,YAAI,CAAC,QAAQ,MAAM,EAAG,QAAO,EAAE,MAAM,QAAQ;AAC7C,cAAM,SAAS,MAAM,QAAQ,aAAa,MAAM;AAChD,eAAO,EAAE,MAAM,QAAQ,MAAM,KAAK,WAAW,SAAS,SAAS,QAAQ;AAAA,MACzE;AAAA,MACA,WAAW,OAAO,EAAE,OAAO,MAAM;AAC/B,YAAI,CAAC,QAAQ,MAAM,EAAG,QAAO,EAAE,MAAM,QAAQ;AAC7C,cAAM,QAAQ;AACd,cAAM,MAAM,QAAQ,SAAS,EAAE,KAAK,KAAK,CAAC,cAAc,UAAU,UAAU,KAAK;AACjF,YAAI,CAAC,OAAO,CAAC,SAAS,GAAG,EAAG,QAAO,EAAE,MAAM,OAAO;AAClD,cAAM,eAAe,MAAM,gBAAgB,KAAK;AAAA,UAC9C,OAAO;AAAA,UACP,SAAS,cAAc,qBAAqB,IAAI,KAAK,CAAC,KAAK,qBAAqB,IAAI,KAAK,CAAC;AAAA,UAC1F,cAAc;AAAA,UACd,aAAa;AAAA,UACb;AAAA,UACA,WAAW,QAAQ;AAAA,UACnB,SAAS,MAAM;AAAA,QACjB,CAAC;AACD,YAAI,CAAC,QAAQ,MAAM,EAAG,QAAO,EAAE,MAAM,QAAQ;AAC7C,YAAI,aAAa,SAAS,UAAU;AAClC,iBAAO,EAAE,MAAM,aAAa,WAAW,UAAU,UAAU,OAAO;AAAA,QACpE;AACA,YAAI,aAAa,SAAS,QAAS,OAAM,aAAa;AACtD,YAAI,aAAa,SAAS,YAAa,QAAO,EAAE,MAAM,QAAQ;AAE9D,cAAM,SAAS,QAAQ,SAAS,EAAE,KAAK,KAAK,CAAC,cAAc,UAAU,UAAU,KAAK;AACpF,YAAI,kBAAkB,SAAS,CAAC,UAAU,CAAC,SAAS,MAAM,EAAG,QAAO,EAAE,MAAM,OAAO;AACnF,cAAM,SAAS,MAAM,QAAQ,KAAK;AAAA,UAChC,OAAO;AAAA,UACP;AAAA,UACA,WAAW,QAAQ;AAAA,UACnB,MAAM,CAAC,EAAE,QAAQ,WAAW,MAAM,QAAQ,UAAU,OAAO,OAAO,UAAU;AAAA,UAC5E,SAAS,MAAM;AAAA,QACjB,CAAC;AACD,YAAI,CAAC,QAAQ,MAAM,EAAG,QAAO,EAAE,MAAM,QAAQ;AAC7C,YAAI,OAAO,SAAS,QAAS,OAAM,OAAO;AAC1C,YAAI,OAAO,SAAS,QAAS,QAAO,EAAE,MAAM,QAAQ;AACpD,YAAI,OAAO,SAAS,YAAa,QAAO,EAAE,MAAM,QAAQ;AACxD,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB;AAAA,IACF;AAAA,EACF,CAAC;AACD,QAAM,QAAQ,KAAK,MAAM;AAAA,IACvB,QAAQ,QAAQ;AAAA,IAChB,WAAW,QAAQ;AAAA,IACnB,UAAU,QAAQ;AAAA,IAClB,SAAS,CAAC,MAAM,UAAU;AACxB,UAAI,CAAC,QAAQ,OAAO,WAAW,QAAQ,UAAU,KAAK,IAAI,OAAO;AAC/D,YAAI,GAAG;AAAA,UACL,qBAAqB,0BAA0B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC,EAAE;AAAA,UACvG;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,SAAS,KAA0B;AAC1C,SAAO,IAAI,UAAU,YAAY,IAAI,UAAU;AACjD;AAEA,SAAS,UAAU,OAAmC;AACpD,SAAO,SAAS,MAAM,KAAK,MAAM,WAAW,MAAM,KAAK,OAAO,QAAQ,EAAE,MAAM,YAAY,MAAM,OAAO;AACzG;AAEA,SAAS,SAAS,KAA2B;AAC3C,SAAO;AAAA,IACL,WAAW,qBAAqB,IAAI,KAAK,CAAC;AAAA,IAC1C,UAAU,qBAAqB,IAAI,KAAK,CAAC;AAAA,IACzC,YAAY,UAAU,IAAI,SAAS,CAAC;AAAA,IACpC,GAAI,IAAI,cAAc,SAAY,CAAC,IAAI,CAAC,YAAY,UAAU,IAAI,SAAS,CAAC,EAAE;AAAA,IAC9E,GAAI,IAAI,eAAe,SAAY,CAAC,IAAI,CAAC,aAAa,UAAU,IAAI,UAAU,CAAC,EAAE;AAAA,IACjF,GAAI,IAAI,YAAY,SAAY,CAAC,IAAI,CAAC,YAAY,IAAI,OAAO,UAAU;AAAA,EACzE;AACF;AAEA,SAAS,UAAU,OAAuB;AACxC,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,SAAO,OAAO,SAAS,KAAK,QAAQ,CAAC,IAAI,KAAK,YAAY,IAAI;AAChE;",
6
- "names": []
7
- }