{"version":3,"file":"prompt-template-bridge.d.ts","sourceRoot":"","sources":["../../../src/slash/prompt-template-bridge.ts"],"names":[],"mappings":"AAUA,OAAO,EACN,KAAK,gCAAgC,EACrC,KAAK,0BAA0B,EAS/B,MAAM,0BAA0B,CAAC;AAGlC,eAAO,MAAM,sCAAsC,qCAAoC,CAAC;AACxF,eAAO,MAAM,sCAAsC,qCAAoC,CAAC;AACxF,eAAO,MAAM,uCAAuC,sCAAqC,CAAC;AAC1F,eAAO,MAAM,qCAAqC,oCAAmC,CAAC;AACtF,eAAO,MAAM,qCAAqC,oCAAmC,CAAC;AAEtF,MAAM,WAAW,0BAA0B;IAC1C,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;IAC9E,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;CACzC;AAED,UAAU,2BAA2B,CAAC,GAAG,SAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE;IACjE,MAAM,EAAE,0BAA0B,CAAC;IACnC,UAAU,EAAE,MAAM,GAAG,GAAG,IAAI,CAAC;IAC7B,OAAO,EAAE,CACR,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gCAAgC,EACxC,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,KAClD,OAAO,CAAC,0BAA0B,CAAC,CAAC;IACzC,mEAAmE;IACnE,iBAAiB,CAAC,EAAE,CACnB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,gCAAgC,EACxC,MAAM,EAAE,WAAW,EACnB,GAAG,EAAE,GAAG,EACR,QAAQ,EAAE,CAAC,MAAM,EAAE,0BAA0B,KAAK,IAAI,KAClD,OAAO,CAAC,0BAA0B,CAAC,CAAC;CACzC;AAiBD,wBAAgB,sCAAsC,CAAC,GAAG,SAAS;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,EAClF,OAAO,EAAE,2BAA2B,CAAC,GAAG,CAAC,GACvC;IACF,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACpB,CAuTA","sourcesContent":["import {\n\tSUBAGENT_DELEGATION_CANCEL_EVENT,\n\tSUBAGENT_DELEGATION_REQUEST_EVENT,\n\tSUBAGENT_DELEGATION_RESPONSE_EVENT,\n\tSUBAGENT_DELEGATION_STARTED_EVENT,\n\tSUBAGENT_DELEGATION_UPDATE_EVENT,\n\ttype SubagentDelegationInvalidResponse,\n\ttype SubagentDelegationRequest,\n\ttype SubagentDelegationResponse,\n} from \"../api/delegation.ts\";\nimport {\n\ttype DelegatedSubagentExecutionParams,\n\ttype PromptTemplateBridgeResult,\n\ttype PromptTemplateDelegationRequest,\n\ttype PromptTemplateDelegationResponse,\n\tparsePromptTemplateRequest,\n\ttoDelegationUpdate,\n\ttoPromptTemplateResponse,\n\ttoSubagentDelegationExecutionParams,\n\ttoSubagentDelegationResponse,\n\ttoSubagentDelegationUpdate,\n} from \"./delegation-adapters.ts\";\nimport { parseSubagentDelegationRequest } from \"./delegation-request.ts\";\n\nexport const PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT = SUBAGENT_DELEGATION_REQUEST_EVENT;\nexport const PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT = SUBAGENT_DELEGATION_STARTED_EVENT;\nexport const PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT = SUBAGENT_DELEGATION_RESPONSE_EVENT;\nexport const PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT = SUBAGENT_DELEGATION_UPDATE_EVENT;\nexport const PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT = SUBAGENT_DELEGATION_CANCEL_EVENT;\n\nexport interface PromptTemplateBridgeEvents {\n\ton(event: string, handler: (data: unknown) => void): (() => void) | undefined;\n\temit(event: string, data: unknown): void;\n}\n\ninterface PromptTemplateBridgeOptions<Ctx extends { cwd?: string }> {\n\tevents: PromptTemplateBridgeEvents;\n\tgetContext: () => Ctx | null;\n\texecute: (\n\t\trequestId: string,\n\t\tparams: DelegatedSubagentExecutionParams,\n\t\tsignal: AbortSignal,\n\t\tctx: Ctx,\n\t\tonUpdate: (result: PromptTemplateBridgeResult) => void,\n\t) => Promise<PromptTemplateBridgeResult>;\n\t/** Concurrent-safe executor for structured delegation requests. */\n\texecuteStructured?: (\n\t\trequestId: string,\n\t\tparams: DelegatedSubagentExecutionParams,\n\t\tsignal: AbortSignal,\n\t\tctx: Ctx,\n\t\tonUpdate: (result: PromptTemplateBridgeResult) => void,\n\t) => Promise<PromptTemplateBridgeResult>;\n}\n\nfunction hasStructuredDelegationMarker(data: unknown): boolean {\n\tif (!data || typeof data !== \"object\" || Array.isArray(data)) return false;\n\tconst value = data as Record<string, unknown>;\n\treturn (\n\t\tObject.hasOwn(value, \"ownerRunId\") ||\n\t\tObject.hasOwn(value, \"nodeId\") ||\n\t\tObject.hasOwn(value, \"result\") ||\n\t\tObject.hasOwn(value, \"version\")\n\t);\n}\n\nfunction validId(value: unknown): value is string {\n\treturn typeof value === \"string\" && value.trim().length > 0 && value.length <= 256 && !/[\\r\\n]/.test(value);\n}\n\nexport function registerPromptTemplateDelegationBridge<Ctx extends { cwd?: string }>(\n\toptions: PromptTemplateBridgeOptions<Ctx>,\n): {\n\tcancelAll: () => void;\n\tdispose: () => void;\n} {\n\tconst legacyControllers = new Map<string, AbortController>();\n\tconst pendingLegacyCancels = new Map<string, true>();\n\tconst attemptControllers = new Map<string, AbortController>();\n\tconst pendingAttemptCancels = new Map<string, true>();\n\tconst activeOwnedNodes = new Map<string, { attemptKey: string; controller: AbortController }>();\n\tconst settledAttempts = new Map<string, true>();\n\tconst subscriptions: Array<() => void> = [];\n\tlet disposed = false;\n\tlet identitySaturated = false;\n\n\tconst subscribe = (event: string, handler: (data: unknown) => void): void => {\n\t\tconst unsubscribe = options.events.on(event, handler);\n\t\tif (typeof unsubscribe === \"function\") subscriptions.push(unsubscribe);\n\t};\n\tconst ownsLegacyRequest = (requestId: string, controller: AbortController): boolean =>\n\t\t!disposed && legacyControllers.get(requestId) === controller;\n\tconst ownsAttempt = (attemptKey: string, controller: AbortController): boolean =>\n\t\t!disposed && attemptControllers.get(attemptKey) === controller;\n\tconst boundedRemember = (map: Map<string, true>, key: string): void => {\n\t\tmap.delete(key);\n\t\tmap.set(key, true);\n\t\twhile (map.size > 256) {\n\t\t\tconst oldest = map.keys().next().value;\n\t\t\tif (typeof oldest !== \"string\") break;\n\t\t\tmap.delete(oldest);\n\t\t}\n\t};\n\tconst rememberIdentity = (map: Map<string, true>, key: string): void => {\n\t\tif (map.has(key) || identitySaturated) return;\n\t\tif (map.size >= 8_192) {\n\t\t\tidentitySaturated = true;\n\t\t\treturn;\n\t\t}\n\t\tmap.set(key, true);\n\t\tif (map.size === 8_192) {\n\t\t\t// Exact cancellation and terminal-attempt facts are security state, not an\n\t\t\t// LRU cache. Once full, fail closed rather than evicting identity facts.\n\t\t\tidentitySaturated = true;\n\t\t}\n\t};\n\tconst nodeKey = (ownerRunId: string, nodeId: string): string => JSON.stringify([ownerRunId, nodeId]);\n\tconst attemptKey = (requestId: string, ownerRunId: string, nodeId: string): string =>\n\t\tJSON.stringify([requestId, ownerRunId, nodeId]);\n\tconst rememberPendingLegacyCancel = (requestId: string): void => {\n\t\tboundedRemember(pendingLegacyCancels, requestId);\n\t};\n\tconst emitTerminal = (key: string, payload: SubagentDelegationResponse): void => {\n\t\tif (disposed || settledAttempts.has(key)) return;\n\t\trememberIdentity(settledAttempts, key);\n\t\toptions.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);\n\t};\n\n\tsubscribe(PROMPT_TEMPLATE_SUBAGENT_CANCEL_EVENT, (data) => {\n\t\tif (!data || typeof data !== \"object\" || Array.isArray(data)) return;\n\t\tconst value = data as Record<string, unknown>;\n\t\tconst requestId = value.requestId;\n\t\tif (!validId(requestId)) return;\n\t\tif (hasStructuredDelegationMarker(data)) {\n\t\t\tif (Object.keys(value).some((key) => key !== \"requestId\" && key !== \"ownerRunId\" && key !== \"nodeId\")) return;\n\t\t\tconst ownerRunId = value.ownerRunId;\n\t\t\tconst nodeId = value.nodeId;\n\t\t\tif (!validId(ownerRunId) || !validId(nodeId)) return;\n\t\t\tconst key = attemptKey(requestId, ownerRunId, nodeId);\n\t\t\tconst controller = attemptControllers.get(key);\n\t\t\tif (controller) controller.abort();\n\t\t\telse rememberIdentity(pendingAttemptCancels, key);\n\t\t\treturn;\n\t\t}\n\t\tconst controller = legacyControllers.get(requestId);\n\t\tif (controller) {\n\t\t\tcontroller.abort();\n\t\t\treturn;\n\t\t}\n\t\trememberPendingLegacyCancel(requestId);\n\t});\n\n\tsubscribe(PROMPT_TEMPLATE_SUBAGENT_REQUEST_EVENT, async (data) => {\n\t\tconst structuredPayload = hasStructuredDelegationMarker(data);\n\t\tlet requestId: string;\n\t\tlet params: DelegatedSubagentExecutionParams;\n\t\tlet structuredRequest: SubagentDelegationRequest | undefined;\n\t\tlet key: string | undefined;\n\t\tlet legacyRequest: PromptTemplateDelegationRequest | undefined;\n\n\t\tif (structuredPayload) {\n\t\t\tconst parsed = parseSubagentDelegationRequest(data);\n\t\t\tif (parsed.ok === false) {\n\t\t\t\tif (!disposed && parsed.requestId) {\n\t\t\t\t\tconst payload = {\n\t\t\t\t\t\trequestId: parsed.requestId,\n\t\t\t\t\t\t...(parsed.ownerRunId ? { ownerRunId: parsed.ownerRunId } : {}),\n\t\t\t\t\t\t...(parsed.nodeId ? { nodeId: parsed.nodeId } : {}),\n\t\t\t\t\t\tstatus: \"invalid_request\",\n\t\t\t\t\t\terror: parsed.error,\n\t\t\t\t\t} satisfies SubagentDelegationInvalidResponse;\n\t\t\t\t\tif (parsed.ownerRunId && parsed.nodeId) {\n\t\t\t\t\t\tconst attemptedKey = attemptKey(parsed.requestId, parsed.ownerRunId, parsed.nodeId);\n\t\t\t\t\t\tif (!attemptControllers.has(attemptedKey)) emitTerminal(attemptedKey, payload);\n\t\t\t\t\t} else {\n\t\t\t\t\t\toptions.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, payload);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstructuredRequest = parsed.request;\n\t\t\trequestId = parsed.request.requestId;\n\t\t\tkey = attemptKey(requestId, parsed.request.ownerRunId, parsed.request.nodeId);\n\t\t\tparams = toSubagentDelegationExecutionParams(parsed.request);\n\t\t} else {\n\t\t\tif (data && typeof data === \"object\" && !Array.isArray(data)) {\n\t\t\t\tconst legacy = data as Record<string, unknown>;\n\t\t\t\tif (\n\t\t\t\t\t(legacy.tasks !== undefined || legacy.worktree !== undefined) &&\n\t\t\t\t\ttypeof legacy.requestId === \"string\" &&\n\t\t\t\t\tlegacy.requestId\n\t\t\t\t) {\n\t\t\t\t\toptions.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {\n\t\t\t\t\t\trequestId: legacy.requestId,\n\t\t\t\t\t\tmessages: [],\n\t\t\t\t\t\tisError: true,\n\t\t\t\t\t\terrorText: \"Legacy prompt-template tasks/worktree orchestration was removed; use workflowScript.\",\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tlegacyRequest = parsePromptTemplateRequest(data);\n\t\t\tif (!legacyRequest) return;\n\t\t\toptions.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {\n\t\t\t\t...legacyRequest,\n\t\t\t\tmessages: [],\n\t\t\t\tisError: true,\n\t\t\t\terrorText:\n\t\t\t\t\t\"Legacy prompt-template direct delegation was removed; use workflowScript through the subagent tool or structured delegation.\",\n\t\t\t} satisfies PromptTemplateDelegationResponse);\n\t\t\treturn;\n\t\t}\n\n\t\tif (!structuredRequest && legacyControllers.has(requestId)) return;\n\t\tif (structuredRequest && key) {\n\t\t\tif (attemptControllers.has(key) || settledAttempts.has(key)) return;\n\t\t\tif (pendingAttemptCancels.delete(key)) {\n\t\t\t\temitTerminal(key, {\n\t\t\t\t\trequestId,\n\t\t\t\t\townerRunId: structuredRequest.ownerRunId,\n\t\t\t\t\tnodeId: structuredRequest.nodeId,\n\t\t\t\t\tstatus: \"cancelled\",\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (identitySaturated) {\n\t\t\t\toptions.events.emit(SUBAGENT_DELEGATION_RESPONSE_EVENT, {\n\t\t\t\t\trequestId,\n\t\t\t\t\townerRunId: structuredRequest.ownerRunId,\n\t\t\t\t\tnodeId: structuredRequest.nodeId,\n\t\t\t\t\tstatus: \"unavailable_context\",\n\t\t\t\t\terror: \"Delegation identity capacity is exhausted for this extension context.\",\n\t\t\t\t} satisfies SubagentDelegationResponse);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst active = activeOwnedNodes.get(nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId));\n\t\t\tif (active) {\n\t\t\t\temitTerminal(key, {\n\t\t\t\t\trequestId,\n\t\t\t\t\townerRunId: structuredRequest.ownerRunId,\n\t\t\t\t\tnodeId: structuredRequest.nodeId,\n\t\t\t\t\tstatus: \"duplicate_node\",\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tconst ctx = options.getContext();\n\t\tif (!ctx) {\n\t\t\tif (structuredRequest && key) {\n\t\t\t\temitTerminal(key, {\n\t\t\t\t\trequestId,\n\t\t\t\t\townerRunId: structuredRequest.ownerRunId,\n\t\t\t\t\tnodeId: structuredRequest.nodeId,\n\t\t\t\t\tstatus: \"unavailable_context\",\n\t\t\t\t\terror: \"No active extension context for delegated subagent execution.\",\n\t\t\t\t});\n\t\t\t} else if (legacyRequest) {\n\t\t\t\toptions.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {\n\t\t\t\t\t...legacyRequest,\n\t\t\t\t\tmessages: [],\n\t\t\t\t\tisError: true,\n\t\t\t\t\terrorText: \"No active extension context for delegated subagent execution.\",\n\t\t\t\t} satisfies PromptTemplateDelegationResponse);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst controller = new AbortController();\n\t\tif (structuredRequest && key) {\n\t\t\tattemptControllers.set(key, controller);\n\t\t\tactiveOwnedNodes.set(nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId), {\n\t\t\t\tattemptKey: key,\n\t\t\t\tcontroller,\n\t\t\t});\n\t\t} else {\n\t\t\tlegacyControllers.set(requestId, controller);\n\t\t\tif (pendingLegacyCancels.delete(requestId)) controller.abort();\n\t\t}\n\t\tif (controller.signal.aborted) {\n\t\t\tif (structuredRequest && key) {\n\t\t\t\temitTerminal(key, {\n\t\t\t\t\trequestId,\n\t\t\t\t\townerRunId: structuredRequest.ownerRunId,\n\t\t\t\t\tnodeId: structuredRequest.nodeId,\n\t\t\t\t\tstatus: \"cancelled\",\n\t\t\t\t});\n\t\t\t\tactiveOwnedNodes.delete(nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId));\n\t\t\t} else if (legacyRequest) {\n\t\t\t\toptions.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {\n\t\t\t\t\t...legacyRequest,\n\t\t\t\t\tmessages: [],\n\t\t\t\t\tisError: true,\n\t\t\t\t\terrorText: \"Delegated prompt cancelled.\",\n\t\t\t\t} satisfies PromptTemplateDelegationResponse);\n\t\t\t}\n\t\t\tif (key) attemptControllers.delete(key);\n\t\t\telse legacyControllers.delete(requestId);\n\t\t\treturn;\n\t\t}\n\n\t\toptions.events.emit(\n\t\t\tstructuredRequest ? SUBAGENT_DELEGATION_STARTED_EVENT : PROMPT_TEMPLATE_SUBAGENT_STARTED_EVENT,\n\t\t\tstructuredRequest\n\t\t\t\t? { requestId, ownerRunId: structuredRequest.ownerRunId, nodeId: structuredRequest.nodeId }\n\t\t\t\t: { requestId },\n\t\t);\n\n\t\ttry {\n\t\t\tconst executeRequest =\n\t\t\t\tstructuredRequest && options.executeStructured ? options.executeStructured : options.execute;\n\t\t\tconst result = await executeRequest(requestId, params, controller.signal, ctx, (update) => {\n\t\t\t\tif (key ? !ownsAttempt(key, controller) : !ownsLegacyRequest(requestId, controller)) return;\n\t\t\t\tif (structuredRequest) {\n\t\t\t\t\tconst payload = toSubagentDelegationUpdate(structuredRequest, update);\n\t\t\t\t\tif (payload) options.events.emit(SUBAGENT_DELEGATION_UPDATE_EVENT, payload);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst payload = toDelegationUpdate(requestId, update);\n\t\t\t\tif (payload) options.events.emit(PROMPT_TEMPLATE_SUBAGENT_UPDATE_EVENT, payload);\n\t\t\t});\n\t\t\tif (key ? !ownsAttempt(key, controller) : !ownsLegacyRequest(requestId, controller)) return;\n\t\t\tif (structuredRequest && key) {\n\t\t\t\temitTerminal(key, toSubagentDelegationResponse(structuredRequest, result, controller.signal.aborted));\n\t\t\t} else if (legacyRequest) {\n\t\t\t\toptions.events.emit(\n\t\t\t\t\tPROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT,\n\t\t\t\t\tcontroller.signal.aborted\n\t\t\t\t\t\t? { ...legacyRequest, messages: [], isError: true, errorText: \"Delegated prompt cancelled.\" }\n\t\t\t\t\t\t: toPromptTemplateResponse(legacyRequest, result),\n\t\t\t\t);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (key ? !ownsAttempt(key, controller) : !ownsLegacyRequest(requestId, controller)) return;\n\t\t\tif (structuredRequest && key) {\n\t\t\t\temitTerminal(key, {\n\t\t\t\t\trequestId,\n\t\t\t\t\townerRunId: structuredRequest.ownerRunId,\n\t\t\t\t\tnodeId: structuredRequest.nodeId,\n\t\t\t\t\tstatus: controller.signal.aborted ? \"cancelled\" : \"failed\",\n\t\t\t\t\t...(controller.signal.aborted ? {} : { error: error instanceof Error ? error.message : String(error) }),\n\t\t\t\t});\n\t\t\t} else if (legacyRequest) {\n\t\t\t\toptions.events.emit(PROMPT_TEMPLATE_SUBAGENT_RESPONSE_EVENT, {\n\t\t\t\t\t...legacyRequest,\n\t\t\t\t\tmessages: [],\n\t\t\t\t\tisError: true,\n\t\t\t\t\terrorText: error instanceof Error ? error.message : String(error),\n\t\t\t\t} satisfies PromptTemplateDelegationResponse);\n\t\t\t}\n\t\t} finally {\n\t\t\tif (key) {\n\t\t\t\tif (attemptControllers.get(key) === controller) attemptControllers.delete(key);\n\t\t\t} else if (legacyControllers.get(requestId) === controller) legacyControllers.delete(requestId);\n\t\t\tif (structuredRequest) {\n\t\t\t\tconst ownedNodeKey = nodeKey(structuredRequest.ownerRunId, structuredRequest.nodeId);\n\t\t\t\tif (activeOwnedNodes.get(ownedNodeKey)?.controller === controller) activeOwnedNodes.delete(ownedNodeKey);\n\t\t\t}\n\t\t}\n\t});\n\n\treturn {\n\t\tcancelAll: () => {\n\t\t\tfor (const controller of legacyControllers.values()) controller.abort();\n\t\t\tfor (const controller of attemptControllers.values()) controller.abort();\n\t\t\tlegacyControllers.clear();\n\t\t\tattemptControllers.clear();\n\t\t\tpendingLegacyCancels.clear();\n\t\t\tpendingAttemptCancels.clear();\n\t\t\tactiveOwnedNodes.clear();\n\t\t\tsettledAttempts.clear();\n\t\t\tidentitySaturated = false;\n\t\t},\n\t\tdispose: () => {\n\t\t\tdisposed = true;\n\t\t\tfor (const controller of legacyControllers.values()) controller.abort();\n\t\t\tfor (const controller of attemptControllers.values()) controller.abort();\n\t\t\tlegacyControllers.clear();\n\t\t\tattemptControllers.clear();\n\t\t\tfor (const unsubscribe of subscriptions) unsubscribe();\n\t\t\tsubscriptions.length = 0;\n\t\t\tpendingLegacyCancels.clear();\n\t\t\tpendingAttemptCancels.clear();\n\t\t\tactiveOwnedNodes.clear();\n\t\t\tsettledAttempts.clear();\n\t\t},\n\t};\n}\n"]}