@task-handoff/control-plane 0.0.23 → 0.0.25-alpha.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.
- package/dist/cli.js +2 -2
- package/package.json +2 -1
- package/ui/assets/{CodeBlockNode-DxQIKAda.js → CodeBlockNode-DMNmVaS-.js} +1 -1
- package/ui/assets/{Tooltip-BqNWbSAq.js → Tooltip-DZyWZK0a.js} +1 -1
- package/ui/assets/{abnfDiagram-VRR7QNED-BuM5vxND.js → abnfDiagram-VRR7QNED-DiuUPdDy.js} +1 -1
- package/ui/assets/{arc-BROse336.js → arc-iy-uMjIh.js} +1 -1
- package/ui/assets/{architectureDiagram-ZJ3FMSHR-C2K6piv9.js → architectureDiagram-ZJ3FMSHR-fH1YXTve.js} +1 -1
- package/ui/assets/{blockDiagram-677ZJIJ3-DsQs6BYv.js → blockDiagram-677ZJIJ3-CUP-UseI.js} +1 -1
- package/ui/assets/{c4Diagram-LMCZKHZV-BWS8x9_M.js → c4Diagram-LMCZKHZV-OkY763ZS.js} +1 -1
- package/ui/assets/channel-CNuMNAY9.js +1 -0
- package/ui/assets/{chunk-2Q5K7J3B-BhF8pB--.js → chunk-2Q5K7J3B-DaZOY24G.js} +1 -1
- package/ui/assets/{chunk-32BRIVSS-BIIvRKRB.js → chunk-32BRIVSS-CHh5Zcfu.js} +1 -1
- package/ui/assets/{chunk-5VM5RSS4-Bzd_y2Ds.js → chunk-5VM5RSS4-ClYSqISt.js} +1 -1
- package/ui/assets/{chunk-EX3LRPZG-CggXOIdI.js → chunk-EX3LRPZG-D73zvDym.js} +1 -1
- package/ui/assets/{chunk-JWPE2WC7-BlVK6a0F.js → chunk-JWPE2WC7-DDLdIrh1.js} +1 -1
- package/ui/assets/{chunk-MOJQB5TN-sZDWuXQs.js → chunk-MOJQB5TN-CKtpvi8I.js} +1 -1
- package/ui/assets/{chunk-RYQCIY6F-CYbLbn_F.js → chunk-RYQCIY6F-hZyuYg-3.js} +1 -1
- package/ui/assets/{chunk-V7JOEXUC-BHERvBFw.js → chunk-V7JOEXUC-D8fG9j0h.js} +1 -1
- package/ui/assets/{chunk-VR4S4FIN-B-htAI9H.js → chunk-VR4S4FIN-DVTEukOd.js} +1 -1
- package/ui/assets/{chunk-XXDRQBXY-DdptYhPq.js → chunk-XXDRQBXY-CHxdETIk.js} +1 -1
- package/ui/assets/classDiagram-OUVF2IWQ-a1fOfsUa.js +1 -0
- package/ui/assets/classDiagram-v2-EOCWNBFH-a1fOfsUa.js +1 -0
- package/ui/assets/{cose-bilkent-JH36ORCC-UHFtMEBv.js → cose-bilkent-JH36ORCC-BqR8G2tM.js} +1 -1
- package/ui/assets/{cynefin-VYW2F7L2-D-Cl09c-.js → cynefin-VYW2F7L2-BQMGSBdL.js} +1 -1
- package/ui/assets/{cynefinDiagram-TSTJHNR4-1qR0-Y00.js → cynefinDiagram-TSTJHNR4-dPnVTIYQ.js} +1 -1
- package/ui/assets/{dagre-VKFMJZFB-DNGKqu_E.js → dagre-VKFMJZFB-CObIWACA.js} +1 -1
- package/ui/assets/{diagram-FQU43EPY-DN78tjXn.js → diagram-FQU43EPY-CptcyYFA.js} +1 -1
- package/ui/assets/{diagram-G47NLZAW-BLL5djPy.js → diagram-G47NLZAW-DnEgng1Z.js} +1 -1
- package/ui/assets/{diagram-NH7WQ7WH-B1Oszng2.js → diagram-NH7WQ7WH-C4l1EwjW.js} +1 -1
- package/ui/assets/{diagram-OA4YK3LP-BOgfq-e0.js → diagram-OA4YK3LP-CFnkuuyK.js} +1 -1
- package/ui/assets/{diagram-WEI45ONY-BdqZvM5e.js → diagram-WEI45ONY-BeA9BqW_.js} +1 -1
- package/ui/assets/{ebnfDiagram-CCIWWBDH-DTGYwAUi.js → ebnfDiagram-CCIWWBDH-BU15l6cV.js} +1 -1
- package/ui/assets/{erDiagram-Q63AITRT-h6v6Saa7.js → erDiagram-Q63AITRT-52axU4Nb.js} +1 -1
- package/ui/assets/{flowDiagram-23GEKE2U-CkQBKJmc.js → flowDiagram-23GEKE2U-Bz9QoNVE.js} +1 -1
- package/ui/assets/{ganttDiagram-NO4QXBWP-DV7e1TU1.js → ganttDiagram-NO4QXBWP-B6MdugqO.js} +1 -1
- package/ui/assets/{gitGraphDiagram-IHSO6WYX-CxFS8a4w.js → gitGraphDiagram-IHSO6WYX-BrIeR_4e.js} +1 -1
- package/ui/assets/index-6f64o_Rb.css +1 -0
- package/ui/assets/index-BF292pGR.js +624 -0
- package/ui/assets/{index10-DXtzGjee.js → index10-DS28X48Q.js} +1 -1
- package/ui/assets/{index11-ChvX-qYp.js → index11-87XM357U.js} +1 -1
- package/ui/assets/{index5-81LqVmSI.js → index5-40v4FujQ.js} +1 -1
- package/ui/assets/{index6-VUdIGVI6.js → index6-gYVM-nAp.js} +1 -1
- package/ui/assets/{index7-BmKPoGUF.js → index7-L_rPLUsN.js} +1 -1
- package/ui/assets/{index8-Boc9TyRX.js → index8-B56tJ-t0.js} +1 -1
- package/ui/assets/{infoDiagram-FWYZ7A6U-kricERAW.js → infoDiagram-FWYZ7A6U-BNHiKY0o.js} +1 -1
- package/ui/assets/{ishikawaDiagram-FXEZZL3T-DCtlnwAt.js → ishikawaDiagram-FXEZZL3T-bUVKNQot.js} +1 -1
- package/ui/assets/{journeyDiagram-5HDEW3XC-Dpnn1ZGd.js → journeyDiagram-5HDEW3XC-BmkHXVvf.js} +1 -1
- package/ui/assets/{kanban-definition-HUTT4EX6-DVqIkmAs.js → kanban-definition-HUTT4EX6-DiW9L9Sx.js} +1 -1
- package/ui/assets/{linear-DaYXigF0.js → linear-DDhYA9Dw.js} +1 -1
- package/ui/assets/{mermaid.core-FF00iLlQ.js → mermaid.core-BCs5qzbM.js} +4 -4
- package/ui/assets/{mhchem-BNqRF38u.js → mhchem-DK_ZuO0a.js} +1 -1
- package/ui/assets/{mindmap-definition-LN4V7U3C-D5wMMfFX.js → mindmap-definition-LN4V7U3C-B8-XLfqf.js} +1 -1
- package/ui/assets/{pegDiagram-2B236MQR-BJeT7qlG.js → pegDiagram-2B236MQR-CMkx1m4Z.js} +1 -1
- package/ui/assets/{pieDiagram-ENE6RG2P-C48oXHKY.js → pieDiagram-ENE6RG2P-Bd4uFh7q.js} +1 -1
- package/ui/assets/{quadrantDiagram-ABIIQ3AL-DQMWlaTM.js → quadrantDiagram-ABIIQ3AL-D4870MVY.js} +1 -1
- package/ui/assets/{railroadDiagram-RFXS5EU6-C8wvs97U.js → railroadDiagram-RFXS5EU6-CfEDmzQ4.js} +1 -1
- package/ui/assets/{requirementDiagram-TGXJPOKE-Dv7FUR3_.js → requirementDiagram-TGXJPOKE-qYyKCbUd.js} +1 -1
- package/ui/assets/{sankeyDiagram-HTMAVEWB-BrTOFoG8.js → sankeyDiagram-HTMAVEWB-DjIsF9ms.js} +1 -1
- package/ui/assets/{sequenceDiagram-DBY2YBRQ-MG0o6ikU.js → sequenceDiagram-DBY2YBRQ-ZU_b0vV1.js} +1 -1
- package/ui/assets/{sizeCapture-X5ZJPWSS-CBh0uc68.js → sizeCapture-X5ZJPWSS-GCwK4-M0.js} +1 -1
- package/ui/assets/{stateDiagram-2N3HPSRC-F3vW6gcv.js → stateDiagram-2N3HPSRC-CtKtKDwD.js} +1 -1
- package/ui/assets/stateDiagram-v2-6OUMAXLB-IOAnDy98.js +1 -0
- package/ui/assets/{swimlanes-5IMT3BWC-BPrQuiIh.js → swimlanes-5IMT3BWC-CNROjJb_.js} +2 -2
- package/ui/assets/swimlanesDiagram-G3AALYLV-CKsdTRWh.js +8 -0
- package/ui/assets/{timeline-definition-FHXFAJF6-BZj0BO-H.js → timeline-definition-FHXFAJF6-6nhCW0Fy.js} +1 -1
- package/ui/assets/{vennDiagram-L72KCM5P-BmZYnaOV.js → vennDiagram-L72KCM5P-CnV8KBME.js} +1 -1
- package/ui/assets/{wardleyDiagram-EHGQE667-D3zi0Iet.js → wardleyDiagram-EHGQE667-DxMGDt6l.js} +1 -1
- package/ui/assets/{xychartDiagram-FW5EYKEG-DBGaNv8m.js → xychartDiagram-FW5EYKEG-5ChFdnhl.js} +1 -1
- package/ui/index.html +2 -2
- package/ui/assets/channel-Bz97ttq-.js +0 -1
- package/ui/assets/classDiagram-OUVF2IWQ-DaZrxeb9.js +0 -1
- package/ui/assets/classDiagram-v2-EOCWNBFH-DaZrxeb9.js +0 -1
- package/ui/assets/index-Bg63dXT3.js +0 -624
- package/ui/assets/index-CRGIhcZ1.css +0 -1
- package/ui/assets/stateDiagram-v2-6OUMAXLB-CNwQ7fW7.js +0 -1
- package/ui/assets/swimlanesDiagram-G3AALYLV-B0rX6ey_.js +0 -8
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";var e=require("commander"),t=require("node:path"),n=require("node:fs"),i=require("node:crypto"),s=require("fastify"),r=require("@fastify/cookie"),o=require("@fastify/websocket"),a=require("zod"),d=require("node:util"),c=require("write-file-atomic"),l=require("ws"),p=require("node:http"),u=require("node:net"),m=require("node:stream"),g=require("telegramify-markdown"),h=require("node:fs/promises"),y=require("node:os"),f=require("dingtalk-stream"),I=require("@larksuiteoapi/node-sdk"),b=require("node:child_process"),v=require("tar"),w=require("tweetnacl");function S(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(n){if("default"!==n){var i=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,i.get?i:{enumerable:!0,get:function(){return e[n]}})}}),t.default=e,Object.freeze(t)}var A=S(v);function k(e,t){try{const i=JSON.parse(n.readFileSync(e,"utf8"));if(t&&i.name!==t)return;return"string"==typeof i.version&&i.version.trim()?i.version.trim():void 0}catch{return}}function z(e){if(e)try{return t.dirname(n.realpathSync(e))}catch{return}}function T(e,n=process.env,i=e){const s=n.TASK_HANDOFF_VERSION?.trim();if(s)return s;const r=i.split("/").at(-1),o=process.argv[1]?t.resolve(process.argv[1]):void 0,a=o?t.dirname(o):void 0,d=[z(o),a,process.cwd()].filter(e=>Boolean(e));for(const n of new Set(d)){let i=n;for(;;){const n=k(t.join(i,"package.json"),e);if(n)return n;const s=t.dirname(i);if(s===i)break;i=s}}let c;for(const e of new Set(d)){let n=e;for(;;){if(r){const e=k(t.join(n,"packages",r,"package.json"),i);if(e)return e}c||=k(t.join(n,"package.json"));const e=t.dirname(n);if(e===n)break;n=e}}return c||"unknown"}const E=20971520,C=512e3,x=41943040,N="ai-session.snapshot",O="ai-session.patch",_="ai-session.removed",R="ai-session.message-delta",P="ai-session.timeline-item",j="ai-session.unread.updated",D=a.z.string().trim().min(1).max(80),M=a.z.enum(["app-session","ai-session"]),L=a.z.enum(["running","waiting","idle","failed"]),q=a.z.object({instanceId:a.z.string().trim().min(1).max(160),sessionId:a.z.string().trim().min(1).max(120),unread:a.z.boolean(),sessionUpdatedAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),$=a.z.enum(["thinking","tool","editing","approval","responding","unknown"]),B=a.z.object({id:a.z.string().trim().min(1).max(240).optional(),kind:a.z.string().trim().min(1).max(80).optional(),name:a.z.string().trim().min(1).max(120),inputPreview:a.z.string().trim().max(500).optional(),startedAt:a.z.string().datetime().optional()}).strict(),U=a.z.enum(["running","completed","failed","waiting"]),F=a.z.object({id:a.z.string().trim().min(1).max(240),turnId:a.z.string().trim().min(1).max(240)}).strict(),H=F.extend({type:a.z.literal("user-message"),text:a.z.string()}).strict(),W=F.extend({type:a.z.literal("ai-message"),text:a.z.string()}).strict(),G=F.extend({type:a.z.literal("activity"),activityKind:a.z.string().trim().min(1).max(120),title:a.z.string().trim().min(1).max(240),status:U.optional(),summary:a.z.string().max(4e3).optional(),input:a.z.string().max(1e5).optional(),output:a.z.string().max(1e6).optional(),paths:a.z.array(a.z.string().trim().min(1).max(4096)).max(500).optional(),exitCode:a.z.number().int().optional(),durationMs:a.z.number().int().nonnegative().optional()}).strict(),V=a.z.discriminatedUnion("type",[H,W,G]),K=a.z.object({sessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),items:a.z.array(V),generatedAt:a.z.string().datetime()}).strict(),J=a.z.object({sessionId:a.z.string().trim().min(1).max(120),turnId:a.z.string().trim().min(1).max(240),items:a.z.array(V),generatedAt:a.z.string().datetime()}).strict(),Y=a.z.enum(["pending-init","running","interrupted","completed","errored","shutdown","not-found"]),Q=a.z.enum(["started","interacted","interrupted"]),X=a.z.object({threadId:a.z.string().trim().min(1).max(240),path:a.z.string().trim().max(4096).optional(),status:Y,activity:Q.optional(),message:a.z.string().trim().max(1e3).optional(),updatedAt:a.z.string().datetime()}).strict(),Z=a.z.object({toolCalls:a.z.number().int().min(0).default(0),edits:a.z.number().int().min(0).default(0),approvals:a.z.number().int().min(0).default(0)}).strict().default({toolCalls:0,edits:0,approvals:0}),ee=a.z.object({send:a.z.boolean().optional(),interrupt:a.z.boolean().optional(),approval:a.z.boolean().optional(),fork:a.z.boolean().optional(),openApp:a.z.boolean().optional(),close:a.z.boolean().optional()}).strict(),te=a.z.object({kind:a.z.literal("fork"),parentProviderSessionId:a.z.string().trim().min(1).max(240),throughTurnId:a.z.string().trim().min(1).max(240).optional()}).strict(),ne=a.z.enum(["image","file"]),ie=a.z.object({id:a.z.string().trim().min(1).max(120),kind:ne,name:a.z.string().trim().min(1).max(240),mime:a.z.string().trim().min(1).max(120),size:a.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER)}),se=a.z.union([ie.extend({source:a.z.object({type:a.z.literal("inline"),encoding:a.z.literal("base64"),data:a.z.string().min(1).max(31457280)}).strict()}).strict().superRefine((e,t)=>{const n="image"===e.kind?E:C;(e.size<=0||("file"===e.kind?e.size>=n:e.size>n))&&t.addIssue({code:a.z.ZodIssueCode.custom,path:["size"],message:`Inline ${e.kind} must be between 1 byte and ${n} bytes.`})}),ie.extend({source:a.z.object({type:a.z.literal("runtime-path"),path:a.z.string().trim().min(1).max(4096)}).strict()}).strict()]),re=ie.extend({sourceType:a.z.enum(["inline","runtime-path"])}).strict(),oe=a.z.union([a.z.object({id:a.z.string().trim().min(1).max(120),kind:ne.optional(),source:a.z.object({type:a.z.literal("upload-ref")}).strict().default({type:"upload-ref"})}).strict(),a.z.object({id:a.z.string().trim().min(1).max(120),kind:ne,name:a.z.string().trim().min(1).max(240),mime:a.z.string().trim().min(1).max(120),size:a.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),source:a.z.object({type:a.z.literal("runtime-path"),path:a.z.string().trim().min(1).max(4096)}).strict()}).strict()]),ae=a.z.enum(["auto","queue","steer","immediate"]),de=a.z.enum(["ask","auto-review","full-access"]),ce=a.z.enum(["review","rename","goal","compact"]),le=a.z.object({command:ce,argument:a.z.string().trim().max(4e3).optional()}).strict().superRefine((e,t)=>{"rename"!==e.command||e.argument||t.addIssue({code:"custom",path:["argument"],message:"Rename requires a thread name."}),"review"!==e.command&&"compact"!==e.command||!e.argument||t.addIssue({code:"custom",path:["argument"],message:`${e.command} does not accept an argument.`})}),pe=a.z.object({command:ce,value:a.z.string().max(4e3).optional(),turnId:a.z.string().trim().min(1).max(240).optional()}).strict();a.z.enum(["skill","app","plugin"]);const ue=a.z.object({name:a.z.string().trim().min(1).max(240),path:a.z.string().trim().min(1).max(4096)}),me=a.z.discriminatedUnion("kind",[ue.extend({kind:a.z.literal("skill"),path:a.z.string().trim().min(1).max(4096).refine(e=>e.startsWith("/"),"Skill paths must be absolute.")}).strict(),ue.extend({kind:a.z.literal("app"),path:a.z.string().trim().min(7).max(4096).regex(/^app:\/\/[^\s/]+$/,"App paths must use app://<id>.")}).strict(),ue.extend({kind:a.z.literal("plugin"),path:a.z.string().trim().min(10).max(4096).regex(/^plugin:\/\/[^\s/]+$/,"Plugin paths must use plugin://<id>.")}).strict()]),ge=a.z.array(me).max(20).default([]),he=a.z.enum(["plugin","skill","file","directory","app"]),ye=a.z.object({kind:he,name:a.z.string().trim().min(1).max(240),description:a.z.string().trim().max(1e3).optional(),path:a.z.string().trim().min(1).max(4096),icon:a.z.string().trim().max(4096).optional()}).strict().superRefine((e,t)=>{"skill"!==e.kind||e.path.startsWith("/")||t.addIssue({code:"custom",path:["path"],message:"Skill paths must be absolute."}),"app"!==e.kind||/^app:\/\/[^\s/]+$/.test(e.path)||t.addIssue({code:"custom",path:["path"],message:"App paths must use app://<id>."}),"plugin"!==e.kind||/^plugin:\/\/[^\s/]+$/.test(e.path)||t.addIssue({code:"custom",path:["path"],message:"Plugin paths must use plugin://<id>."}),"file"!==e.kind&&"directory"!==e.kind||!e.path.startsWith("/")&&!e.path.split(/[\\/]+/).includes("..")||t.addIssue({code:"custom",path:["path"],message:"File and directory paths must be relative to the session cwd."})}),fe=a.z.object({category:a.z.enum(["skills","plugins","apps","files"]),code:a.z.string().trim().min(1).max(160),message:a.z.string().trim().min(1).max(2e3)}).strict(),Ie=a.z.object({sessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),cwd:a.z.string().trim().min(1).max(4096),candidates:a.z.array(ye).max(1e3).default([]),diagnostics:a.z.array(fe).max(20).default([])}).strict(),be=a.z.object({query:a.z.string().trim().max(240).default("")}).strict(),ve=a.z.object({sessionId:a.z.string().trim().min(1).max(120),cwd:a.z.string().trim().min(1).max(4096),query:a.z.string().trim().max(240),requestId:a.z.string().trim().min(1).max(160),candidates:a.z.array(ye.refine(e=>"file"===e.kind||"directory"===e.kind,"File search only returns files and directories.")).max(200).default([]),complete:a.z.boolean().default(!1)}).strict(),we=a.z.object({message:a.z.string().trim().min(1).max(2e4),mode:ae.optional(),permissionMode:de.optional()}),Se=we.extend({attachments:a.z.array(se).max(6).default([]),references:ge}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>x&&t.addIssue({code:a.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),Ae=we.extend({attachments:a.z.array(oe).max(6).default([]),references:ge}).strict(),ke=a.z.object({type:a.z.literal("runtime-path"),path:a.z.string().trim().min(1).max(4096).refine(e=>e.startsWith("/")||/^[A-Za-z]:[\\/]/.test(e),"Runtime paths must be absolute in the target controlled instance.")}).strict(),ze=Se.extend({agent:D,cwd:ke,cwdFolderId:a.z.string().trim().min(1).max(120).optional(),clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),Te=a.z.object({mode:a.z.enum(["current-folder","worktree"]),branch:a.z.string().trim().min(1).max(1024)}).strict(),Ee=Ae.extend({agent:D,cwdFolderId:a.z.string().trim().min(1).max(120).optional(),gitSelection:Te.optional(),clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),Ce=a.z.object({disposition:a.z.enum(["created","already-created"]),aiSessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),creationSource:a.z.literal("ai-session")}).strict(),xe=a.z.object({mode:a.z.enum(["current","managed-worktree"]).default("current")}).strict().default({mode:"current"}),Ne=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160),throughTurnId:a.z.string().trim().min(1).max(240).optional(),workspace:xe.optional().default({mode:"current"})}).strict(),Oe=a.z.object({disposition:a.z.enum(["created","already-created"]),aiSessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),creationSource:a.z.literal("ai-session")}).strict(),_e=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),Re=a.z.object({disposition:a.z.enum(["opened","already-open"]),aiSessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),appSessionId:a.z.string().trim().min(1).max(120),creationSource:M}).strict(),Pe=a.z.object({clientRequestId:a.z.string().trim().min(1).max(160)}).strict(),je=a.z.object({disposition:a.z.enum(["closed","already-closed"]),aiSessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),creationSource:M}).strict();a.z.object({code:a.z.enum(["invalid-request","not-found","unsupported","provider-unavailable","materialization-failed","open-app-failed","close-failed","conflict"]),message:a.z.string().trim().min(1).max(4e3),retryable:a.z.boolean().default(!1),aiSessionId:a.z.string().trim().min(1).max(120).optional(),providerSessionId:a.z.string().trim().min(1).max(240).optional()}).strict();const De=a.z.object({decision:a.z.enum(["allow","deny","skip"])}).strict(),Me=a.z.object({expectedRevision:a.z.number().int().min(0),queueIds:a.z.array(a.z.string().trim().min(1).max(120)).max(100)}).strict(),Le=a.z.object({expectedRevision:a.z.number().int().min(0),message:a.z.string().trim().min(1).max(2e4)}).strict();a.z.object({code:a.z.string().trim().min(1).max(160),message:a.z.string(),instanceId:a.z.string().trim().min(1).max(160).optional(),nodeId:a.z.string().trim().min(1).max(160).optional(),route:a.z.string().trim().min(1).max(4096).optional()}).strict();const qe=a.z.object({id:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2e4),attachments:a.z.array(re).max(6).default([]),references:ge,permissionMode:de.optional(),status:a.z.enum(["queued","sending","failed"]).default("queued"),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime(),error:a.z.string().trim().max(4e3).optional()}).strict(),$e=a.z.object({revision:a.z.number().int().min(0).default(0),pendingCount:a.z.number().int().min(0).default(0),items:a.z.array(qe).max(100).default([])}).strict().default({revision:0,pendingCount:0,items:[]}),Be=a.z.enum(["control","realtime","adapter-snapshot","transcript-tail","transcript-scan","process-scan","app-session"]),Ue=a.z.object({id:a.z.string().trim().min(1).max(240),status:a.z.enum(["running","completed"]),startedAt:a.z.string().datetime().optional(),completedAt:a.z.string().datetime().optional()}).strict(),Fe=a.z.object({id:a.z.string().trim().min(1).max(240),providerTurnId:a.z.string().trim().max(240).optional(),source:Be.optional(),userPrompt:a.z.string().trim().optional(),status:a.z.enum(["queued","running","waiting","completed","failed"]).default("running"),phase:$.optional(),summary:a.z.string().trim().max(1e3).optional(),lastMessage:a.z.string().trim().optional(),lastMessageItemId:a.z.string().trim().max(240).optional(),contextCompactions:a.z.array(Ue).max(20).optional(),revision:a.z.number().int().min(0).default(0),sourcePriority:a.z.number().int().min(0).max(100).optional(),snapshotVersion:a.z.number().int().min(0).optional(),observedAt:a.z.string().datetime().optional(),startedAt:a.z.string().datetime().optional(),updatedAt:a.z.string().datetime().optional(),completedAt:a.z.string().datetime().optional()}).strict(),He=Fe.pick({id:!0,providerTurnId:!0,userPrompt:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,contextCompactions:!0,startedAt:!0,updatedAt:!0,completedAt:!0}).strict(),We=a.z.object({id:a.z.string().trim().min(1).max(120),agent:D,creationSource:M.default("app-session"),appSessionId:a.z.string().trim().max(120).optional(),appId:a.z.string().trim().max(120).optional(),providerSessionId:a.z.string().trim().max(240).optional(),lineage:te.optional(),providerMeta:a.z.record(a.z.string(),a.z.unknown()).optional(),appBindingKeys:a.z.array(a.z.string().trim().min(1).max(240)).max(20).optional(),actions:ee.optional(),activeTurnId:a.z.string().trim().max(240).optional(),title:a.z.string().trim().max(240).optional(),cwd:a.z.string().trim().max(4096).optional(),cwdFolderId:a.z.string().trim().min(1).max(120).optional(),userPrompt:a.z.string().trim().optional(),turns:a.z.array(Fe).max(50).optional(),status:L.default("running"),phase:$.default("unknown"),summary:a.z.string().trim().max(1e3).optional(),lastMessage:a.z.string().trim().optional(),lastMessageItemId:a.z.string().trim().max(240).optional(),currentTool:B.optional(),toolCallsSinceLastMessage:a.z.number().int().min(0).default(0),subAgents:a.z.array(X).max(50).default([]),transcriptPath:a.z.string().trim().max(4096).optional(),transcriptSize:a.z.number().int().min(0).optional(),startedAt:a.z.string().datetime(),updatedAt:a.z.string().datetime(),completedAt:a.z.string().datetime().optional(),error:a.z.string().trim().max(4e3).optional(),counters:Z,queue:$e}).strict(),Ge=a.z.object({session:We,provider:a.z.string().trim().min(1).max(80),action:a.z.enum(["send","queue","steer","interrupt","approval"]),decision:a.z.enum(["allow","deny","skip"]).optional(),turnId:a.z.string().trim().min(1).max(240).optional(),providerTurnId:a.z.string().trim().min(1).max(240).optional(),queueId:a.z.string().trim().min(1).max(120).optional()}).strict(),Ve=500,Ke=a.z.object({id:a.z.string().trim().min(1).max(120),agent:a.z.enum(["codex","claude"]),creationSource:M,providerSessionId:a.z.string().trim().min(1).max(240),lineage:te.optional(),title:a.z.string().trim().max(240).optional(),userPrompt:a.z.string().trim().optional(),lastMessage:a.z.string().trim().optional(),cwd:a.z.string().trim().min(1).max(4096),cwdFolderId:a.z.string().trim().min(1).max(120).optional(),lastActiveAt:a.z.string().datetime(),archivedAt:a.z.string().datetime()}).strict();a.z.object({schemaVersion:a.z.literal(1).default(1),items:a.z.array(Ke).max(Ve).default([])}).strict();const Je=a.z.object({items:a.z.array(Ke).max(Ve).default([])}).strict(),Ye=a.z.object({item:Ke,turns:a.z.array(He).max(50).default([])}).strict(),Qe=a.z.object({disposition:a.z.enum(["resumed","already-open"]),aiSessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),appSessionId:a.z.string().trim().min(1).max(120).optional(),creationSource:M}).strict(),Xe=We.pick({id:!0,agent:!0,creationSource:!0,appSessionId:!0,appId:!0,providerSessionId:!0,lineage:!0,providerMeta:!0,appBindingKeys:!0,actions:!0,activeTurnId:!0,title:!0,cwd:!0,cwdFolderId:!0,userPrompt:!0,turns:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,lastMessageItemId:!0,currentTool:!0,toolCallsSinceLastMessage:!0,subAgents:!0,queue:!0,startedAt:!0,updatedAt:!0,error:!0}),Ze=a.z.object({runningCount:a.z.number().int().min(0).default(0),waitingCount:a.z.number().int().min(0).default(0),staleCount:a.z.number().int().min(0).default(0),sessions:a.z.array(Xe).default([]),updatedAt:a.z.string().datetime()}).strict(),et=a.z.object({streamId:a.z.string().trim().min(1).max(240),revision:a.z.number().int().min(0),lastEventAt:a.z.string().datetime(),snapshot:Ze}).strict(),tt=Ze.pick({runningCount:!0,waitingCount:!0,staleCount:!0,updatedAt:!0}).extend({idleCount:a.z.number().int().min(0).default(0),problemCount:a.z.number().int().min(0).default(0),revision:a.z.number().int().min(0).optional()});function nt(e,t={}){const n=e.sessions.filter(e=>"idle"===e.status).length,i=e.sessions.filter(e=>"failed"===e.status).length;return tt.parse({runningCount:e.runningCount,waitingCount:e.waitingCount,staleCount:e.staleCount,idleCount:n,problemCount:i,updatedAt:e.updatedAt,revision:t.revision})}const it=a.z.enum(["provider-event","app-session-created","app-session-updated","app-session-deleted","discovery-scan","control-action","heartbeat-sync","startup"]),st=a.z.object({streamId:a.z.string().trim().min(1).max(240),instanceId:a.z.string().trim().min(1).max(160),nodeId:a.z.string().trim().min(1).max(160).optional(),revision:a.z.number().int().min(0),previousRevision:a.z.number().int().min(0).optional(),traceId:a.z.string().trim().min(1).max(160),generatedAt:a.z.string().datetime(),reason:it}).strict(),rt=a.z.object({meta:st,snapshot:Ze}).strict(),ot=a.z.object({meta:st,upserted:a.z.array(Xe).default([]),removed:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),at=a.z.object({meta:st,sessionIds:a.z.array(a.z.string().trim().min(1).max(120)).default([]),expiresAt:a.z.string().datetime()}).strict(),dt=a.z.object({instanceId:a.z.string().trim().min(1).max(160),nodeId:a.z.string().trim().min(1).max(160).optional(),sessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),turnId:a.z.string().trim().min(1).max(240),itemId:a.z.string().trim().min(1).max(240),delta:a.z.string().min(1),generatedAt:a.z.string().datetime()}).strict(),ct=a.z.object({instanceId:a.z.string().trim().min(1).max(160),nodeId:a.z.string().trim().min(1).max(160).optional(),sessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().min(1).max(240),item:V,generatedAt:a.z.string().datetime()}).strict(),lt=a.z.object({streamId:a.z.string().trim().min(1).max(240),instanceId:a.z.string().trim().min(1).max(160),sinceRevision:a.z.number().int().min(0),latestRevision:a.z.number().int().min(0),earliestRetainedRevision:a.z.number().int().min(0),syncRequired:a.z.boolean().default(!1),events:a.z.array(a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal(N),payload:rt}).strict(),a.z.object({type:a.z.literal(O),payload:ot}).strict(),a.z.object({type:a.z.literal(_),payload:at}).strict()])).default([])}).strict(),pt=a.z.object({source:Be,sourcePriority:a.z.number().int().min(0).max(100).optional(),observedAt:a.z.string().datetime().optional(),snapshotVersion:a.z.number().int().min(0).optional()}).strict(),ut=pt.extend({type:a.z.literal("snapshot"),agent:a.z.string().trim().min(1).max(80),creationSource:M.optional(),appSessionId:a.z.string().trim().max(120).optional(),appId:a.z.string().trim().max(120).optional(),providerSessionId:a.z.string().trim().max(240).optional(),lineage:te.optional(),providerMeta:a.z.record(a.z.string(),a.z.unknown()).optional(),appBindingKeys:a.z.array(a.z.string().trim().min(1).max(240)).max(20).optional(),actions:ee.optional(),title:a.z.string().trim().max(240).optional(),cwd:a.z.string().trim().max(4096).optional(),cwdFolderId:a.z.string().trim().min(1).max(120).optional(),activeTurnId:a.z.string().trim().max(240).optional(),userPrompt:a.z.string().trim().optional(),turns:a.z.array(Fe).max(50).optional(),status:L.optional(),phase:$.optional(),summary:a.z.string().trim().max(1e3).optional(),lastMessage:a.z.string().trim().optional(),lastMessageItemId:a.z.string().trim().max(240).optional(),error:a.z.string().trim().max(4e3).optional(),currentTool:B.optional(),toolCallsSinceLastMessage:a.z.number().int().min(0).optional(),subAgents:a.z.array(X).max(50).optional(),transcriptPath:a.z.string().trim().max(4096).optional(),transcriptSize:a.z.number().int().min(0).optional(),replaceActivity:a.z.boolean().optional()}).strict(),mt=pt.extend({type:a.z.literal("event"),sessionId:a.z.string().trim().min(1).max(120),kind:a.z.enum(["lifecycle","send-ack","turn-started","user-message","assistant-message","approval-requested","turn-completed","session-error","tool-activity","sub-agent-activity","context-compaction"]),activeTurnId:a.z.string().trim().max(240).optional(),providerTurnId:a.z.string().trim().max(240).optional(),userPrompt:a.z.string().trim().optional(),text:a.z.string().optional(),itemId:a.z.string().trim().max(240).optional(),status:L.optional(),phase:$.optional(),summary:a.z.string().trim().max(1e3).optional(),error:a.z.string().trim().max(4e3).optional(),currentTool:B.nullable().optional(),toolCallsSinceLastMessage:a.z.number().int().min(0).optional(),subAgents:a.z.array(X).max(50).optional(),contextCompaction:Ue.optional(),counters:a.z.object({toolCalls:a.z.number().int().min(0).optional(),edits:a.z.number().int().min(0).optional(),approvals:a.z.number().int().min(0).optional()}).strict().optional()}).strict().superRefine((e,t)=>{if("session-error"!==e.kind||e.error||t.addIssue({code:"custom",path:["error"],message:"session-error events require error"}),"context-compaction"===e.kind?e.contextCompaction||t.addIssue({code:"custom",path:["contextCompaction"],message:"context-compaction events require contextCompaction"}):void 0!==e.contextCompaction&&t.addIssue({code:"custom",path:["contextCompaction"],message:"contextCompaction is only valid for context-compaction events"}),"sub-agent-activity"===e.kind?e.subAgents||t.addIssue({code:"custom",path:["subAgents"],message:"sub-agent-activity events require subAgents"}):void 0!==e.subAgents&&t.addIssue({code:"custom",path:["subAgents"],message:"subAgents is only valid for sub-agent-activity events"}),"tool-activity"!==e.kind)return void 0!==e.currentTool&&t.addIssue({code:"custom",path:["currentTool"],message:"currentTool is only valid for tool-activity events"}),void(void 0!==e.toolCallsSinceLastMessage&&t.addIssue({code:"custom",path:["toolCallsSinceLastMessage"],message:"toolCallsSinceLastMessage is only valid for tool-activity events"}));"currentTool"in e||t.addIssue({code:"custom",path:["currentTool"],message:"tool-activity events require currentTool"}),void 0===e.toolCallsSinceLastMessage&&t.addIssue({code:"custom",path:["toolCallsSinceLastMessage"],message:"tool-activity events require toolCallsSinceLastMessage"})});a.z.discriminatedUnion("type",[ut,mt]);const gt=a.z.object({type:a.z.literal("snapshot"),data:a.z.string(),pendingEscape:a.z.string(),cols:a.z.number().int().positive(),rows:a.z.number().int().positive()}).passthrough(),ht="app-session.snapshot",yt="app-session.patch",ft="app-session.removed",It=a.z.enum(["created","starting","running","stopping","stopped","exited","failed","closed","terminated","unknown"]),bt=a.z.enum(["tty","vnc","web"]);a.z.object({mode:bt,url:a.z.string().trim().min(1).max(4096),token:a.z.string().trim().min(1).max(512),expiresAt:a.z.string().datetime()}).strict(),a.z.object({revoked:a.z.boolean()}).strict();const vt=new Set(["stopped","failed","exited","closed","terminated"]),wt=a.z.object({type:a.z.enum(["app-session","provider-session","adapter-key"]),id:a.z.string().trim().min(1).max(240),agent:a.z.string().trim().min(1).max(80).optional(),adapter:a.z.string().trim().min(1).max(80).optional(),key:a.z.string().trim().min(1).max(240).optional()}).strict(),St=a.z.record(a.z.string(),a.z.unknown()).and(a.z.object({id:a.z.string().trim().min(1).max(160),appId:a.z.string().trim().min(1).max(160).optional(),title:a.z.string().trim().max(240).optional(),kind:a.z.string().trim().max(80).optional(),status:It.default("unknown"),bindings:a.z.array(wt).max(40).default([]),workspace:a.z.object({cwd:a.z.string().trim().max(4096).optional()}).strict().optional(),createdAt:a.z.string().datetime().optional(),updatedAt:a.z.string().datetime().optional()})),At=a.z.object({runningCount:a.z.number().int().min(0).default(0),problemCount:a.z.number().int().min(0).default(0),sessions:a.z.array(St).default([]),updatedAt:a.z.string().datetime()}).strict(),kt=a.z.object({streamId:a.z.string().trim().min(1).max(240),revision:a.z.number().int().min(0),lastEventAt:a.z.string().datetime(),snapshot:At}).strict();At.pick({runningCount:!0,problemCount:!0,updatedAt:!0}).extend({revision:a.z.number().int().min(0).optional()});const zt=a.z.enum(["app-session-created","app-session-updated","app-session-deleted","app-session-recovered","control-action","heartbeat-sync","startup"]),Tt=a.z.object({streamId:a.z.string().trim().min(1).max(240),instanceId:a.z.string().trim().min(1).max(160),nodeId:a.z.string().trim().min(1).max(160).optional(),revision:a.z.number().int().min(0),previousRevision:a.z.number().int().min(0).optional(),traceId:a.z.string().trim().min(1).max(160),generatedAt:a.z.string().datetime(),reason:zt}).strict(),Et=a.z.object({meta:Tt,snapshot:At}).strict(),Ct=a.z.object({meta:Tt,session:St}).strict(),xt=a.z.object({meta:Tt,sessionId:a.z.string().trim().min(1).max(160),tombstone:St.optional(),expiresAt:a.z.string().datetime().optional()}).strict(),Nt=a.z.object({streamId:a.z.string().trim().min(1).max(240),instanceId:a.z.string().trim().min(1).max(160),sinceRevision:a.z.number().int().min(0),latestRevision:a.z.number().int().min(0),earliestRetainedRevision:a.z.number().int().min(0),syncRequired:a.z.boolean().default(!1),events:a.z.array(a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal(ht),payload:Et}).strict(),a.z.object({type:a.z.literal(yt),payload:Ct}).strict(),a.z.object({type:a.z.literal(ft),payload:xt}).strict()])).default([])}).strict();function Ot(e,t=(new Date).toISOString()){const n=e.map(e=>Rt(e));return At.parse({runningCount:n.filter(e=>"running"===e.status).length,problemCount:n.filter(e=>"failed"===e.status).length,sessions:n,updatedAt:t})}function _t(e,t=(new Date).toISOString()){return Ot(e.filter(e=>jt("string"==typeof e.status?e.status:void 0)),t)}function Rt(e){const t=Pt("string"==typeof e.status?e.status:void 0),n="string"==typeof e.id?e.id:"",i=function(e){const t=Bt(e.workspace),n=Bt(e.tty),i=Bt(e.launch),s=Bt(e.ai),r=Bt(s.claude),o=Ut(t.cwd)||Ut(n.cwd)||Ut(r.cwd)||Ut(i.cwd);return o?{cwd:o}:void 0}(e),{workspace:s,...r}=e;return St.parse({...r,status:t,bindings:$t([...(o=e.bindings,Array.isArray(o)?o.flatMap(e=>{const t=wt.safeParse(e);return t.success?[t.data]:[]}):[]),...n?[{type:"app-session",id:n}]:[],...Lt(e)]),...i?{workspace:i}:{}});var o}function Pt(e){const t=(e||"unknown").trim().toLowerCase();return"ended"===t?"closed":"terminating"===t?"stopping":It.options.includes(t)?t:"unknown"}function jt(e){return!vt.has(Pt(e))}function Dt(e){return"tty"===e.kind?"tty":"gui"===e.kind?"vnc":"web"===e.kind?"web":void 0}function Mt(e){return"app-session"===e.type?`app:${e.id}`:"provider-session"===e.type?`provider:${e.agent||""}:${e.id}`:`adapter:${e.adapter||""}:${e.key||e.id}`}function Lt(e){const t=Bt(e.ai),n=Bt(t.claude),i=Bt(t.appServer),s=Bt(e.launch),r=[],o=Ut(Bt(s.aiSessionResume).providerSessionId),a="codex"===e.appId||"claude"===e.appId?e.appId:void 0;a&&o&&r.push({type:"provider-session",agent:a,id:o});const d=Ut(n.short);d&&r.push({type:"adapter-key",adapter:"claude",agent:"claude",id:`short:${d}`,key:`short:${d}`});const c=Ut(n.providerSessionId);c&&r.push({type:"provider-session",agent:"claude",id:c});const l=Array.isArray(t.threadIds)?t.threadIds.filter(e=>"string"==typeof e&&Boolean(e.trim())):[],p=Ut(t.activeThreadId);for(const e of[...new Set([p,...l].filter(Boolean))])r.push({type:"provider-session",agent:"codex",id:e});const u=Ut(i.socketPath);return u&&r.push({type:"adapter-key",adapter:"codex-app-server",agent:"codex",id:`socket:${u}`,key:`socket:${u}`}),r}function qt(e){const t="string"==typeof e.id?e.id:"",n=Bt(e.ai),i=Ut(Bt(n.claude).short);return[t?`app:${t}`:"",i?`claude-short:${i}`:""]}function $t(e){const t=new Map;for(const n of e)t.set(Mt(n),n);return[...t.values()]}function Bt(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Ut(e){return"string"==typeof e&&e.trim()?e.trim():""}function Ft(e=(new Date).toISOString()){return At.parse({runningCount:0,problemCount:0,sessions:[],updatedAt:e})}const Ht=a.z.string().trim().min(3).max(160).regex(/^[a-z][a-z0-9_-]*$/),Wt=a.z.string().datetime(),Gt=a.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/),Vt=a.z.string().min(32).max(4096),Kt=a.z.strictObject({default:a.z.string().trim().min(1).max(160),translations:a.z.record(a.z.string().regex(/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/),a.z.string().trim().min(1).max(160)).default({})});function Jt(e){return Array.isArray(e)?`[${e.map(Jt).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${Jt(t)}`).join(",")}}`:JSON.stringify(e)}const Yt="2026-08-10",Qt="2026-08-10",Xt="2026-08-10",Zt=Object.freeze({AccountApi:"task-handoff:official-account-api",Binding:"task-handoff:control-plane-binding",CoordinatorControl:"task-handoff:coordinator-control",RelayAllocation:"task-handoff:relay-allocation",RelayClientAttach:"task-handoff:relay-client-attach",RelayControlPlaneAttach:"task-handoff:relay-control-plane-attach",RelayRevocation:"task-handoff:relay-revocation",ControlPlaneAccess:"task-handoff:control-plane-access"});a.z.strictObject({protocolVersion:a.z.literal("2026-08-10"),audience:a.z.literal(Zt.AccountApi)});const en=a.z.string().email().max(320).transform(e=>e.trim().toLowerCase()),tn=a.z.enum(["pending-verification","active","disabled","pending-deletion"]);a.z.strictObject({id:Ht,email:en,emailVerified:a.z.boolean(),hasPassword:a.z.boolean().optional(),totpEnabled:a.z.boolean().optional(),displayName:Kt.optional(),status:tn,createdAt:Wt}),a.z.strictObject({id:Ht,kind:a.z.enum(["browser","mobile"]),deviceName:a.z.string().trim().min(1).max(160),platform:a.z.string().trim().min(1).max(80).optional(),createdAt:Wt,lastSeenAt:Wt.optional(),expiresAt:Wt,revokedAt:Wt.optional()}),a.z.union([a.z.object({code:Vt,state:a.z.string().min(1).max(4096).optional(),redirectUri:a.z.string().url(),expiresAt:Wt}),a.z.object({authorizationUrl:a.z.string().url(),expiresAt:Wt})]),a.z.object({tokenType:a.z.literal("Bearer"),accessToken:Vt,accessExpiresAt:Wt,refreshCredential:Vt,accountId:Ht,deviceSessionId:Ht}),a.z.strictObject({enrollmentToken:Vt,secret:Vt,algorithm:a.z.literal("SHA1"),digits:a.z.literal(6),periodSeconds:a.z.literal(30),otpauthUri:a.z.string().url().startsWith("otpauth://totp/"),expiresAt:Wt});const nn=a.z.strictObject({controlPlaneId:Ht,algorithm:a.z.literal("Ed25519"),publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:Gt});a.z.strictObject({protocolVersion:a.z.literal(Yt),audience:a.z.literal(Zt.Binding),challengeId:Ht,challenge:Vt,serviceOrigin:a.z.string().url(),identity:nn,nonce:a.z.string().min(16).max(256),initiatingAdminSessionId:Ht,issuedAt:Wt,expiresAt:Wt}),a.z.strictObject({code:a.z.enum(["CONTROL_PLANE_ALREADY_BOUND","REVISION_CONFLICT","REVOCATION_PENDING","IDENTITY_CLONE_CONFLICT"]),controlPlaneId:Ht,expectedRevision:a.z.number().int().nonnegative().optional(),actualRevision:a.z.number().int().nonnegative().optional(),retryable:a.z.boolean()});const sn=a.z.strictObject({bindingId:Ht.optional(),controlPlaneId:Ht,displayName:Kt,publicKeyFingerprint:Gt,bindingRevision:a.z.number().int().positive(),remoteAccess:a.z.enum(["enabled","disabled","revocation-pending"]),leaseExpiresAt:Wt.optional(),lastConnectedAt:Wt.optional(),relayUsageBytes:a.z.number().int().nonnegative(),relayQuotaBytes:a.z.number().int().nonnegative().optional(),versionWarning:a.z.string().trim().min(1).max(500).optional(),errorCode:a.z.string().trim().min(1).max(160).optional()}),rn=a.z.enum(["interactive","stream","bulk"]),on=a.z.object({type:a.z.literal("tty-snapshot"),streamId:a.z.string().trim().min(1).optional(),data:a.z.string(),pendingEscape:a.z.string(),cols:a.z.number().int().positive(),rows:a.z.number().int().positive()}).passthrough(),an=a.z.strictObject({protocolVersion:a.z.literal(Qt),audience:a.z.literal(Zt.CoordinatorControl),connectionId:Ht,processInstanceId:Ht,controlPlaneId:Ht,publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),publicKeyFingerprint:Gt,bindingId:Ht.optional(),bindingRevision:a.z.number().int().positive().optional(),epoch:a.z.number().int().nonnegative(),capabilities:a.z.array(a.z.enum(["request","stream","websocket"])).min(1),issuedAt:Wt,expiresAt:Wt}).superRefine((e,t)=>{Boolean(e.bindingId)!==Boolean(e.bindingRevision)&&t.addIssue({code:"custom",message:"binding id and revision must be supplied together"})});an.safeExtend({signature:Vt}),a.z.strictObject({connectionId:Ht,controlPlaneId:Ht,bindingRevision:a.z.number().int().positive(),epoch:a.z.number().int().nonnegative(),relayId:Ht,relayRegion:a.z.string().trim().min(1).max(80),issuedAt:Wt,expiresAt:Wt});const dn=a.z.strictObject({protocolVersion:a.z.literal(Qt),audience:a.z.literal(Zt.ControlPlaneAccess),ticketId:Ht,accountId:Ht,deviceSessionId:Ht,controlPlaneId:Ht,bindingId:Ht,bindingRevision:a.z.number().int().positive(),targetPublicKeyFingerprint:Gt,nonce:a.z.string().min(16).max(256),trafficClasses:a.z.array(rn).min(1),issuedAt:Wt,expiresAt:Wt,signature:Vt});a.z.strictObject({audience:a.z.literal(Zt.ControlPlaneAccess),accountId:Ht,deviceSessionId:Ht,controlPlaneId:Ht,bindingId:Ht,bindingRevision:a.z.number().int().positive(),authenticatedAt:Wt,expiresAt:Wt,signature:Vt});const cn=a.z.enum(["client","control-plane"]),ln=a.z.strictObject({protocolVersion:a.z.literal(Xt),audience:a.z.enum([Zt.RelayClientAttach,Zt.RelayControlPlaneAttach]),allocationId:Ht,relayId:Ht,role:cn,controlPlaneId:Ht,accountId:Ht,deviceSessionId:Ht,bindingId:Ht,ticketId:Ht,bindingRevision:a.z.number().int().positive(),trafficClass:rn,nonce:a.z.string().min(16).max(256),issuedAt:Wt,expiresAt:Wt,signature:Vt}).superRefine((e,t)=>{const n="client"===e.role?Zt.RelayClientAttach:Zt.RelayControlPlaneAttach;e.audience!==n&&t.addIssue({code:"custom",path:["audience"],message:`audience must match ${e.role} role`})});a.z.object({allocationId:Ht,relayId:Ht,relayRegion:a.z.string().trim().min(1).max(80),relayUrl:a.z.string().url(),clientAttach:ln,expiresAt:Wt}),a.z.strictObject({channelId:Ht,allocationId:Ht,controlPlaneId:Ht,bindingRevision:a.z.number().int().positive(),trafficClass:rn,state:a.z.enum(["waiting-for-peer","handshaking","open","closing","closed"]),clientAttached:a.z.boolean(),controlPlaneAttached:a.z.boolean(),openedAt:Wt.optional(),leaseExpiresAt:Wt}),a.z.strictObject({protocolVersion:a.z.literal(Xt),channelId:Ht,sequence:a.z.number().int().nonnegative(),kind:a.z.enum(["handshake","data","cancel","window-update","close"]),ciphertext:a.z.string().max(1398102).optional(),creditBytes:a.z.number().int().positive().optional()}),a.z.strictObject({channelId:Ht,code:a.z.enum(["normal","expired","revoked","quota-exceeded","idle-timeout","slow-consumer","protocol-error","peer-disconnected"]),retryable:a.z.boolean()}),a.z.strictObject({protocolVersion:a.z.literal(Xt),audience:a.z.literal(Zt.RelayRevocation),revocationId:Ht,relayId:Ht.optional(),allocationId:Ht.optional(),accountId:Ht.optional(),deviceSessionId:Ht.optional(),bindingId:Ht.optional(),issuedAt:Wt,expiresAt:Wt,signature:Vt}).refine(e=>[e.allocationId,e.accountId,e.deviceSessionId,e.bindingId].some(Boolean),"revocation target is required"),a.z.strictObject({data:a.z.strictObject({protocolVersion:a.z.literal(Yt),items:a.z.array(sn)})}),Object.keys(sn.shape);const pn=a.z.object({ticketId:a.z.string().trim().min(3).max(160),deviceSessionId:a.z.string().trim().min(3).max(160),clientEphemeralPublicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/)});function un(){return Object.assign(new Error("End-to-end handshake is invalid."),{code:"E2E_HANDSHAKE_INVALID"})}a.z.object({serverEphemeralPublicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),transcript:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),signature:a.z.string().regex(/^[A-Za-z0-9_-]{86}$/)});const mn=a.z.union([a.z.object({type:a.z.literal("schedule"),scheduleKind:a.z.literal("interval").default("interval"),intervalMs:a.z.number().int().min(1e3)}).strict(),a.z.object({type:a.z.literal("schedule"),scheduleKind:a.z.literal("daily"),timeOfDay:a.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),timezone:a.z.string().trim().min(1).max(120)}).strict(),a.z.object({type:a.z.literal("schedule"),scheduleKind:a.z.literal("weekly"),weekdays:a.z.array(a.z.number().int().min(0).max(6)).min(1).max(7),timeOfDay:a.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),timezone:a.z.string().trim().min(1).max(120)}).strict()]),gn=a.z.union([mn,a.z.object({type:a.z.literal("file-change"),roots:a.z.array(a.z.string().trim().min(1).max(4096)).min(1).max(50),globs:a.z.array(a.z.string().trim().min(1).max(500)).min(1).max(100),ignore:a.z.array(a.z.string().trim().min(1).max(500)).max(100).optional(),debounceMs:a.z.number().int().min(100).max(6e4).default(1500)}).strict(),a.z.object({type:a.z.literal("ai-session"),agent:a.z.string().trim().min(1).max(80).optional(),statuses:a.z.array(a.z.enum(["running","waiting","idle","failed"])).max(20).optional(),phases:a.z.array(a.z.enum(["thinking","tool","editing","approval","responding","unknown"])).max(20).optional()}).strict()]),hn=a.z.object({promptTemplate:a.z.string().trim().min(1).max(2e4)}).strict(),yn=a.z.object({cooldownMs:a.z.number().int().min(0).max(864e5).optional(),maxConcurrentRuns:a.z.number().int().min(1).max(20).default(1),whenBusy:a.z.enum(["skip","queue"]).default("skip")}).strict(),fn=a.z.object({configHash:a.z.string().trim().min(8).max(80),name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(1e3).optional(),source:gn,action:hn,policy:yn.default({maxConcurrentRuns:1,whenBusy:"skip"}),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),In=a.z.object({type:a.z.literal("ai-session"),aiSessionId:a.z.string().trim().min(1).max(160)}).strict(),bn=a.z.object({configHash:a.z.string().trim().min(8).max(80),deploymentId:a.z.string().trim().min(1).max(240).optional(),instanceId:a.z.string().trim().min(1).max(160),origin:a.z.enum(["control-plane","controlled-instance"]).default("controlled-instance"),enabled:a.z.boolean().default(!0),target:In,localName:a.z.string().trim().min(1).max(160).optional(),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict(),vn=a.z.object({configHash:a.z.string().trim().min(8).max(80),deploymentId:a.z.string().trim().min(1).max(240).optional(),instanceId:a.z.string().trim().min(1).max(160),status:a.z.enum(["idle","running","disabled","error"]).default("idle"),lastTriggeredAt:a.z.string().datetime().optional(),lastCompletedAt:a.z.string().datetime().optional(),lastSkippedAt:a.z.string().datetime().optional(),lastError:a.z.string().trim().max(4e3).optional(),runCount:a.z.number().int().min(0).default(0),skippedCount:a.z.number().int().min(0).default(0)}).strict(),wn=a.z.object({id:a.z.string().trim().min(1).max(160),configHash:a.z.string().trim().min(8).max(80),deploymentId:a.z.string().trim().min(1).max(240).optional(),instanceId:a.z.string().trim().min(1).max(160),eventType:a.z.enum(["manual","schedule","file-change","ai-session"]),status:a.z.enum(["started","completed","failed","skipped"]),target:In,promptPreview:a.z.string().trim().max(500),eventSummary:a.z.string().trim().max(1e3).optional(),error:a.z.string().trim().max(4e3).optional(),startedAt:a.z.string().datetime(),completedAt:a.z.string().datetime().optional()}).strict();a.z.object({schemaVersion:a.z.literal(1).default(1),configs:a.z.array(fn).default([]),deployments:a.z.array(bn).default([]),runtime:a.z.array(vn).default([]),recentRuns:a.z.array(wn).default([])}).strict();const Sn=a.z.object({instanceId:a.z.string().trim().min(1).max(160),instanceName:a.z.string().trim().min(1).max(160),deployment:bn,runtime:vn.optional()}).strip(),An=wn.extend({instanceName:a.z.string().trim().min(1).max(160).optional()}).strip(),kn=a.z.object({configHash:a.z.string().trim().min(8).max(80),config:fn,deploymentCount:a.z.number().int().min(0),enabledCount:a.z.number().int().min(0),runningCount:a.z.number().int().min(0),errorCount:a.z.number().int().min(0),ownedByControlPlane:a.z.boolean(),controlPlaneDeploymentCount:a.z.number().int().min(0),deployments:a.z.array(Sn),recentRuns:a.z.array(An)}).strip(),zn=a.z.object({updatedAt:a.z.string().datetime(),triggers:a.z.array(kn)}).strip();function Tn(e){const t=xn({source:e.source,action:e.action,policy:yn.parse(e.policy||{})});return`trg_${function(e){const t=(new TextEncoder).encode(e),n=64*Math.ceil((t.length+9)/64),i=new Uint8Array(n);i.set(t),i[t.length]=128;const s=new DataView(i.buffer),r=8*t.length;s.setUint32(n-8,Math.floor(r/4294967296)),s.setUint32(n-4,r>>>0);const o=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),a=new Uint32Array(64);for(let e=0;e<n;e+=64){for(let t=0;t<16;t+=1)a[t]=s.getUint32(e+4*t);for(let e=16;e<64;e+=1){const t=a[e-15],n=a[e-2],i=Cn(t,7)^Cn(t,18)^t>>>3,s=Cn(n,17)^Cn(n,19)^n>>>10;a[e]=a[e-16]+i+a[e-7]+s>>>0}let[t,n,i,r,d,c,l,p]=o;for(let e=0;e<64;e+=1){const s=p+(Cn(d,6)^Cn(d,11)^Cn(d,25))+(d&c^~d&l)+En[e]+a[e]>>>0,o=t&n^t&i^n&i;p=l,l=c,c=d,d=r+s>>>0,r=i,i=n,n=t,t=s+((Cn(t,2)^Cn(t,13)^Cn(t,22))+o>>>0)>>>0}o[0]=o[0]+t>>>0,o[1]=o[1]+n>>>0,o[2]=o[2]+i>>>0,o[3]=o[3]+r>>>0,o[4]=o[4]+d>>>0,o[5]=o[5]+c>>>0,o[6]=o[6]+l>>>0,o[7]=o[7]+p>>>0}return[...o].map(e=>e.toString(16).padStart(8,"0")).join("")}(JSON.stringify(t)).slice(0,24)}`}a.z.object({name:fn.shape.name,description:fn.shape.description,source:gn,action:hn,policy:yn.partial().optional()}).strict();const En=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function Cn(e,t){return e>>>t|e<<32-t}function xn(e){return Array.isArray(e)?e.map(xn):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,xn(t)])):e}const Nn="2026-08-01",On=a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Proxy protocol version must use YYYY-MM-DD format."),_n=a.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Rn=a.z.string().datetime(),Pn=a.z.string().trim().min(32).max(4096),jn=_n,Dn=a.z.string().trim().max(2048).transform((e,t)=>{try{return function(e){const t=new URL(e.trim());if("https:"!==t.protocol||t.username||t.password||"/"!==t.pathname||t.search||t.hash)throw new Error("Proxy origin must be an HTTPS origin without credentials, path, query, or fragment.");return t.origin}(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),a.z.NEVER}}),Mn=a.z.string().trim().min(1).max(4096).transform((e,t)=>{try{return function(e){const t=e.trim();if(!t.startsWith("/")||t.startsWith("//")||t.includes("\\")||/%25/i.test(t))throw new Error("Proxy route must be a single-encoded node-agent relative route.");const n=t.split("?",1)[0];let i,s;try{i=n.split("/").map(e=>decodeURIComponent(e))}catch{throw new Error("Proxy route contains invalid percent encoding.")}if(i.some(e=>".."===e||"."===e))throw new Error("Proxy route cannot traverse outside the node-agent API.");try{s=new URL(t,"https://node-agent.invalid")}catch{throw new Error("Proxy route is invalid.")}if("https://node-agent.invalid"!==s.origin||s.username||s.password)throw new Error("Proxy route cannot select an absolute upstream URL.");return`${s.pathname}${s.search}`}(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),a.z.NEVER}}),Ln=new Set(["accept","accept-language","authorization","content-type","if-match","if-none-match","range","x-request-id"]),qn=new Set(["cache-control","content-disposition","content-language","content-length","content-range","content-type","etag","last-modified","x-request-id"]),$n="x-task-handoff-proxy-protocol-version",Bn="x-task-handoff-proxy-source-control-plane-id",Un="x-task-handoff-proxy-binding-key-id",Fn="x-task-handoff-proxy-credential",Hn={ProtocolUnsupported:"CONTROL_PLANE_PROXY_PROTOCOL_UNSUPPORTED",InviteInvalid:"CONTROL_PLANE_PROXY_INVITE_INVALID",InviteExpired:"CONTROL_PLANE_PROXY_INVITE_EXPIRED",InviteConsumed:"CONTROL_PLANE_PROXY_INVITE_CONSUMED",InviteRevoked:"CONTROL_PLANE_PROXY_INVITE_REVOKED",TargetUnavailable:"CONTROL_PLANE_PROXY_TARGET_UNAVAILABLE",TargetMismatch:"CONTROL_PLANE_PROXY_TARGET_MISMATCH",BindingUnknown:"CONTROL_PLANE_PROXY_BINDING_UNKNOWN",BindingRevoked:"CONTROL_PLANE_PROXY_BINDING_REVOKED",BindingIdentityConflict:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",AuthenticationFailed:"CONTROL_PLANE_PROXY_AUTHENTICATION_FAILED",RouteInvalid:"CONTROL_PLANE_PROXY_ROUTE_INVALID",HeaderInvalid:"CONTROL_PLANE_PROXY_HEADER_INVALID",ResourceLimit:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",SnapshotRequired:"CONTROL_PLANE_PROXY_SNAPSHOT_REQUIRED",Unavailable:"CONTROL_PLANE_PROXY_UNAVAILABLE",TransportFailed:"CONTROL_PLANE_PROXY_TRANSPORT_FAILED"},Wn=a.z.enum(Object.values(Hn)),Gn=a.z.object({code:Wn,message:a.z.string().trim().min(1).max(2048),retryable:a.z.boolean(),details:a.z.record(a.z.string(),a.z.unknown()).optional()}).strict(),Vn=a.z.enum(["active","consumed","revoked","expired"]),Kn=a.z.object({id:_n,targetNodeId:_n,tokenHash:a.z.string().trim().min(32).max(256),status:Vn,createdBy:_n,expiresAt:Rn,consumedByClaimId:_n.optional(),consumedAt:Rn.optional(),revokedAt:Rn.optional(),createdAt:Rn,updatedAt:Rn}).strict(),Jn=Kn.omit({tokenHash:!0}),Yn=a.z.object({targetNodeId:_n,expiresInSeconds:a.z.number().int().min(60).max(3600).default(600)}).strict(),Qn=a.z.object({invite:Jn,token:a.z.string().trim().min(24).max(512),proxyOrigin:Dn,protocolVersion:On}).strict(),Xn=a.z.enum(["active","revoked"]),Zn=a.z.object({id:_n,claimId:_n,sourceControlPlaneId:_n,targetNodeId:_n,bindingKeyId:_n,credentialHash:a.z.string().trim().min(32).max(256),status:Xn,revision:a.z.number().int().positive(),lastError:Gn.optional(),revokedAt:Rn.optional(),createdAt:Rn,updatedAt:Rn}).strict(),ei=Zn.omit({credentialHash:!0}),ti=a.z.object({protocolVersion:On,inviteToken:a.z.string().trim().min(24).max(512).optional(),claimId:_n,sourceControlPlaneId:_n,targetNodeId:_n.optional(),bindingKeyId:_n,credential:Pn}).strict(),ni=a.z.object({sourceControlPlaneId:_n,bindingKeyId:_n,credential:Pn}).strict(),ii=a.z.object({id:_n,name:a.z.string().trim().min(1).max(160),status:a.z.enum(["unknown","online","offline","degraded"]),health:a.z.enum(["unknown","ok","degraded","failed"]),lastSeenAt:Rn.optional(),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({})}).strict(),si=a.z.object({protocolVersion:On,binding:ei,streamId:_n,revision:a.z.number().int().nonnegative(),observedAt:Rn,target:ii}).strict(),ri=a.z.object({type:a.z.literal("control-plane-proxy.event"),protocolVersion:On,streamId:_n,bindingId:_n,sourceControlPlaneId:_n,targetNodeId:_n,revision:a.z.number().int().positive(),source:a.z.object({id:a.z.string().trim().min(1).max(512),seq:a.z.number().int().nonnegative()}).strict(),target:ii,event:a.z.object({type:a.z.string().trim().min(1).max(240),topic:a.z.string().trim().min(1).max(240),createdAt:Rn}).strict()}).strict(),oi=a.z.object({type:a.z.literal("control-plane-proxy.events.ready"),protocolVersion:On,streamId:_n,bindingId:_n,sourceControlPlaneId:_n,targetNodeId:_n,latestRevision:a.z.number().int().nonnegative(),earliestRetainedRevision:a.z.number().int().nonnegative()}).strict(),ai=a.z.object({type:a.z.literal("control-plane-proxy.snapshot-required"),protocolVersion:On,streamId:_n,bindingId:_n,sourceControlPlaneId:_n,targetNodeId:_n,sinceRevision:a.z.number().int().nonnegative(),latestRevision:a.z.number().int().nonnegative(),earliestRetainedRevision:a.z.number().int().nonnegative(),error:Gn}).strict(),di=a.z.discriminatedUnion("type",[ri,oi,ai]),ci=a.z.object({protocolVersion:On,binding:ei,target:si.shape.target}).strict(),li=a.z.object({id:_n,claimId:_n,proxyOrigin:Dn,requestedName:a.z.string().trim().min(1).max(160).optional(),sourceControlPlaneId:_n,targetNodeId:_n.optional(),bindingKeyId:_n,credential:Pn,status:a.z.enum(["pending","compensation-required"]),createdAt:Rn,updatedAt:Rn,expiresAt:Rn}).strict();li.omit({credential:!0});const pi=a.z.object({id:_n,nodeId:_n,proxyOrigin:Dn,proxyBindingId:_n,targetNodeId:_n,sourceControlPlaneId:_n,bindingKeyId:_n,credential:Pn,createdAt:Rn,updatedAt:Rn}).strict(),ui="2026-08-17",mi=new Set(["2026-08-01","2026-08-16",ui]),gi=a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Protocol version must use YYYY-MM-DD format."),hi=a.z.string().trim().min(1).max(120);function yi(){return{features:{appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}}}const fi=a.z.object({sessionReadAgents:a.z.array(hi).max(100).default([]),turnReadAgents:a.z.array(hi).max(100).default([]),liveItemAgents:a.z.array(hi).max(100).default([])}).passthrough(),Ii=a.z.object({appRuntime:a.z.boolean().default(!1),tty:a.z.boolean().default(!1),gui:a.z.boolean().default(!1),browser:a.z.boolean().default(!1),screenshots:a.z.boolean().default(!1),logs:a.z.boolean().default(!1),aiSessionWorkspaceSelection:a.z.boolean().default(!1),aiSessionPersistenceSettings:a.z.boolean().default(!1),aiSessionTimeline:fi.default(function(){return{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}})}).passthrough(),bi=a.z.object({features:Ii.default(function(){return{appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}})}).passthrough();function vi(e){const t={features:{appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}};if(!e||"object"!=typeof e||Array.isArray(e))return t;const n=e,i=n.features;if(!i||"object"!=typeof i||Array.isArray(i))return t;const s=i,r={appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}};for(const e of["appRuntime","tty","gui","browser","screenshots","logs","aiSessionWorkspaceSelection","aiSessionPersistenceSettings"]){const t=a.z.boolean().safeParse(s[e]);t.success&&(r[e]=t.data)}const o=fi.safeParse(s.aiSessionTimeline);return o.success&&(r.aiSessionTimeline=o.data),bi.parse({...n,features:{...s,...r}})}function wi(e,t){const n=function(e){return vi(e).features.aiSessionTimeline}(e);return"session-read"===t?n.sessionReadAgents:"turn-read"===t?n.turnReadAgents:n.liveItemAgents}const Si=a.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Ai=a.z.string().datetime(),ki=a.z.record(a.z.string(),a.z.string()).default({}),zi=a.z.record(a.z.string(),a.z.string()).default({});function Ti(e){if(null!=e){if("string"==typeof e)return{encoding:"utf8",data:e};if(Buffer.isBuffer(e))return{encoding:"base64",data:e.toString("base64")};if(e instanceof ArrayBuffer)return{encoding:"base64",data:Buffer.from(e).toString("base64")};if(ArrayBuffer.isView(e))return{encoding:"base64",data:Buffer.from(e.buffer,e.byteOffset,e.byteLength).toString("base64")};throw new TypeError("Node tunnel request body must be a string or binary buffer.")}}a.z.object({encoding:a.z.enum(["utf8","base64"]),data:a.z.string()}).strict().superRefine((e,t)=>{"base64"===e.encoding&&Buffer.from(e.data,"base64").toString("base64")!==e.data&&t.addIssue({code:"custom",path:["data"],message:"Node tunnel binary body must use canonical base64 encoding."})});const Ei=/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/,Ci=/^sha256:([a-fA-F0-9]{64})$/,xi=/^(?:localhost|[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?)(?::[1-9][0-9]{0,4})?$/,Ni=/^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*$/;function Oi(e){const t=e.trim();if(!t||t.length>512||t.includes("://")||/\s/.test(t))throw new Error("Docker image reference must not contain a URL scheme or whitespace.");const n=t.indexOf("@");if(-1!==n&&n!==t.lastIndexOf("@"))throw new Error("Docker image reference contains more than one digest separator.");const i=-1===n?void 0:t.slice(n+1),s=-1===n?t:t.slice(0,n),r=i?Ci.exec(i):void 0;if(i&&!r)throw new Error("Docker image digest must use sha256 followed by 64 hexadecimal characters.");const o=s.lastIndexOf("/"),a=s.lastIndexOf(":"),d=a>o,c=d?s.slice(a+1):void 0,l=d?s.slice(0,a):s;if(c&&!Ei.test(c))throw new Error("Docker image tag is invalid.");if(!c&&!r)throw new Error("Docker image reference must include an explicit tag or sha256 digest.");const p=l.split("/");if(!p.length||p.some(e=>!e))throw new Error("Docker image repository path is invalid.");const u=p.length>1&&(p[0].includes(".")||p[0].includes(":")||"localhost"===p[0]),m=u?p.slice(1):p;if(u&&!xi.test(p[0].toLowerCase()))throw new Error("Docker image registry host or port is invalid.");if(!m.length||m.some(e=>!Ni.test(e)))throw new Error("Docker image repository names must be lowercase and use valid separators.");const g=p.map((e,t)=>u&&0===t?e.toLowerCase():e).join("/"),h=r?`sha256:${r[1].toLowerCase()}`:void 0;return`${g}${c?`:${c}`:""}${h?`@${h}`:""}`}function _i(e){const t=Oi(e),n=t.indexOf("@"),i=-1===n?void 0:t.slice(n+1),s=-1===n?t:t.slice(0,n),r=s.lastIndexOf("/"),o=s.lastIndexOf(":"),a=o>r;return{reference:t,repository:a?s.slice(0,o):s,tag:a?s.slice(o+1):void 0,digest:i}}const Ri=a.z.string().trim().min(1).max(512).transform((e,t)=>{try{return Oi(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),a.z.NEVER}}),Pi=a.z.string().trim().transform((e,t)=>{const n=Ci.exec(e);return n?`sha256:${n[1].toLowerCase()}`:(t.addIssue({code:"custom",message:"Docker image digest must use sha256 followed by 64 hexadecimal characters."}),a.z.NEVER)}),ji=a.z.object({codexModelHash:Si.nullable().optional(),claudeModelHash:Si.nullable().optional()}).strict().default({}),Di=a.z.object({imageId:Si,tag:a.z.string().trim().min(1).max(128).regex(Ei).optional()}).strict(),Mi=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("image"),imageSelection:Di}).strict(),a.z.object({type:a.z.literal("template"),environmentTemplateId:Si}).strict()]),Li=a.z.enum(["creating","ready","failed","deleting"]),qi=a.z.enum(["linux","darwin","win32","freebsd","openbsd","aix","sunos","unknown"]),$i=a.z.enum(["x64","arm64","arm","ia32","ppc64","s390x","riscv64","unknown"]),Bi=a.z.object({code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2048),phase:a.z.enum(["validate","commit","inspect","security-check","persist","delete","recovery"]).optional()}).strict(),Ui=a.z.object({templateId:Si,nodeId:Si,imageId:Pi,name:a.z.string().trim().min(1).max(160),platform:qi,architecture:$i}).strict(),Fi=a.z.enum(["data","agent-home","workspace"]),Hi=a.z.object({deleteVolumes:a.z.boolean()}).strict(),Wi=a.z.object({role:Fi,name:a.z.string().trim().min(1).max(255),mountPath:a.z.string().trim().startsWith("/").max(4096),status:a.z.enum(["deleted","retained","missing","failed"]),error:a.z.object({code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2048)}).strict().optional()}).strict(),Gi=a.z.object({instanceId:Si,containerDeleted:a.z.boolean(),completed:a.z.boolean(),deletedVolumes:a.z.array(Wi),retainedVolumes:a.z.array(Wi),volumeResults:a.z.array(Wi)}).strict(),Vi={img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"};function Ki(e,t){if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;return{imageId:"string"==typeof t.imageId&&Vi[t.imageId]||t.imageId,..."string"==typeof t.tag?{tag:t.tag}:{}}}if("string"==typeof t)return{imageId:Vi[t]||t}}function Ji(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,{defaultImageId:n,...i}=t;return{...i,defaultImageSelection:Ki(t.defaultImageSelection,n)}}const Yi=a.z.object({id:Si,name:a.z.string().trim().min(1).max(120),kind:a.z.enum(["tty","gui","web"]),source:a.z.enum(["builtin","custom"]),availability:a.z.enum(["available","missing-dependency"]),capabilities:a.z.object({automation:a.z.enum(["cdp"]).optional(),supportsCwdSelection:a.z.boolean().default(!1)}).strict().default({supportsCwdSelection:!1}),diagnosticCode:a.z.enum(["APP_EXECUTABLE_NOT_FOUND"]).optional()}).strict(),Qi=a.z.object({code:a.z.enum(["APP_CATALOG_INVALID"]),message:a.z.string().trim().min(1).max(500)}).strict(),Xi=a.z.object({items:a.z.array(Yi).max(256),observedAt:Ai,issues:a.z.array(Qi).max(32).default([])}).strict(),Zi=a.z.object({id:Si,name:a.z.string().trim().min(1).max(160),sourceInstanceId:Si,nodeId:Si,imageId:Pi.optional(),internalTag:a.z.string().trim().min(1).max(512).optional(),platform:qi.optional(),architecture:$i.optional(),sizeBytes:a.z.number().int().nonnegative().optional(),status:Li,error:Bi.optional(),createdAt:Ai,updatedAt:Ai}).strict().superRefine((e,t)=>{if("ready"===e.status)for(const n of["imageId","internalTag","platform","architecture","sizeBytes"])void 0===e[n]&&t.addIssue({code:"custom",path:[n],message:`Ready environment template requires ${n}.`});"failed"!==e.status||e.error||t.addIssue({code:"custom",path:["error"],message:"Failed environment template requires an error diagnostic."})}),es=a.z.enum(["apt","dnf","brew","npm"]),ts=a.z.enum(["user","passwordless-sudo","root"]),ns=a.z.object({platform:qi,arch:$i,installers:a.z.array(es).max(8),privilege:ts,installerAccess:a.z.object({npmGlobalWritable:a.z.boolean().optional()}).strict().optional()}).strict(),is=a.z.enum(["installed","not-installed","broken","unsupported"]),ss=a.z.enum(["recipe","bundled","external","none"]),rs=a.z.object({code:a.z.enum(["BUNDLED","EXTERNALLY_MANAGED","ALREADY_INSTALLED","NOT_INSTALLED","UNSUPPORTED_PLATFORM","INSTALLER_UNAVAILABLE","INSTALLER_NOT_WRITABLE","INSUFFICIENT_PRIVILEGE","OPERATION_IN_PROGRESS"]),message:a.z.string().trim().min(1).max(500)}).strict(),os=a.z.object({id:Si,name:a.z.string().trim().min(1).max(120),kind:a.z.enum(["tty","gui","web"]),description:a.z.string().trim().max(500).optional(),state:is,managementSource:ss,version:a.z.string().trim().max(120).optional(),canInstall:a.z.boolean(),canUninstall:a.z.boolean(),installReason:rs.optional(),uninstallReason:rs.optional(),activeJobId:Si.optional()}).strict(),as=a.z.enum(["install","uninstall"]),ds=a.z.enum(["queued","running","succeeded","failed","cancelled","interrupted"]),cs=a.z.object({current:a.z.number().finite().nonnegative().optional(),total:a.z.number().finite().positive().optional(),unit:a.z.string().trim().min(1).max(40).optional()}).strict().refine(e=>void 0===e.total||void 0===e.current||e.current<=e.total,{message:"Progress current must not exceed total.",path:["current"]}),ls=a.z.object({executable:a.z.string().trim().min(1).max(4096),args:a.z.array(a.z.string().max(4096)).max(128)}).strict(),ps=a.z.object({code:a.z.string().trim().min(1).max(120).regex(/^[a-z0-9][a-z0-9._-]*$/),message:a.z.string().trim().min(1).max(4096),retryable:a.z.boolean(),sessionIds:a.z.array(Si).max(64).optional()}).strict(),us=a.z.object({id:Si,requestId:Si.optional(),appId:Si,operation:as,state:ds,phase:a.z.string().trim().min(1).max(120).optional(),progress:cs.optional(),command:ls.optional(),logTail:a.z.string().max(32768).optional(),logTruncated:a.z.boolean().optional(),error:ps.optional(),requestedAt:Ai,startedAt:Ai.optional(),finishedAt:Ai.optional(),updatedAt:Ai}).strict(),ms=a.z.object({streamId:Si,sequence:a.z.number().int().nonnegative(),capabilities:ns,apps:a.z.array(os).max(256),activeJobs:a.z.array(us).max(256),recentJobs:a.z.array(us).max(256),observedAt:Ai}).strict(),gs=a.z.object({requestId:Si.optional()}).strict(),hs=a.z.object({job:us}).strict();a.z.object({type:a.z.literal("app-management"),streamId:Si,sequence:a.z.number().int().nonnegative(),observedAt:Ai,job:us.optional(),snapshot:ms.optional()}).strict().refine(e=>void 0!==e.job||void 0!==e.snapshot,{message:"An app management event requires a job or snapshot."});const ys=a.z.object({component:a.z.enum(["control-plane","node-agent","controlled-instance"]),packageName:a.z.string().trim().max(160).optional(),packageVersion:a.z.string().trim().max(80).optional(),protocolVersion:gi.optional(),buildId:a.z.string().trim().max(160).optional(),builtAt:a.z.string().trim().max(120).optional(),gitCommit:a.z.string().trim().max(120).optional(),imageRef:a.z.string().trim().max(512).optional(),imageDigest:a.z.string().trim().max(240).optional()}).strict(),fs=a.z.object({data:a.z.object({ok:a.z.literal(!0),role:a.z.literal("control-plane"),protocolVersion:gi,build:ys.extend({component:a.z.literal("control-plane"),packageVersion:a.z.string().trim().min(1).max(80)}).loose(),dataDir:a.z.string().min(1),serverTime:Ai}).loose()}).loose(),Is=a.z.enum(["stable","beta","alpha"]),bs=a.z.object({packageName:a.z.literal("@task-handoff/controlled-instance"),version:a.z.string().trim().min(1).max(80),platform:a.z.string().trim().min(1).max(40),arch:a.z.string().trim().min(1).max(40),formatVersion:a.z.number().int().positive(),launcherAbi:a.z.number().int().positive(),entrypoint:a.z.string().trim().min(1).max(512),sha256:a.z.string().regex(/^[a-f0-9]{64}$/)}).strict(),vs=a.z.object({code:a.z.enum(["INSTANCE_RUNTIME_VERSION_MISMATCH","INSTANCE_RUNTIME_ARTIFACT_UNAVAILABLE","INSTANCE_RUNTIME_ARTIFACT_INVALID","INSTANCE_RUNTIME_INSTALL_FAILED","INSTANCE_RUNTIME_RESTART_FAILED","INSTANCE_RUNTIME_VERIFICATION_FAILED","INSTANCE_BASE_RUNTIME_INCOMPATIBLE","NODE_UPDATE_PREFLIGHT_FAILED","NODE_UPDATE_FAILED","LEGACY_INSTANCE_UPDATE_RETIRED"]),message:a.z.string().trim().min(1).max(4096),expectedVersion:a.z.string().trim().min(1).max(80).optional(),actualVersion:a.z.string().trim().min(1).max(80).optional(),retryable:a.z.boolean().default(!1)}).strict(),ws=a.z.object({desiredVersion:a.z.string().trim().min(1).max(80),actualVersion:a.z.string().trim().min(1).max(80).optional(),phase:a.z.enum(["pending","draining","installing","restarting","verifying","matched","failed"]),attempt:a.z.number().int().nonnegative().default(0),lastAttemptAt:Ai.optional(),matchedAt:Ai.optional(),error:vs.optional()}).strict(),Ss=a.z.object({runningInstanceCount:a.z.number().int().nonnegative(),stoppedInstanceCount:a.z.number().int().nonnegative(),activeInstanceCount:a.z.number().int().nonnegative(),restartInstanceCount:a.z.number().int().nonnegative(),runningInstanceIds:a.z.array(Si).max(1024).default([]),stoppedInstanceIds:a.z.array(Si).max(1024).default([]),activeInstanceIds:a.z.array(Si).max(1024).default([])}).strict(),As=a.z.object({phase:a.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),desiredVersion:a.z.string().trim().min(1).max(80),nodeVersion:a.z.string().trim().min(1).max(80).optional(),expectedInstanceIds:a.z.array(Si).max(1024).default([]),expectedInstanceCount:a.z.number().int().nonnegative(),matchedInstanceCount:a.z.number().int().nonnegative(),pendingInstanceCount:a.z.number().int().nonnegative(),failedInstanceCount:a.z.number().int().nonnegative(),deferredInstanceCount:a.z.number().int().nonnegative().default(0)}).strict(),ks=a.z.object({channel:Is.default("stable")}).strict(),zs=a.z.object({source:a.z.literal("npm"),channel:Is,currentVersion:a.z.string().trim().max(240).optional(),availableVersion:a.z.string().trim().min(1).max(240),artifactRef:a.z.string().trim().min(1).max(512).optional(),runtimeArtifacts:a.z.array(bs).default([]),impact:Ss,updateAvailable:a.z.boolean(),supported:a.z.boolean().default(!0),reason:a.z.string().trim().max(2048).optional(),checkedAt:Ai,preflightToken:a.z.string().trim().min(16).max(240).optional()}).strict(),Ts=a.z.object({id:Si,nodeId:Si,source:a.z.literal("npm"),channel:Is,fromVersion:a.z.string().trim().max(240).optional(),toVersion:a.z.string().trim().min(1).max(240),artifactRef:a.z.string().trim().min(1).max(512).optional(),runtimeArtifacts:a.z.array(bs).default([]),impact:Ss,rollout:As,status:a.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),error:vs.optional(),startedAt:Ai.optional(),completedAt:Ai.optional(),createdAt:Ai,updatedAt:Ai}).strict(),Es=a.z.object({channel:Is,targetVersion:a.z.string().trim().min(1).max(240),preflightToken:a.z.string().trim().min(16).max(240)}).strict(),Cs=a.z.object({type:a.z.enum(["branch","tag","commit"]),name:a.z.string().trim().min(1).max(240).optional(),commit:a.z.string().trim().max(80).optional()}).strict(),xs=a.z.object({type:a.z.enum(["none","ssh-key","https-token"]).default("none"),secretId:a.z.string().trim().min(1).max(120).optional()}).strict(),Ns=a.z.object({depth:a.z.number().int().positive().max(1e5).optional(),submodules:a.z.boolean().default(!1),lfs:a.z.boolean().default(!1),subdirectory:a.z.string().trim().max(240).default("")}).strict();a.z.object({id:Si,name:a.z.string().trim().min(1).max(160),url:a.z.string().trim().min(1).max(2048),provider:a.z.string().trim().max(80).optional(),ref:Cs.default({type:"branch",name:"main"}),auth:xs.default({type:"none"}),clone:Ns.default({submodules:!1,lfs:!1,subdirectory:""}),defaultImageSelection:Di.optional(),labels:ki,createdAt:Ai,updatedAt:Ai}).strict();const Os=a.z.object({id:Si,nodeId:Si,name:a.z.string().trim().min(1).max(160),path:a.z.string().trim().min(1).max(4096),defaultImageSelection:Di.optional(),labels:ki,createdAt:Ai,updatedAt:Ai}).strict(),_s=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("git-repository"),repositoryId:Si.optional(),url:a.z.string().trim().min(1).max(2048),provider:a.z.string().trim().max(80).optional(),ref:Cs.default({type:"branch",name:"main"}),auth:xs.default({type:"none"}),clone:Ns.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),a.z.object({type:a.z.literal("git-template"),url:a.z.string().trim().min(1).max(2048),templateId:a.z.string().trim().min(1).max(120).optional(),ref:Cs.default({type:"branch",name:"main"}),auth:xs.default({type:"none"}),clone:Ns.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),a.z.object({type:a.z.literal("local-folder"),localFolderId:Si.optional(),path:a.z.string().trim().min(1).max(4096),ownerNodeId:Si.optional()}).strict()]),Rs=a.z.object({mode:a.z.enum(["local-bind","git-clone","empty-volume","persistent-volume"]),path:a.z.string().trim().min(1).max(4096).default("/workspace"),volumeName:a.z.string().trim().max(240).optional(),readOnly:a.z.boolean().default(!1)}).strict(),Ps=a.z.enum(["codex","claude"]),js=a.z.object({id:Si,name:a.z.string().trim().min(1).max(160),source:_s,defaultImageSelection:Di.optional(),defaultNodeId:Si.optional(),defaultRuntimeId:Si.optional(),workspacePolicy:Rs,labels:ki,createdAt:Ai,updatedAt:Ai}).strict(),Ds=a.z.object({id:Si,name:a.z.string().trim().min(1).max(160),endpoint:a.z.string().trim().min(1).max(2048),key:a.z.string().trim().min(1).max(4096),model:a.z.string().trim().min(1).max(240),app:Ps,enabled:a.z.boolean().default(!0),order:a.z.number().int().min(0).max(1e6).default(0),labels:ki,createdAt:Ai,updatedAt:Ai}).strict(),Ms=Ds.omit({key:!0}).extend({keyPreview:a.z.string().trim().min(1).max(160),keySet:a.z.boolean()}).strict(),Ls=Ms.extend({referenceCount:a.z.number().int().min(0)}).strict(),qs=a.z.object({instanceId:Si,codexModelHash:Si.optional(),claudeModelHash:Si.optional(),updatedAt:Ai}).strict(),$s=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("control-plane"),name:Ds.shape.name,enabled:Ds.shape.enabled,order:Ds.shape.order}).strict(),a.z.object({type:a.z.literal("node"),nodeId:Si,name:Ds.shape.name,enabled:Ds.shape.enabled,order:Ds.shape.order,referenceCount:a.z.number().int().min(0)}).strict()]),Bs=a.z.object({id:Si,model:Ms,locations:a.z.array($s).min(1),referenceCount:a.z.number().int().min(0).default(0)}).strict(),Us=a.z.object({nodeId:Si,code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2e3)}).strict(),Fs=a.z.object({models:a.z.array(Bs),nodeDiagnostics:a.z.array(Us).default([]),updatedAt:Ai}).strict();function Hs(e){const t={app:Ps.parse(e.app),endpoint:Ds.shape.endpoint.parse(e.endpoint),key:Ds.shape.key.parse(e.key),model:Ds.shape.model.parse(e.model)};return`mdl_${i.createHash("sha256").update(JSON.stringify(t)).digest("hex")}`}Ds.omit({id:!0,createdAt:!0,updatedAt:!0}).strict().partial().strict(),a.z.object({modelSelection:ji,codexModelHash:Si.optional(),claudeModelHash:Si.optional()}).strict();const Ws=a.z.enum(["market","custom"]),Gs=a.z.enum(["active","deprecated","yanked"]),Vs=a.z.discriminatedUnion("kind",[a.z.object({kind:a.z.literal("builtin"),key:a.z.string().trim().min(1).max(120)}).strict(),a.z.object({kind:a.z.literal("remote"),url:a.z.string().trim().url().max(2048),mediaType:a.z.enum(["image/png","image/jpeg","image/webp"]).optional(),digest:Pi.optional()}).strict()]),Ks={kind:"builtin",key:"default-image-cover"},Js=a.z.array(a.z.string().trim().min(1).max(80)).default([]),Ys=a.z.array(a.z.string().trim().min(1).max(120)).default([]),Qs=a.z.record(a.z.string().trim().min(2).max(35),a.z.string().trim().min(1).max(4096)),Xs=a.z.object({os:a.z.string().trim().min(1).max(40),architecture:a.z.string().trim().min(1).max(40),digest:Pi.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional()}).strict(),Zs=a.z.object({name:a.z.string().trim().min(1).max(128).regex(Ei),version:a.z.string().trim().min(1).max(160).optional(),reference:Ri,manifestDigest:Pi.optional(),publishedAt:Ai.optional(),platforms:a.z.array(Xs).default([]),status:Gs.default("active")}).strict(),er=a.z.object({id:Si,publisher:a.z.string().trim().min(1).max(160),slug:a.z.string().trim().min(1).max(160),name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().min(1).max(4096),localizedDescriptions:Qs.optional(),cover:Vs.optional(),repository:a.z.string().trim().min(1).max(512),defaultTag:a.z.string().trim().min(1).max(128).regex(Ei),tags:a.z.array(Zs).min(1),capabilities:Js,optionalApps:Ys,defaultEnv:zi,labels:ki,status:Gs.default("active")}).strict().superRefine((e,t)=>{e.tags.some(t=>t.name===e.defaultTag)||t.addIssue({code:"custom",path:["defaultTag"],message:"Market defaultTag must identify one of the image tags."})}),tr=a.z.object({protocolVersion:gi,catalogId:Si,revision:a.z.string().trim().min(1).max(240),source:a.z.enum(["embedded","remote","cache"]),generatedAt:Ai,expiresAt:Ai.optional(),items:a.z.array(er)}).strict(),nr=a.z.object({source:a.z.enum(["embedded","remote","cache"]),state:a.z.enum(["ready","refreshing","stale","failed"]),revision:a.z.string().trim().min(1).max(240),updatedAt:Ai,error:a.z.string().trim().max(4096).optional()}).strict(),ir=a.z.object({id:Si,origin:a.z.literal("custom"),name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Qs.optional(),cover:Vs.optional(),reference:Ri,repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(Ei).optional(),pullPolicy:a.z.literal("if-not-present").default("if-not-present"),capabilities:Js,optionalApps:Ys,defaultEnv:zi,labels:ki,createdAt:Ai,updatedAt:Ai}).strict(),sr=a.z.object({name:a.z.string().trim().min(1).max(128).regex(Ei),version:a.z.string().trim().min(1).max(160).optional(),reference:Ri,manifestDigest:Pi.optional(),status:Gs}).strict(),rr=a.z.object({id:Si,origin:Ws,name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Qs.optional(),cover:Vs,repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(Ei).optional(),availableTags:a.z.array(sr),reference:Ri,digest:Pi.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional(),capabilities:Js,optionalApps:Ys,defaultEnv:zi,labels:ki,readOnly:a.z.boolean(),lifecycleStatus:Gs.optional(),market:a.z.object({catalogId:Si,catalogRevision:a.z.string().trim().min(1).max(240),publisher:a.z.string().trim().min(1).max(160),version:a.z.string().trim().min(1).max(160).optional()}).strict().optional()}).strict(),or=a.z.object({id:Si,origin:Ws,name:a.z.string().trim().min(1).max(160),description:a.z.string().trim().max(4096).optional(),localizedDescriptions:Qs.optional(),cover:Vs.optional(),repository:a.z.string().trim().min(1).max(512),tag:a.z.string().trim().min(1).max(128).regex(Ei).optional(),requestedReference:Ri,resolvedDigest:Pi.optional(),resolvedReference:Ri.optional(),downloadSizeBytes:a.z.number().int().positive().optional(),pullPolicy:a.z.literal("if-not-present").default("if-not-present"),capabilities:Js,optionalApps:Ys,defaultEnv:zi,labels:ki,market:a.z.object({catalogId:Si,catalogRevision:a.z.string().trim().min(1).max(240),publisher:a.z.string().trim().min(1).max(160),version:a.z.string().trim().min(1).max(160).optional()}).strict().optional(),createdAt:Ai,updatedAt:Ai}).strict(),ar=a.z.object({phase:a.z.enum(["checking-image","pulling-image","resolving-image","ready","failed"]),requestedReference:Ri,generation:a.z.number().int().nonnegative().default(0),error:a.z.string().trim().max(4096).optional(),startedAt:Ai,updatedAt:Ai}).strict(),dr="image.pull.terminal.output",cr="image.pull.terminal.finished",lr=a.z.object({instanceId:Si,generation:a.z.number().int().nonnegative(),requestedReference:Ri,sequence:a.z.number().int().nonnegative(),observedAt:Ai}).strict(),pr=lr.extend({data:a.z.string().min(1).max(65536),replay:a.z.boolean().optional()}).strict(),ur=lr.extend({outcome:a.z.enum(["succeeded","failed"])}).strict(),mr=lr.extend({status:a.z.enum(["connecting","pulling","extracting","complete","failed"]),layers:a.z.object({total:a.z.number().int().nonnegative(),completed:a.z.number().int().nonnegative(),downloaded:a.z.number().int().nonnegative(),downloading:a.z.number().int().nonnegative(),extracting:a.z.number().int().nonnegative()}).strict(),bytes:a.z.object({current:a.z.number().finite().nonnegative(),total:a.z.number().finite().positive()}).strict().optional(),percent:a.z.number().finite().min(0).max(100).optional(),message:a.z.string().trim().min(1).max(500),terminalTail:a.z.string().max(262144).optional(),terminalTruncated:a.z.boolean().optional()}).strict();function gr(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,i=new Set(["id","origin","name","description","localizedDescriptions","cover","reference","repository","tag","image","registry","pullPolicy","capabilities","optionalApps","defaultEnv","labels","createdAt","updatedAt"]);for(const e of Object.keys(n))i.has(e)||t?.({imageId:"string"==typeof n.id?n.id:void 0,field:e});const s="string"==typeof n.id?n.id:void 0,r="string"==typeof n.image?n.image:void 0;void 0!==r&&t?.({imageId:s,field:"image"}),Object.prototype.hasOwnProperty.call(n,"registry")&&t?.({imageId:s,field:"registry"});let o,a="string"==typeof n.reference?n.reference:r;if(a)try{a=Oi(a)}catch{if(!a.includes("@")&&a.lastIndexOf(":")<=a.lastIndexOf("/"))try{a=Oi(`${a}:latest`),t?.({imageId:s,field:"reference:implicit-latest"})}catch{}}try{o=a?_i(a):void 0}catch{}return{id:n.id,origin:"custom",name:n.name,description:n.description,localizedDescriptions:n.localizedDescriptions,cover:Ur(n.cover,["kind","key","url","mediaType","digest"]),reference:o?.reference??a,repository:o?.repository??n.repository,tag:o?.tag??n.tag,pullPolicy:n.pullPolicy??"if-not-present",capabilities:n.capabilities,optionalApps:n.optionalApps,defaultEnv:n.defaultEnv,labels:n.labels,createdAt:n.createdAt,updatedAt:n.updatedAt}}const hr=a.z.discriminatedUnion("kind",[a.z.object({kind:a.z.literal("direct")}).strict(),a.z.object({kind:a.z.literal("control-plane-proxy"),proxyId:Si,proxyBindingId:Si,targetNodeId:Si}).strict()]),yr=a.z.object({reachability:a.z.enum(["unknown","reachable","unreachable"]),bindingStatus:a.z.enum(["unknown","active","revoked"]),bindingRevision:a.z.number().int().positive().optional(),streamId:a.z.string().trim().min(1).max(160).optional(),revision:a.z.number().int().nonnegative().optional(),observedAt:Ai.optional(),target:ii.optional(),lastError:Gn.optional(),updatedAt:Ai}).strict(),fr=a.z.object({id:Si,name:a.z.string().trim().min(1).max(160),connectionMode:a.z.enum(["local-ipc","local-loopback","direct-http","reverse-wss","control-plane-proxy"]).default("direct-http"),connectionPath:hr.default({kind:"direct"}),connectionEnabled:a.z.boolean().default(!0),auth:a.z.object({mode:a.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Si.optional(),secret:a.z.string().trim().max(4096).optional(),pairedAt:Ai.optional(),pairing:a.z.object({status:a.z.enum(["pending","paired","expired"]).default("pending"),joinToken:a.z.string().trim().max(4096).optional(),expiresAt:Ai.optional()}).strict().optional()}).strict().default({mode:"local-static-key"}),endpoint:a.z.string().trim().max(2048).optional(),controlEndpoint:a.z.string().trim().max(2048).optional(),containerEndpoint:a.z.string().trim().max(2048).optional(),publicWebBase:a.z.string().trim().max(2048).optional(),status:a.z.enum(["unknown","online","offline","degraded"]).default("unknown"),health:a.z.enum(["unknown","ok","degraded","failed"]).default("unknown"),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({}),proxyState:yr.optional(),appInventory:Xi.optional(),labels:ki,lastSeenAt:Ai.optional(),createdAt:Ai,updatedAt:Ai}).strict().superRefine((e,t)=>{"control-plane-proxy"===e.connectionPath.kind&&"control-plane-proxy"!==e.connectionMode&&t.addIssue({code:"custom",path:["connectionPath"],message:"Control-plane proxy paths require control-plane-proxy connection mode."}),"control-plane-proxy"===e.connectionMode&&"control-plane-proxy"!==e.connectionPath.kind&&t.addIssue({code:"custom",path:["connectionPath"],message:"Control-plane proxy nodes require a control-plane-proxy connection path."})}),Ir=a.z.object({id:Si,nodeId:Si,name:a.z.string().trim().min(1).max(160),type:a.z.enum(["docker","kubernetes","local"]),status:a.z.enum(["unknown","online","offline","degraded"]).default("unknown"),accessStrategy:a.z.enum(["node-proxy","direct-port","kubernetes-ingress","kubernetes-port-forward"]).default("node-proxy"),capabilities:a.z.record(a.z.string(),a.z.unknown()).default({}),labels:ki,createdAt:Ai,updatedAt:Ai}).strict(),br=a.z.object({instanceId:Si,runtimeKind:a.z.literal("docker"),state:a.z.enum(["pending","available","stopped","unavailable"]),sampledAt:Ai,cpu:a.z.object({usagePercent:a.z.number().nonnegative()}).strict().optional(),memory:a.z.object({usageBytes:a.z.number().nonnegative(),limitBytes:a.z.number().nonnegative().optional(),usagePercent:a.z.number().nonnegative().optional()}).strict().optional(),network:a.z.object({rxBytes:a.z.number().nonnegative(),txBytes:a.z.number().nonnegative()}).strict().optional(),blockIo:a.z.object({readBytes:a.z.number().nonnegative(),writeBytes:a.z.number().nonnegative()}).strict().optional(),pids:a.z.number().int().nonnegative().optional(),error:a.z.string().trim().max(2048).optional()}).strict(),vr=a.z.object({modelEndpointProbe:a.z.boolean().optional(),aiSessionHistoryLimit:a.z.boolean().optional()}).strip(),wr=a.z.object({ok:a.z.boolean().optional(),role:a.z.string().optional(),nodeId:Si.optional(),platform:qi.optional(),arch:$i.optional(),protocolVersion:gi.optional(),capabilities:vr.optional(),build:ys.strip().optional(),process:a.z.object({pid:a.z.number().int().positive(),startIdentity:a.z.string().trim().min(1).optional()}).strip().optional(),listener:a.z.object({host:a.z.string().trim().min(1),port:a.z.number().int().min(1).max(65535)}).strip().optional(),instanceProxy:a.z.object({requests:a.z.number().int().nonnegative(),active:a.z.number().int().nonnegative(),completed:a.z.number().int().nonnegative(),aborted:a.z.number().int().nonnegative(),limitRejected:a.z.number().int().nonnegative(),responseBytes:a.z.number().nonnegative(),totalDurationMs:a.z.number().nonnegative(),maxResponseBytes:a.z.number().int().nonnegative()}).partial().strip().optional(),serverTime:Ai.optional()}).strip(),Sr=a.z.object({bindScope:a.z.enum(["loopback","all-ipv4"]),port:a.z.number().int().min(1).max(65535)}).strict().extend({host:a.z.enum(["127.0.0.1","0.0.0.0"]),status:a.z.enum(["listening","error"]),source:a.z.enum(["bootstrap","persisted"]),error:a.z.string().trim().max(2048).optional()}).strict(),Ar=a.z.object({nodeId:Si,joinToken:a.z.string().trim().min(1),expiresAt:Ai}).passthrough(),kr=a.z.object({nodeId:Si,keyId:Si,secret:a.z.string().regex(/^[A-Za-z0-9_-]{32,128}$/),pairedAt:Ai}).strict(),zr=a.z.object({id:Si,keyId:Si,name:a.z.string().trim().min(1).max(160).optional(),pairedAt:Ai,updatedAt:Ai,current:a.z.boolean()}).passthrough(),Tr=a.z.object({keyId:Si,revoked:a.z.literal(!0),revokedAt:Ai}).strict(),Er=a.z.object({id:Si,pairingKeyId:Si,url:a.z.string().trim().min(1).max(2048),name:a.z.string().trim().min(1).max(160).optional(),enabled:a.z.boolean(),createdAt:Ai,updatedAt:Ai,status:a.z.enum(["disabled","connecting","connected","reconnecting","failed"]),lastConnectedAt:Ai.optional(),lastDisconnectedAt:Ai.optional(),error:a.z.string().optional()}).passthrough(),Cr=a.z.object({pairing:zr,connection:a.z.object({id:Si,pairingKeyId:Si,url:a.z.string().trim().min(1).max(2048),name:a.z.string().trim().min(1).max(160).optional(),enabled:a.z.boolean(),createdAt:Ai,updatedAt:Ai}).passthrough(),tunnel:a.z.object({status:a.z.enum(["disabled","saved","connecting","connected","failed"]),error:a.z.string().trim().max(2048).optional()}).passthrough()}).passthrough(),xr=a.z.object({deleted:a.z.boolean().optional()}).passthrough(),Nr=a.z.object({repository:a.z.string().trim().optional(),tag:a.z.string().trim().optional(),id:a.z.string().trim(),createdSince:a.z.string().trim().optional(),size:a.z.string().trim().optional(),sizeBytes:a.z.number().int().nonnegative().optional(),reference:a.z.string().trim().min(1),repoDigests:a.z.array(a.z.string().trim().min(1).max(512)).default([])}).passthrough(),Or=a.z.object({image:rr,status:a.z.enum(["available","pull-required","unknown"]),localImage:Nr.optional(),localSizeBytes:a.z.number().int().nonnegative().optional(),downloadSizeBytes:a.z.number().int().positive().optional(),unpackedSizeBytes:a.z.number().int().positive().optional(),error:a.z.string().trim().max(2048).optional()}).strict(),_r=a.z.lazy(()=>a.z.object({name:a.z.string().trim().min(1),path:a.z.string().trim().min(1).max(4096),children:a.z.array(_r)}).passthrough()),Rr=a.z.object({status:a.z.number().int().min(100).max(599).optional(),headers:a.z.record(a.z.string(),a.z.string()).optional(),bodyBase64:a.z.string().optional()}).passthrough(),Pr=a.z.object({strategy:a.z.enum(["node-proxy","direct-port","kubernetes-ingress","kubernetes-port-forward"]).default("node-proxy"),web:a.z.string().trim().max(2048).optional(),api:a.z.string().trim().max(2048).optional(),vnc:a.z.string().trim().max(2048).optional(),tty:a.z.string().trim().max(2048).optional(),logs:a.z.string().trim().max(2048).optional(),status:a.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown")}).strict(),jr=a.z.object({strategy:a.z.enum(["control-plane-proxy","direct-port","node-proxy","kubernetes-ingress","kubernetes-port-forward"]).default("control-plane-proxy"),web:a.z.string().trim().max(2048).optional(),api:a.z.string().trim().max(2048).optional(),ws:a.z.string().trim().max(2048).optional(),status:a.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown")}).strict().default({strategy:"control-plane-proxy",status:"unknown"}),Dr=a.z.object({mode:a.z.enum(["local-bind","git-clone","empty-volume","persistent-volume"]).optional(),status:a.z.enum(["unknown","pending","ready","failed"]).default("unknown"),path:a.z.string().trim().max(4096).optional(),resolvedCommit:a.z.string().trim().max(120).optional(),error:a.z.string().trim().max(2048).optional()}).passthrough(),Mr=a.z.object({id:Si,name:a.z.string().trim().min(1).max(160),projectId:Si.optional(),source:_s,sourceSnapshot:a.z.record(a.z.string(),a.z.unknown()).default({}),modelSelection:ji,nodeId:Si,runtimeId:Si,imageSelection:Di.optional(),environmentSource:Mi.optional(),environmentTemplateOrigin:Ui.optional(),imageSnapshot:or.optional(),imageProvisioning:ar.optional(),stateRevision:a.z.number().int().min(0).default(0),processIncarnationId:a.z.string().trim().min(1).max(120).optional(),status:a.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]).default("created"),health:a.z.enum(["unknown","ok","degraded","failed"]).default("unknown"),connectionStatus:a.z.enum(["unknown","online","offline","endpoint-unreachable"]).default("unknown"),agentStatus:a.z.enum(["unknown","online","offline"]).default("unknown"),targetStatus:a.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown"),uiAccessStatus:a.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown"),controlMode:a.z.enum(["standalone","controlled"]).default("controlled"),protocolVersion:gi.optional(),instanceVersion:a.z.string().trim().max(80).optional(),build:ys.optional(),runtimeVersion:ws.optional(),ready:a.z.boolean().default(!1),capabilities:bi.default(yi),appInventory:Xi.optional(),config:a.z.object({autoImportAgentConfigs:a.z.boolean().default(!0),defaultCodexPermissionMode:de.default("ask"),aiSessionHistoryLimit:a.z.number().int().min(1).max(Ve).default(50)}).strict().default({autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask",aiSessionHistoryLimit:50}),workspace:Dr.default({status:"unknown"}),target:Pr.default({strategy:"direct-port",status:"unknown"}),access:jr,apps:a.z.object({runningCount:a.z.number().int().min(0).default(0),problemCount:a.z.number().int().min(0).default(0),updatedAt:Ai.optional(),revision:a.z.number().int().min(0).optional()}).strict().default({runningCount:0,problemCount:0}),aiSessions:Ze.default(()=>({runningCount:0,waitingCount:0,staleCount:0,sessions:[],updatedAt:(new Date).toISOString()})),triggers:a.z.object({enabledCount:a.z.number().int().min(0).default(0),runningCount:a.z.number().int().min(0).default(0),errorCount:a.z.number().int().min(0).default(0),configs:a.z.array(a.z.object({configHash:a.z.string().trim().min(1),config:fn,deployments:a.z.array(bn).default([]),runtime:a.z.array(vn).default([])}).strict()).default([]),recentRuns:a.z.array(wn).default([])}).strict().optional(),runtime:a.z.object({kind:a.z.string().trim().max(80).optional(),containerName:a.z.string().trim().max(240).optional(),containerId:a.z.string().trim().max(240).optional(),workspacePath:a.z.string().trim().max(4096).optional(),pid:a.z.number().int().positive().optional(),port:a.z.number().int().positive().max(65535).optional(),labels:a.z.record(a.z.string(),a.z.string()).default({})}).strict().default({labels:{}}),registrationToken:a.z.string().trim().min(1).max(240).optional(),lastHeartbeatAt:Ai.optional(),createdAt:Ai,updatedAt:Ai}).strict(),Lr="instance.lifecycle.snapshot",qr=a.z.object({instanceId:Mr.shape.id,revision:a.z.number().int().min(0),updatedAt:Ai,status:Mr.shape.status.unwrap(),health:Mr.shape.health.unwrap(),connectionStatus:Mr.shape.connectionStatus.unwrap(),accessStatus:a.z.enum(["reachable","endpoint-unreachable"]),imageProvisioning:ar.optional(),workspace:Dr,runtime:Mr.shape.runtime.unwrap(),runtimeVersion:ws.optional(),ready:a.z.boolean(),lastHeartbeatAt:Ai.optional()}).strict();function $r(e,t,n,i,s){if(!t||"object"!=typeof t||Array.isArray(t))return;let r=structuredClone(t);for(let t=0;t<20;t+=1){const t=e.safeParse(r);if(t.success)return t.data;let n=!1;for(const e of t.error.issues){if("unrecognized_keys"!==e.code)continue;const t=Br(r,e.path);if(t&&"object"==typeof t&&!Array.isArray(t))for(const i of e.keys)Object.prototype.hasOwnProperty.call(t,i)&&(delete t[i],n=!0)}if(!n){const n=structuredClone(r);let i=!1;for(const e of t.error.issues){if(!e.path.length||"string"!=typeof e.path.at(-1))continue;const t=Br(n,e.path.slice(0,-1)),s=e.path.at(-1);t&&"object"==typeof t&&!Array.isArray(t)&&Object.prototype.hasOwnProperty.call(t,s)&&(delete t[s],i=!0)}if(i){const t=e.safeParse(n);if(t.success)return t.data}break}}}function Br(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function Ur(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e;return Object.fromEntries(t.filter(e=>Object.prototype.hasOwnProperty.call(n,e)).map(e=>[e,n[e]]))}a.z.object({instanceId:Si.optional(),projectId:Si.optional(),source:_s.optional(),nodeId:Si.optional(),runtimeId:Si.optional(),imageSelection:Di.optional(),instanceVersion:a.z.string().trim().max(80).optional(),protocolVersion:gi,build:ys.optional(),controlMode:a.z.enum(["standalone","controlled"]).default("controlled"),capabilities:bi.default(yi),appInventory:Xi.optional(),target:Pr.default({strategy:"direct-port",status:"unknown"}),workspace:Dr.default({status:"unknown"}),registrationToken:a.z.string().trim().max(240).optional(),processIncarnationId:a.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{mi.has(e.protocolVersion)&&!e.appInventory&&t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol register payload requires appInventory."})}),a.z.object({status:Mr.shape.status.optional(),health:Mr.shape.health.optional(),protocolVersion:gi,build:ys.optional(),capabilities:Mr.shape.capabilities.optional(),appInventory:Xi.optional(),apps:Mr.shape.apps.optional(),aiSessions:Mr.shape.aiSessions.optional(),triggers:Mr.shape.triggers.optional(),workspace:Dr.optional(),target:Pr.partial().optional(),processIncarnationId:a.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{mi.has(e.protocolVersion)&&!e.appInventory&&t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol heartbeat payload requires appInventory."})});const Fr=a.z.enum(["web","telegram","wechat","dingding","lark"]),Hr=a.z.object({id:Si,channel:Fr,name:a.z.string().trim().min(1).max(160),enabled:a.z.boolean().default(!1),token:a.z.string().trim().max(4096).optional(),defaultChatId:a.z.string().trim().max(240).optional(),allowedUserIds:a.z.array(a.z.string().trim().min(1).max(240)).default([]),pollIntervalMs:a.z.number().int().positive().max(6e4).default(3e3),settings:a.z.record(a.z.string(),a.z.unknown()).default({}),createdAt:Ai,updatedAt:Ai}).strict(),Wr=a.z.object({id:Si,channel:Fr,bridgeId:Si.optional(),chatSessionId:a.z.string().trim().min(1).max(240),userId:a.z.string().trim().max(240).optional(),activeProjectId:Si.optional(),activeInstanceId:Si.optional(),activeAiSessionId:a.z.string().trim().min(1).max(120).optional(),lastUsedAt:Ai,createdAt:Ai,updatedAt:Ai}).strict(),Gr=a.z.object({source:a.z.object({type:a.z.literal("chat-gateway").default("chat-gateway"),channel:Fr,bridgeId:Si.optional(),chatSessionId:a.z.string().trim().min(1).max(240),userId:a.z.string().trim().max(240).optional()}).strict(),message:a.z.object({text:a.z.string().trim().max(2e4).default(""),attachments:a.z.array(se).max(6).default([])}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>x&&t.addIssue({code:a.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),target:a.z.object({instanceId:Si,aiSessionId:a.z.string().trim().min(1).max(120)}).strict().optional()}).strict(),Vr=a.z.object({id:Si,instanceId:Si,projectId:Si.optional(),aiSessionId:a.z.string().trim().min(1).max(120),providerSessionId:a.z.string().trim().max(240).optional(),result:a.z.string().default(""),timeoutMs:a.z.number().positive().optional(),source:a.z.string().trim().max(120).optional(),kind:a.z.enum(["task","approval"]).default("task"),status:a.z.enum(["pending","unreachable"]).default("pending"),error:a.z.string().trim().max(2048).optional(),lastSeenAt:Ai}).strict();function Kr(e){return!1!==e.ready&&(!e.runtimeVersion||["matched","failed"].includes(e.runtimeVersion.phase))}const Jr=6048e5;function Yr(e,n){const i=t.resolve(e),s=t.resolve(i,n);if(t.dirname(s)!==i||t.basename(s)!==n)throw new Error(`Retention entry is not a direct child of its managed root: ${n}`);return s}function Qr(e){if(n.existsSync(e)){const t=n.lstatSync(e);if(!t.isDirectory()||t.isSymbolicLink())throw new Error(`Managed persistence path must be a real directory: ${e}`)}n.mkdirSync(e,{recursive:!0,mode:448}),n.chmodSync(e,448)}function Xr(e){return e.startsWith("ai-session.")||e.startsWith("ai.session.")?"ai.sessions":e.startsWith("app-session.")?"app.sessions":e.startsWith("app.management")?"apps":e.startsWith("trigger.")?"triggers":e.startsWith("instance.")?"instances":e.startsWith("node.")?"nodes":e.startsWith("project.")?"projects":e.startsWith("model.")?"models":e.startsWith("image.")?"images":e.startsWith("market.")?"market":"system"}const Zr=a.z.enum(["ai.sessions","app.sessions"]),eo=a.z.object({topic:Zr,instanceId:a.z.string().trim().min(1).max(160),streamId:a.z.string().trim().min(1).max(240),latestRevision:a.z.number().int().min(0),earliestRetainedRevision:a.z.number().int().min(0)}).strict(),to=a.z.object({protocolVersion:a.z.literal(1),streams:a.z.array(eo)}).strict(),no=a.z.object({authentication:a.z.enum(["required","disabled"]),aiSessions:a.z.boolean(),nodes:a.z.boolean(),instanceBoard:a.z.boolean(),triggers:a.z.boolean().optional()}).strict(),io=a.z.object({version:a.z.literal(1),kind:a.z.literal("control-plane"),controlPlaneId:a.z.string().trim().min(1).max(160),publicKey:a.z.object({algorithm:a.z.literal("Ed25519"),encoding:a.z.literal("base64url"),value:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:a.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/)}).strict(),capabilities:no,protocolVersion:a.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),issuedAt:a.z.string().datetime(),expiresAt:a.z.string().datetime()}).strict(),so=a.z.object({data:a.z.object({payload:io,signature:a.z.string().regex(/^[A-Za-z0-9_-]{86}$/)}).strict()}).strict(),ro=a.z.object({id:a.z.string().trim().min(8).max(160),name:a.z.string().trim().min(1).max(160),platform:a.z.enum(["ios","android"]),appVersion:a.z.string().trim().min(1).max(80).optional()}).strict(),oo=a.z.object({username:a.z.string().trim().min(1).max(80),password:a.z.string().min(1).max(4096),device:ro}).strict(),ao=a.z.object({id:a.z.string().trim().min(1),username:a.z.string().trim().min(1).max(80),role:a.z.enum(["viewer","operator","admin"]),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime(),lastLoginAt:a.z.string().datetime().optional()}).strict(),co=a.z.object({id:a.z.string().trim().min(1),expiresAt:a.z.string().datetime(),createdAt:a.z.string().datetime(),lastSeenAt:a.z.string().datetime().optional(),device:ro,user:ao}).strict();a.z.object({data:a.z.object({sessionToken:a.z.string().trim().min(32),session:co}).strict()}).strict(),a.z.object({data:a.z.array(co)}).strict(),a.z.object({data:a.z.object({revoked:a.z.boolean()}).strict()}).strict();function lo(e,t=448){n.mkdirSync(e,{recursive:!0,mode:t}),n.chmodSync(e,t)}function po(e,i,s={}){const r=s.directoryMode??448,o=s.fileMode??384;lo(t.dirname(e),r),c.sync(e,`${JSON.stringify(i,null,2)}\n`,{encoding:"utf8",mode:o}),n.chmodSync(e,o)}function uo(e,t){console.warn(JSON.stringify({message:e,...t}))}function mo(e){return e&&"object"==typeof e&&"issues"in e?{issues:e.issues}:{error:e instanceof Error?e.message:String(e)}}function go(e,t){const i=t.logger||uo;let s;try{s=JSON.parse(n.readFileSync(e,"utf8"))}catch(t){return void i("stored JSON could not be read",{filePath:e,...mo(t)})}if(!t.schema)return s;const r=t.sanitize?t.sanitize(s):s,o=t.schema.safeParse(r);if(o.success)return o.data;const a="strip"in t.schema&&"function"==typeof t.schema.strip?t.schema.strip().safeParse(r):void 0;if(a?.success)return i("unknown stored fields were ignored",{filePath:e,issues:o.error.issues}),a.data;i("stored record failed validation and was isolated",{filePath:e,issues:o.error.issues})}function ho(e){return`${e}_${i.randomUUID().replace(/-/g,"").slice(0,20)}`}function yo(){return i.randomBytes(24).toString("base64url")}class fo{directory;options;permissionsInitialized=!1;constructor(e,t={}){this.directory=e,this.options=t}init(){if(this.permissionsInitialized&&n.existsSync(this.directory))return;lo(this.directory,this.options.directoryMode??448);const e=this.options.fileMode??384;for(const i of n.readdirSync(this.directory).filter(e=>e.endsWith(".json")))n.chmodSync(t.join(this.directory,i),e);this.permissionsInitialized=!0}filePath(e){return t.join(this.directory,`${e}.json`)}list(){return this.init(),n.readdirSync(this.directory).filter(e=>e.endsWith(".json")).sort().flatMap(e=>{const n=go(t.join(this.directory,e),this.options);return n?[n]:[]})}get(e){this.init();const t=this.filePath(e);return n.existsSync(t)?go(t,this.options):void 0}put(e){const t=this.options.sanitize?this.options.sanitize(e):e,n=this.options.schema?this.options.schema.parse(t):t;return po(this.filePath(n.id),n,this.options),n}patch(e,t){const n=this.get(e);if(!n)return;const i={...n,...t,id:n.id,createdAt:n.createdAt,updatedAt:(new Date).toISOString()};return this.put(i)}delete(e){const t=this.filePath(e);return!!n.existsSync(t)&&(n.unlinkSync(t),!0)}}class Io{filePathValue;defaults;options;constructor(e,t,n={}){this.filePathValue=e,this.defaults=t,this.options=n}init(){lo(t.dirname(this.filePathValue),this.options.directoryMode??448),n.existsSync(this.filePathValue)?n.chmodSync(this.filePathValue,this.options.fileMode??384):this.put(this.defaults())}get(){return this.init(),n.existsSync(this.filePathValue)?go(this.filePathValue,this.options)??this.defaults():this.defaults()}put(e){const t=this.options.sanitize?this.options.sanitize(e):e,n=this.options.schema?this.options.schema.parse(t):t;return po(this.filePathValue,n,this.options),n}}const bo=d.promisify(i.scrypt),vo="task_handoff_cp_session",wo=a.z.enum(["disabled","password"]),So=a.z.string().trim().min(1).max(80).regex(/^[a-zA-Z0-9_.@-]+$/),Ao=a.z.string().min(8).max(4096),ko=a.z.object({username:So,password:Ao}).strict(),zo=a.z.object({username:a.z.string().trim().min(1).max(80),password:a.z.string().min(1).max(4096)}).strict(),To=a.z.object({currentPassword:a.z.string().min(1).max(4096),newPassword:Ao}).strict(),Eo=a.z.object({username:So,password:Ao}).strict(),Co=a.z.object({id:a.z.string().trim().min(1),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}),xo=Co.extend({username:So,passwordHash:a.z.string().trim().min(1),role:a.z.enum(["viewer","operator","admin"]),lastLoginAt:a.z.string().datetime().optional()}).strict(),No=Co.extend({userId:a.z.string().trim().min(1),tokenHash:a.z.string().trim().min(1),expiresAt:a.z.string().datetime(),lastSeenAt:a.z.string().datetime().optional(),clientType:a.z.enum(["web","mobile"]).default("web"),device:ro.optional()}).strict().refine(e=>"mobile"!==e.clientType||Boolean(e.device),{path:["device"],message:"Mobile sessions require device metadata."});function Oo(){return(new Date).toISOString()}function _o(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}class Ro{options;sourceFailures=new Map;usernameFailures=new Map;concurrent=0;constructor(e={}){this.options=function(e={}){return{windowMs:_o(e.windowMs,9e5),maxFailuresPerSource:_o(e.maxFailuresPerSource,20),maxFailuresPerUsername:_o(e.maxFailuresPerUsername,10),maxConcurrent:_o(e.maxConcurrent,4)}}(e)}begin(e,t){const n=Date.now();if(this.assertBucketAvailable(this.sourceFailures,e,this.options.maxFailuresPerSource,n),this.assertBucketAvailable(this.usernameFailures,t,this.options.maxFailuresPerUsername,n),this.concurrent>=this.options.maxConcurrent)throw Po("Too many password verifications are already in progress.",1e3);this.concurrent+=1}finish(){this.concurrent=Math.max(0,this.concurrent-1)}recordFailure(e,t){const n=Date.now();this.record(this.sourceFailures,e,n),this.record(this.usernameFailures,t,n),this.sourceFailures.size+this.usernameFailures.size>1e4&&(this.pruneAll(n),this.trimOldest(this.sourceFailures,5e3),this.trimOldest(this.usernameFailures,5e3))}assertBucketAvailable(e,t,n,i){const s=this.currentFailures(e,t,i);if(!(s.length<n))throw Po("Too many failed sign-in attempts. Try again later.",s[0]+this.options.windowMs-i)}record(e,t,n){const i=this.currentFailures(e,t,n);i.push(n),e.set(t,i)}currentFailures(e,t,n){const i=n-this.options.windowMs,s=(e.get(t)||[]).filter(e=>e>i);return s.length?e.set(t,s):e.delete(t),s}pruneAll(e){for(const[t]of this.sourceFailures)this.currentFailures(this.sourceFailures,t,e);for(const[t]of this.usernameFailures)this.currentFailures(this.usernameFailures,t,e)}trimOldest(e,t){for(;e.size>t;){const t=e.keys().next().value;if(void 0===t)return;e.delete(t)}}}function Po(e,t){const n=new Error(e);return Object.assign(n,{statusCode:429,code:"AUTH_LOGIN_RATE_LIMITED",retryable:!0,retryAfterSeconds:Math.max(1,Math.ceil(t/1e3))}),n}function jo(e){return i.createHash("sha256").update(e).digest("base64url")}async function Do(e){const t=i.randomBytes(16).toString("base64url");return`scrypt$${t}$${(await bo(e,t,64)).toString("base64url")}`}async function Mo(e,t){const[n,s,r]=t.split("$");if("scrypt"!==n||!s||!r)return!1;const o=await bo(e,s,64),a=Buffer.from(r,"base64url");return a.length===o.length&&i.timingSafeEqual(a,o)}function Lo(e){return{id:e.id,username:e.username,role:e.role,createdAt:e.createdAt,updatedAt:e.updatedAt,lastLoginAt:e.lastLoginAt}}function qo(e,t){return co.parse({id:e.id,expiresAt:e.expiresAt,createdAt:e.createdAt,lastSeenAt:e.lastSeenAt,device:e.device,user:Lo(t)})}class $o{mode;users;sessions;loginRateLimiter;bootstrapAdminInProgress=!1;credentialUpdateInProgress=!1;constructor(e,t={}){this.mode=function(e={}){return wo.parse(e.mode||process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"disabled")}(t),this.users=new fo(e.authUsersDir,{schema:xo}),this.sessions=new fo(e.authSessionsDir,{schema:No}),this.loginRateLimiter=new Ro(t.loginRateLimit)}init(){this.users.init(),this.sessions.init()}enabled(){return"password"===this.mode}state(){return{mode:this.mode,enabled:this.enabled(),requiresBootstrap:this.enabled()&&0===this.users.list().length}}async bootstrapAdmin(e){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}if(this.bootstrapAdminInProgress){const e=new Error("Control Plane admin initialization is already in progress.");throw Object.assign(e,{statusCode:409,code:"AUTH_BOOTSTRAP_IN_PROGRESS"}),e}if(this.users.list().length>0){const e=new Error("Control Plane admin user already exists.");throw Object.assign(e,{statusCode:409,code:"AUTH_BOOTSTRAP_ALREADY_DONE"}),e}const t=ko.parse(e);this.bootstrapAdminInProgress=!0;try{const e=Oo();return Lo(this.users.put({id:ho("user"),username:t.username,passwordHash:await Do(t.password),role:"admin",createdAt:e,updatedAt:e}))}finally{this.bootstrapAdminInProgress=!1}}async login(e,t={}){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}const n=zo.parse(e),i=await this.authenticate(n.username,n.password,t),s=this.createSession(i,"web");return{user:Lo(i),sessionToken:s.token,expiresAt:s.record.expiresAt}}async loginMobile(e,t={}){const n=oo.parse(e),i=await this.authenticate(n.username,n.password,t),s=this.createSession(i,"mobile",n.device);return{sessionToken:s.token,session:qo(s.record,i)}}async changePassword(e,t,n={}){const i=this.resolveSessionToken(e,"web");if(!i){const e=new Error("Sign in to change the password.");throw Object.assign(e,{statusCode:401,code:"CONTROL_PLANE_AUTH_REQUIRED"}),e}const s=To.parse(t);if(this.credentialUpdateInProgress){const e=new Error("Control Plane credentials are already being updated.");throw Object.assign(e,{statusCode:409,code:"AUTH_CREDENTIAL_UPDATE_IN_PROGRESS"}),e}this.credentialUpdateInProgress=!0;const r=String(n.sourceId||"unknown").trim()||"unknown",o=i.storedUser.username.toLocaleLowerCase("en-US");let a=!1;try{if(this.loginRateLimiter.begin(r,o),a=!0,!await Mo(s.currentPassword,i.storedUser.passwordHash)){this.loginRateLimiter.recordFailure(r,o);const e=new Error("The current password is incorrect.");throw Object.assign(e,{statusCode:400,code:"AUTH_CURRENT_PASSWORD_INVALID"}),e}if(await Mo(s.newPassword,i.storedUser.passwordHash)){const e=new Error("The new password must be different from the current password.");throw Object.assign(e,{statusCode:400,code:"AUTH_PASSWORD_UNCHANGED"}),e}const e=Oo(),t=this.users.put({...i.storedUser,passwordHash:await Do(s.newPassword),updatedAt:e});this.revokeUserSessions(t.id);const n=this.createSession(t,"web");return{user:Lo(t),sessionToken:n.token,expiresAt:n.record.expiresAt}}finally{a&&this.loginRateLimiter.finish(),this.credentialUpdateInProgress=!1}}async replaceCredentials(e){const t=Eo.parse(e),n=this.users.list();if(0===n.length){const e=new Error("Control Plane administrator has not been initialized.");throw Object.assign(e,{statusCode:409,code:"AUTH_ACCOUNT_NOT_INITIALIZED"}),e}if(1!==n.length){const e=new Error("The account to update is ambiguous.");throw Object.assign(e,{statusCode:409,code:"AUTH_ACCOUNT_AMBIGUOUS"}),e}const i=Oo(),s=this.users.put({...n[0],username:t.username,passwordHash:await Do(t.password),updatedAt:i});return this.revokeUserSessions(s.id),Lo(s)}async authenticate(e,t,n){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}const i=String(n.sourceId||"unknown").trim()||"unknown",s=e.toLocaleLowerCase("en-US");this.loginRateLimiter.begin(i,s);try{const n=this.users.list().find(t=>t.username===e);if(!n||!await Mo(t,n.passwordHash)){this.loginRateLimiter.recordFailure(i,s);const e=new Error("Invalid username or password.");throw Object.assign(e,{statusCode:401,code:"AUTH_LOGIN_FAILED"}),e}const r=Oo();return this.users.put({...n,lastLoginAt:r,updatedAt:r})}finally{this.loginRateLimiter.finish()}}createSession(e,t,n){const i=Oo(),s=yo(),r=this.sessions.put({id:ho("mobile"===t?"msess":"sess"),userId:e.id,tokenHash:jo(s),expiresAt:new Date(Date.now()+12096e5).toISOString(),createdAt:i,updatedAt:i,lastSeenAt:i,clientType:t,...n?{device:n}:{}});return{record:r,token:`${r.id}.${s}`}}revokeUserSessions(e){for(const t of this.sessions.list())t.userId===e&&this.sessions.delete(t.id)}async userForSessionToken(e){const t=this.resolveSessionToken(e,"web");return t?.user}async userForMobileSessionToken(e){const t=this.resolveSessionToken(e,"mobile");return t?.user}resolveSessionToken(e,t){if(!this.enabled()||!e)return;const[n,i]=e.split(".");if(!n||!i)return;const s=this.sessions.get(n);if(!s||t&&s.clientType!==t||s.expiresAt<=Oo()||s.tokenHash!==jo(i))return;const r=this.users.get(s.userId);if(!r)return;const o=Oo();return{session:this.sessions.put({...s,lastSeenAt:o,updatedAt:o}),user:Lo(r),storedUser:r}}async currentSession(e,t="web"){const n=this.state(),i="mobile"===t?await this.userForMobileSessionToken(e):await this.userForSessionToken(e);return{...n,authenticated:!this.enabled()||Boolean(i),user:i}}logout(e){const t=e?.split(".")[0];return t&&this.sessions.delete(t),{ok:!0}}mobileSessions(e){const t=this.resolveSessionToken(e);if(t)return this.sessions.list().filter(e=>"mobile"===e.clientType&&e.userId===t.storedUser.id&&e.expiresAt>Oo()).map(e=>qo(e,t.storedUser))}revokeMobileSession(e,t){const n=this.resolveSessionToken(e);if(!n)return;const i=this.sessions.get(t);return!(!i||"mobile"!==i.clientType||i.userId!==n.storedUser.id)&&this.sessions.delete(i.id)}}function Bo(e,t){let n=Go(t);for(let t=0;t<100;t+=1){const t=e.safeParse(n);if(t.success)return t;const i=Fo(t.error.issues);let s=!1;for(const e of i){const t=Wo(n,e.path);if(t&&"object"==typeof t&&!Array.isArray(t))for(const n of e.keys)Object.prototype.hasOwnProperty.call(t,n)&&(delete t[n],s=!0)}if(!s)return t}return e.safeParse(n)}function Uo(e,t){const n=Bo(e,t);if(!n.success)throw n.error;return n.data}function Fo(e,t=[]){const n=[];for(const i of e){if("unrecognized_keys"===i.code){n.push({code:"unrecognized_keys",keys:i.keys,path:[...t,...i.path]});continue}if("invalid_union"!==i.code||!Array.isArray(i.errors))continue;const e=i.errors.filter(e=>Array.isArray(e));if(!e.length)continue;const s=e.reduce((e,t)=>Ho(t)<Ho(e)?t:e);n.push(...Fo(s,[...t,...i.path]))}return n}function Ho(e){return e.reduce((e,t)=>{if("unrecognized_keys"===t.code)return e;if("invalid_union"!==t.code||!Array.isArray(t.errors))return e+1;const n=t.errors.filter(e=>Array.isArray(e));return e+(n.length?Math.min(...n.map(Ho)):1)},0)}function Wo(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function Go(e){return Array.isArray(e)?e.map(Go):e&&"object"==typeof e?Object.getPrototypeOf(e)!==Object.prototype&&null!==Object.getPrototypeOf(e)?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,Go(t)])):e}const Vo=a.z.enum(["import","export"]),Ko=a.z.object({id:a.z.string().trim().min(1).max(120),label:a.z.string().trim().min(1).max(120),directoryName:a.z.string().trim().min(1).max(120)}).strict(),Jo=a.z.object({direction:Vo,programIds:a.z.array(a.z.string().trim().min(1).max(120)).min(1).max(20).refine(e=>new Set(e).size===e.length,"Config sync program ids must be unique."),workspaceFolder:a.z.string().trim().min(1).max(1e3)}).strict(),Yo=a.z.object({import:a.z.string().trim().min(1).max(1e3).default("."),export:a.z.string().trim().min(1).max(1e3).default(".")}).strict(),Qo=a.z.object({programs:a.z.array(Ko),preferences:Yo}).strict(),Xo=a.z.object({id:a.z.string().trim().min(1).max(120),type:a.z.enum(["file","dir"]),projectPath:a.z.string().trim().min(1).max(1e3),containerPath:a.z.string().trim().min(1).max(1e3),source:a.z.string().trim().min(1).max(4096),target:a.z.string().trim().min(1).max(4096),status:a.z.enum(["copied","skipped_missing_source","failed"]),error:a.z.string().trim().max(4096).optional()}).strict(),Zo=a.z.object({preset:a.z.object({id:a.z.string().trim().min(1).max(120),label:a.z.string().trim().min(1).max(120),projectRoot:a.z.string().trim().min(1).max(1e3)}).strict(),direction:Vo,items:a.z.array(Xo).max(100)}).strict(),ea=a.z.object({direction:Vo,workspaceFolder:a.z.string().trim().min(1).max(1e3),programs:a.z.array(Zo).min(1).max(20)}).strict(),ta=a.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),na=a.z.string().datetime(),ia=a.z.string().trim().min(1).max(255).refine(e=>!(/[\u0000-\u001f\u007f ~^:?*[\\]/.test(e)||e.includes("..")||e.endsWith(".")||e.endsWith("/")),"Invalid Git name."),sa=a.z.string().min(1).max(4096).refine(e=>!(e.includes("\0")||e.startsWith("/")||e.startsWith("\\")||/^[a-zA-Z]:[\\/]/.test(e))&&e.split("/").every(e=>e.length>0&&"."!==e&&".."!==e&&".git"!==e),"Path must be a safe repository-relative path."),ra=a.z.enum(["ai-session","app-session"]),oa=a.z.enum(["available","session-not-found","session-inactive","cwd-missing","cwd-inaccessible","git-unavailable","not-worktree"]),aa=a.z.enum(["branch","detached","unborn"]),da=a.z.enum(["review-changes","resolve-conflicts","publish-branch","push","pull","diverged","up-to-date"]),ca=a.z.enum(["conflict","staged","unstaged","untracked"]),la=a.z.enum(["added","modified","deleted","renamed","copied","type-changed","unmerged","untracked"]),pa=a.z.object({state:aa,oid:a.z.string().regex(/^[0-9a-f]{40,64}$/).optional(),branch:a.z.string().min(1).max(1024).optional()}).strict(),ua=a.z.object({ref:a.z.string().min(1).max(2048),remote:ia,branch:a.z.string().min(1).max(1024),ahead:a.z.number().int().nonnegative(),behind:a.z.number().int().nonnegative()}).strict(),ma=a.z.object({id:ta,isCurrent:a.z.boolean(),isMain:a.z.boolean(),managed:a.z.boolean(),head:pa,dirty:a.z.boolean(),locked:a.z.boolean(),lockReason:a.z.string().max(1e3).optional(),prunable:a.z.boolean(),activeAiSessionIds:a.z.array(ta).max(256).default([]),activeAppSessionIds:a.z.array(ta).max(256).default([])}).strict(),ga=a.z.enum(["main-worktree","external-worktree","outside-workspace-roots","dirty","locked","prunable","session-occupied","path-inaccessible"]),ha=ma.extend({canCreateAiSession:a.z.boolean(),canRemove:a.z.boolean(),createAiSessionBlockers:a.z.array(ga).max(16).default([]),removeBlockers:a.z.array(ga).max(16).default([])}).strict(),ya=a.z.object({repositoryId:ta,repositoryContextId:ta,snapshotId:ta,items:a.z.array(ha).max(1e4)}).strict(),fa=a.z.object({conflicts:a.z.number().int().nonnegative(),staged:a.z.number().int().nonnegative(),unstaged:a.z.number().int().nonnegative(),untracked:a.z.number().int().nonnegative()}).strict(),Ia=a.z.object({name:ia,fetchUrl:a.z.string().max(4096).optional(),pushUrl:a.z.string().max(4096).optional()}).strict(),ba=a.z.object({availability:oa,sessionKind:ra,sessionId:ta,observedAt:na,snapshotId:ta.optional(),repositoryId:ta.optional(),repositoryContextId:ta.optional(),repositoryRoot:a.z.string().min(1).max(4096).optional(),displayName:a.z.string().trim().min(1).max(255).optional(),cwdRelativePath:a.z.string().max(4096).optional(),head:pa.optional(),upstream:ua.optional(),currentWorktree:ma.optional(),changes:fa.optional(),remotes:a.z.array(Ia).max(128).optional(),primaryAction:da.optional()}).strict(),va=a.z.enum(["directory","file","symlink","submodule","nested-repository","special"]),wa=a.z.object({executable:a.z.boolean(),gitMode:a.z.enum(["100644","100755","120000","160000"]).optional()}).strict(),Sa=a.z.object({name:a.z.string().min(1).max(1024),path:sa,kind:va,traversable:a.z.boolean(),editable:a.z.boolean(),size:a.z.number().int().nonnegative().optional(),mode:wa.optional()}).strict();a.z.object({path:a.z.string().max(4096),entries:a.z.array(Sa).max(1e4),snapshotId:ta}).strict();const Aa=a.z.string().min(16).max(160).regex(/^[a-zA-Z0-9_.:-]+$/),ka=a.z.object({path:sa,content:a.z.string(),byteLength:a.z.number().int().nonnegative(),version:Aa,mode:wa}).strict(),za=a.z.object({path:sa,oldPath:sa.optional(),scope:ca,status:la,version:Aa,binary:a.z.boolean().default(!1)}).strict(),Ta=a.z.object({snapshotId:ta,summary:fa,entries:a.z.array(za).max(1e5)}).strict();a.z.object({file:ka.optional(),snapshotId:ta,context:ba,changes:Ta}).strict();const Ea=a.z.object({kind:a.z.enum(["metadata","hunk","context","addition","deletion"]),content:a.z.string(),oldLine:a.z.number().int().positive().optional(),newLine:a.z.number().int().positive().optional(),oldStart:a.z.number().int().nonnegative().optional(),oldCount:a.z.number().int().nonnegative().optional(),newStart:a.z.number().int().nonnegative().optional(),newCount:a.z.number().int().nonnegative().optional(),heading:a.z.string().optional(),hunkId:a.z.string().min(1).max(200).optional()}).strict();a.z.object({path:sa,oldPath:sa.optional(),scope:ca,binary:a.z.boolean(),complete:a.z.boolean(),truncated:a.z.boolean(),byteLimit:a.z.number().int().positive(),content:a.z.string(),lines:a.z.array(Ea).max(2e5),contextGaps:a.z.array(a.z.object({gapId:a.z.string().min(1).max(500),beforeHunkId:a.z.string().min(1).max(200).optional(),afterHunkId:a.z.string().min(1).max(200).optional(),lines:a.z.array(Ea).max(6e3),startLineCount:a.z.number().int().nonnegative().max(3e3),hasMore:a.z.boolean()}).strict()).max(2e4),version:Aa,snapshotId:ta}).strict();const Ca=a.z.object({name:a.z.string().min(1).max(1024),oid:a.z.string().regex(/^[0-9a-f]{40,64}$/),kind:a.z.enum(["local","remote-tracking"]),current:a.z.boolean(),upstream:a.z.string().min(1).max(2048).optional(),ahead:a.z.number().int().nonnegative().optional(),behind:a.z.number().int().nonnegative().optional(),checkedOutWorktreeIds:a.z.array(ta).max(256).default([])}).strict(),xa=a.z.object({snapshotId:ta,branches:a.z.array(Ca).max(1e5)}).strict();a.z.object({snapshotId:ta,context:ba,branches:xa}).strict(),a.z.object({ok:a.z.literal(!0),snapshotId:ta,context:ba,changes:Ta.optional(),commitOid:a.z.string().regex(/^[0-9a-f]{40,64}$/).optional()}).strict();const Na=a.z.enum(["REPOSITORY_REQUEST_INVALID","REPOSITORY_SESSION_NOT_FOUND","REPOSITORY_SESSION_INACTIVE","REPOSITORY_CWD_MISSING","REPOSITORY_CWD_INACCESSIBLE","REPOSITORY_GIT_UNAVAILABLE","REPOSITORY_NOT_WORKTREE","REPOSITORY_PATH_INVALID","REPOSITORY_PATH_FORBIDDEN","REPOSITORY_FILE_NOT_FOUND","REPOSITORY_FILE_EXISTS","REPOSITORY_FILE_UNSUPPORTED","REPOSITORY_FILE_TOO_LARGE","REPOSITORY_FILE_BINARY","REPOSITORY_FILE_STALE","REPOSITORY_STATE_STALE","REPOSITORY_WORKTREE_NOT_FOUND","REPOSITORY_WORKTREE_OCCUPIED","REPOSITORY_WORKTREE_UNSAFE","REPOSITORY_BRANCH_INVALID","REPOSITORY_BRANCH_OCCUPIED","REPOSITORY_BRANCH_UNMERGED","REPOSITORY_CONFLICT","REPOSITORY_DIRTY","REPOSITORY_NOTHING_TO_COMMIT","REPOSITORY_IDENTITY_MISSING","REPOSITORY_HOOK_FAILED","REPOSITORY_SIGNING_FAILED","REPOSITORY_AUTHENTICATION_FAILED","REPOSITORY_NON_FAST_FORWARD","REPOSITORY_UPSTREAM_MISSING","REPOSITORY_COMMAND_TIMEOUT","REPOSITORY_OUTPUT_LIMIT","REPOSITORY_OPERATION_ABORTED","REPOSITORY_OPERATION_FAILED"]);a.z.object({ok:a.z.literal(!1),error:a.z.object({code:Na,message:a.z.string().trim().min(1).max(2e3),retryable:a.z.boolean(),details:a.z.record(a.z.string(),a.z.union([a.z.string(),a.z.number(),a.z.boolean()])).optional()}).strict()}).strict();const Oa=a.z.object({expectedSnapshotId:ta}).strict(),_a=a.z.object({path:sa,expectedVersion:Aa}).strict();a.z.object({path:sa,content:a.z.string().max(4194304),expectedAbsent:a.z.literal(!0),expectedSnapshotId:ta}).strict(),a.z.object({path:sa,content:a.z.string().max(4194304),expectedVersion:Aa,expectedSnapshotId:ta}).strict(),a.z.object({path:sa,destination:sa,expectedVersion:Aa,expectedDestinationAbsent:a.z.literal(!0),expectedSnapshotId:ta}).strict(),a.z.object({path:sa,expectedVersion:Aa,expectedSnapshotId:ta,confirm:a.z.literal(!0)}).strict(),Oa.extend({paths:a.z.array(_a).min(1).max(1e3)}).strict(),Oa.extend({paths:a.z.array(_a).min(1).max(1e3)}).strict(),Oa.extend({paths:a.z.array(_a).min(1).max(1e3),confirm:a.z.literal(!0)}).strict(),Oa.extend({paths:a.z.array(_a).min(1).max(1e3),confirm:a.z.literal(!0)}).strict(),Oa.extend({message:a.z.string().trim().min(1).max(65536)}).strict();const Ra=a.z.discriminatedUnion("mode",[a.z.object({mode:a.z.literal("new-branch"),branchName:ia,startRef:a.z.string().trim().min(1).max(2048),expectedSnapshotId:ta}).strict(),a.z.object({mode:a.z.literal("existing-branch"),branchName:ia,expectedSnapshotId:ta}).strict()]);Oa.extend({worktreeId:ta,confirm:a.z.literal(!0)}).strict(),a.z.object({worktreeId:ta,worktrees:ya}).strict(),a.z.object({removedWorktreeId:ta,branchRetained:a.z.boolean(),worktrees:ya}).strict();const Pa=a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("current")}).strict(),a.z.object({type:a.z.literal("worktree"),repositoryContextId:ta,worktreeId:ta}).strict()]);a.z.object({agent:a.z.enum(["codex","claude"]),workspaceSelection:Pa,message:a.z.string().trim().min(1).max(2e4),clientRequestId:ta,permissionMode:a.z.enum(["ask","auto-review","full-access"]).optional()}).strict(),a.z.object({agent:a.z.enum(["codex","claude"]),worktree:Ra,message:a.z.string().trim().min(1).max(2e4),clientRequestId:ta,permissionMode:a.z.enum(["ask","auto-review","full-access"]).optional()}).strict(),a.z.object({aiSessionId:ta,providerSessionId:a.z.string().trim().min(1).max(240),worktreeId:ta,disposition:a.z.literal("started")}).strict();const ja=a.z.object({name:a.z.string().min(1).max(1024),kind:a.z.enum(["branch","head"]).default("branch"),current:a.z.boolean(),currentFolderSelectable:a.z.boolean(),worktreeSelectable:a.z.boolean(),worktreeCheckout:a.z.enum(["attached","detached"]).default("attached"),currentFolderReason:a.z.enum(["dirty","session-occupied","branch-occupied"]).optional(),worktreeReason:a.z.enum(["current-branch","branch-occupied","worktree-unavailable"]).optional()}).strict(),Da=a.z.object({availability:oa,currentBranch:a.z.string().min(1).max(1024).optional(),dirty:a.z.boolean().default(!1),branches:a.z.array(ja).max(1e5).default([])}).strict();a.z.object({cwd:ke}).strict();const Ma=Te;ze.extend({gitSelection:Ma}).strict(),Oa.extend({name:ia}).strict(),Oa.extend({branch:a.z.string().trim().min(1).max(2048)}).strict(),Oa.extend({name:ia,remoteTrackingRef:a.z.string().trim().min(1).max(2048)}).strict(),Oa.extend({name:ia,confirm:a.z.literal(!0)}).strict(),Oa.extend({remote:ia}).strict(),Oa.extend({remote:ia,sourceBranch:ia,targetBranch:ia,setUpstream:a.z.boolean(),confirmSetUpstream:a.z.boolean().optional()}).strict().refine(e=>!e.setUpstream||!0===e.confirmSetUpstream,{message:"Setting an upstream requires explicit confirmation.",path:["confirmSetUpstream"]}),Oa.extend({remote:ia,sourceBranch:ia,targetBranch:ia}).strict();class La{options;resumeSnapshotRefreshFailures=0;lastResumeSnapshotRefreshFailure;constructor(e){this.options=e}async resolveApproval(e,t,n){return Uo(Ge,await this.post(e,Fa(t,"approval"),{decision:n}))}async listHistory(e){return Uo(Je,await this.get(e,"/ai-sessions/history"))}async historyDetail(e,t){return Uo(Ye,await this.get(e,`/ai-sessions/history/${encodeURIComponent(t)}`))}async timeline(e,t){const n=await this.options.requireInstance(e);if(!function(e){return wi(e.capabilities,"session-read").length>0}(n))throw function(){const e=new Error("The controlled instance does not support AI session Timeline reads.");return Object.assign(e,{statusCode:409,code:"AI_SESSION_TIMELINE_UNSUPPORTED"}),e}();return Uo(K,await this.options.request(n,Fa(t,"timeline"),{method:"GET"}))}async turnTimeline(e,t,n){const i=await this.options.requireInstance(e);if(!function(e){return wi(e.capabilities,"turn-read").length>0}(i))throw function(){const e=new Error("The controlled instance does not support per-turn AI session Timeline reads.");return Object.assign(e,{statusCode:409,code:"AI_SESSION_TURN_TIMELINE_UNSUPPORTED"}),e}();return Uo(J,await this.options.request(i,`${Fa(t,"turns")}/${encodeURIComponent(n)}/timeline`,{method:"GET"}))}async resume(e,t){const n=Uo(Qe,await this.post(e,Fa(t,"resume"),{}));return await this.refreshAfterCommittedResume(e,t),n}async create(e,t){Wa(t.attachments||[]);const n=await this.options.requireInstance(e),i=qa(n);if(t.gitSelection&&!i)throw $a();const s=t.permissionMode||("codex"===t.agent?n.config.defaultCodexPermissionMode:void 0),r=t.gitSelection?"/repository/ai-session-workspace/create":"/ai-sessions",{cwdFolderId:o,...a}=t;return Uo(Ce,await this.options.request(n,r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a,...i&&o?{cwdFolderId:o}:{},...s?{permissionMode:s}:{}})}))}async inspectWorkspace(e,t){const n=await this.options.requireInstance(e);if(!qa(n))throw $a();return Uo(Da,await this.options.request(n,"/repository/ai-session-workspace/inspect",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cwd:t})}))}async fork(e,t,n){const i=Uo(Oe,await this.post(e,Fa(t,"fork"),n));try{await this.options.refreshSnapshots()}catch(n){try{this.options.warn?.({instanceId:e,aiSessionId:t,providerSessionId:i.providerSessionId,code:Ba(n),message:Ua(n)},"AI session Fork committed but snapshot refresh failed")}catch{}}return i}async openApp(e,t,n){return Uo(Re,await this.post(e,Fa(t,"open-app"),{clientRequestId:n}))}async close(e,t,n){return Uo(je,await this.post(e,Fa(t,"close"),{clientRequestId:n}))}async refreshAfterCommittedResume(e,t){try{await this.options.refreshSnapshots()}catch(n){const i={instanceId:e,aiSessionId:t,code:Ba(n),message:Ua(n),occurredAt:(new Date).toISOString()};this.resumeSnapshotRefreshFailures+=1,this.lastResumeSnapshotRefreshFailure=i;try{this.options.warn?.(i,"AI session resumed but snapshot refresh failed")}catch{}}}diagnostics(){return{resumeSnapshotRefreshFailures:this.resumeSnapshotRefreshFailures,lastResumeSnapshotRefreshFailure:this.lastResumeSnapshotRefreshFailure}}async sendMessage(e,t,n,i,s=[],r=[],o){Wa(s);const a=await this.options.requireInstance(e);s.some(e=>"runtime-path"===e.source.type)&&function(e,t){if(!e.some(e=>"runtime-path"===e.source.type)||"local"===t)return;const n=new Error("Runtime path attachments are currently available only for Local Runtime instances.");throw Object.assign(n,{statusCode:400,code:"AI_SESSION_RUNTIME_PATH_UNSUPPORTED"}),n}(s,(await this.options.requireRuntime(a.nodeId,a.runtimeId)).type);const d=a.aiSessions.sessions.find(e=>e.id===t),c=o||("codex"===d?.agent?a.config.defaultCodexPermissionMode:void 0);return Uo(Ge,await this.options.request(a,Fa(t,"messages"),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({message:n,...i?{mode:i}:{},...s.length?{attachments:s}:{},...r.length?{references:r}:{},...c?{permissionMode:c}:{}})}))}async mentionCatalog(e,t){return Uo(Ie,await this.get(e,Fa(t,"mentions")))}async searchMentionFiles(e,t,n){return Uo(ve,await this.post(e,Fa(t,"mentions/files"),{query:n}))}async executeCommand(e,t,n){return Uo(pe,await this.post(e,Fa(t,"commands"),n))}async queue(e,t){return Uo($e,await this.get(e,Fa(t,"queue")))}async steerQueuedMessage(e,t,n){return Uo(Ge,await this.post(e,Ha(t,n,"steer"),{}))}async retryQueuedMessage(e,t,n){return Uo(We,await this.post(e,Ha(t,n,"retry"),{}))}async removeQueuedMessage(e,t,n){const i=await this.options.requireInstance(e);return Uo(We,await this.options.request(i,Ha(t,n),{method:"DELETE"}))}async editQueuedMessage(e,t,n,i){const s=Le.parse(i);return Uo(We,await this.patch(e,Ha(t,n),s))}async reorderQueuedMessages(e,t,n){const i=Me.parse(n);return Uo(We,await this.patch(e,Fa(t,"queue/reorder"),i))}async interrupt(e,t){return Uo(Ge,await this.post(e,Fa(t,"interrupt"),{}))}async get(e,t){return this.options.request(await this.options.requireInstance(e),t)}async post(e,t,n){return this.options.request(await this.options.requireInstance(e),t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}async patch(e,t,n){return this.options.request(await this.options.requireInstance(e),t,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}}function qa(e){return vi(e.capabilities).features.aiSessionWorkspaceSelection}function $a(){const e=new Error("The controlled instance does not support AI session workspace selection.");return Object.assign(e,{statusCode:409,code:"AI_SESSION_WORKSPACE_SELECTION_UNSUPPORTED"}),e}function Ba(e){return e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code?e.code:"AI_SESSION_SNAPSHOT_REFRESH_FAILED"}function Ua(e){return e instanceof Error?e.message:String(e)}function Fa(e,t){return`/ai-sessions/${encodeURIComponent(e)}/${t}`}function Ha(e,t,n){return`${Fa(e,"queue")}/${encodeURIComponent(t)}${n?`/${n}`:""}`}function Wa(e){if(e.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)<=x)return;const t=new Error("Inline attachments must be 41943040 bytes or less in total.");throw Object.assign(t,{statusCode:400,code:"AI_SESSION_ATTACHMENTS_TOO_LARGE"}),t}function Ga(e,t,n,i){const s=i&&"object"==typeof i?i:{};return{nodeId:e.id,route:"string"==typeof s.route?s.route:t,method:n,code:"string"==typeof s.code?s.code:"NODE_AGENT_REQUEST_FAILED",message:i instanceof Error?i.message:String(i),statusCode:"number"==typeof s.statusCode?s.statusCode:void 0,issues:Array.isArray(s.issues)?s.issues:void 0}}class Va{requestImpl;logger;constructor(e){this.requestImpl=e.request,this.logger=e.logger}async request(e,t,n={}){const i=n.method||"GET";let s,r;try{s=await this.requestImpl(e,t,n)}catch(n){throw this.logger?.warn?.({nodeId:e.id,route:t,method:i,error:n instanceof Error?n.message:String(n),errorCode:"NODE_AGENT_TRANSPORT_FAILED"},"node agent transport failed"),n}try{r=await s.json()}catch(n){this.logger?.warn?.({nodeId:e.id,route:t,method:i,statusCode:s.status,error:n instanceof Error?n.message:String(n),errorCode:"NODE_AGENT_RESPONSE_INVALID_JSON"},"node agent response was not valid json");const r=new Error(`Node agent ${e.id} returned invalid JSON for ${t}.`);throw Object.assign(r,{statusCode:502,code:"NODE_AGENT_RESPONSE_INVALID_JSON",nodeId:e.id,route:t}),r}if(!s.ok){const n=new Error(r.error?.message||`Node agent request failed with HTTP ${s.status}`);throw Object.assign(n,{statusCode:s.status,code:r.error?.code||"NODE_AGENT_REQUEST_FAILED",nodeId:e.id,route:t}),this.logger?.warn?.({nodeId:e.id,route:t,method:i,statusCode:s.status,errorCode:r.error?.code||"NODE_AGENT_REQUEST_FAILED",error:n.message},"node agent request failed"),n}return this.logger?.info?.({nodeId:e.id,route:t,method:i,statusCode:s.status},"node agent request ok"),r.data??r}async requestSchema(e,t,n,i={}){return this.parse(e,t,n,await this.request(e,t,i),i.method||"GET")}parse(e,t,n,i,s="GET"){const r=Bo(n,i);if(r.success)return r.data;this.logger?.warn?.({nodeId:e.id,route:t,method:s,errorCode:"NODE_AGENT_PROTOCOL_INVALID",issues:r.error.issues},"node agent protocol response did not match schema");const o=new Error(`Node agent ${e.id} returned invalid protocol data for ${t}.`);throw Object.assign(o,{statusCode:502,code:"NODE_AGENT_PROTOCOL_INVALID",nodeId:e.id,route:t,issues:r.error.issues}),o}}class Ka{client;fleetRequestTimeoutMs;runtimeSnapshots=new Map;instanceSnapshots=new Map;constructor(e,t={}){this.client=e,this.fleetRequestTimeoutMs=Number.isFinite(t.fleetRequestTimeoutMs)&&Number(t.fleetRequestTimeoutMs)>0?Number(t.fleetRequestTimeoutMs):2e3}request(e,t,n={}){return this.client.request(e,t,n)}health(e){return this.client.requestSchema(e,"/health",wr)}checkUpdate(e,t){return this.client.requestSchema(e,"/updates/check",zs,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}applyUpdate(e,t){return this.client.requestSchema(e,"/updates/apply",Ts,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listUpdateJobs(e){return this.client.requestSchema(e,"/updates/jobs",a.z.array(Ts))}getExternalListener(e){return this.client.requestSchema(e,"/settings/external-listener",Sr)}updateExternalListener(e,t){return this.client.requestSchema(e,"/settings/external-listener",Sr,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}createPairingInvite(e,t={}){return this.client.requestSchema(e,"/pairing/invites",Ar,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t&&"object"==typeof t?t:{})})}createControlPlaneConnection(e,t){return this.client.requestSchema(e,"/control-plane-connections",Cr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listControlPlanePairings(e){return this.client.requestSchema(e,"/control-plane-pairings",a.z.array(zr))}deleteControlPlanePairing(e,t){return this.client.requestSchema(e,`/control-plane-pairings/${encodeURIComponent(t)}`,xr,{method:"DELETE"})}listControlPlaneConnections(e){return this.client.requestSchema(e,"/control-plane-connections",a.z.array(Er))}deleteControlPlaneConnection(e,t){return this.client.requestSchema(e,`/control-plane-connections/${encodeURIComponent(t)}`,xr,{method:"DELETE"})}listDockerImages(e){return this.client.requestSchema(e,"/docker/images",a.z.array(Nr))}listFolderTree(e,t={}){const n=new URLSearchParams;t.path&&n.set("path",t.path),void 0!==t.depth&&n.set("depth",String(t.depth));const i=n.toString();return this.client.requestSchema(e,"/folders/tree"+(i?`?${i}`:""),a.z.array(_r))}listLocalFolders(e,t={}){return this.client.requestSchema(e,"/local-folders",a.z.array(Os),t)}createLocalFolder(e,t){return this.client.requestSchema(e,"/local-folders",Os,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}async requireLocalFolder(e,t){const n=(await this.listLocalFolders(e)).find(e=>e.id===t);if(!n){const n=new Error(`Local folder ${t} was not found on node ${e.id}.`);throw Object.assign(n,{statusCode:404,code:"NODE_LOCAL_FOLDER_NOT_FOUND",nodeId:e.id,route:"/local-folders"}),n}return n}listRuntimes(e,t={}){return this.client.requestSchema(e,"/runtimes",a.z.array(Ir),t)}createRuntime(e,t){return this.client.requestSchema(e,"/runtimes",Ir,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateRuntime(e,t,n){const i=`/runtimes/${encodeURIComponent(t)}`;return this.client.requestSchema(e,i,Ir,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}checkRuntime(e,t){const n=`/runtimes/${encodeURIComponent(t)}/check`;return this.client.requestSchema(e,n,Ir,{method:"POST"})}deleteRuntime(e,t){return this.client.requestSchema(e,`/runtimes/${encodeURIComponent(t)}`,xr,{method:"DELETE"})}deleteLocalFolder(e,t){return this.client.requestSchema(e,`/local-folders/${encodeURIComponent(t)}`,xr,{method:"DELETE"})}listModels(e,t={}){return this.client.requestSchema(e,"/models",a.z.array(Ls),t)}createModel(e,t){return this.client.requestSchema(e,"/models",Ls,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}deployModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}/deploy`,Ls,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}updateModel(e,t,n){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,Ls,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteModel(e,t){return this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,xr,{method:"DELETE"})}discoverModels(e,t){return this.client.requestSchema(e,"/models/discover",a.z.object({models:a.z.array(a.z.object({id:a.z.string(),ownedBy:a.z.string().optional()}).strict()),latencyMs:a.z.number().nonnegative()}).strict(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}testModel(e,t){return this.client.requestSchema(e,"/models/test",a.z.object({success:a.z.literal(!0),latencyMs:a.z.number().nonnegative()}).strict(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}assignInstanceModels(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/model-assignment`,a.z.object({assignment:qs,instance:Mr}).strict(),{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}async listFleetModels(e,t={}){return(await Promise.allSettled(e.map(async e=>({node:e,models:await this.listModels(e,t)})))).reduce((t,n,i)=>{if("fulfilled"===n.status)t.items.push(...n.value.models.map(e=>({nodeId:n.value.node.id,model:e})));else{const s=e[i];s&&t.nodeErrors.push(Ga(s,"/models","GET",n.reason))}return t},{items:[],nodeErrors:[]})}async listFleetRuntimes(e,t={}){return this.listFleetFromSnapshots(e,"/runtimes",t,this.runtimeSnapshots,async(e,t)=>({items:await this.listRuntimes(e,t),nodeErrors:[]}))}listInstances(e,t={}){return this.listInstancesWithDiagnostics(e,t).then(e=>e.items)}async listInstancesWithDiagnostics(e,t={}){return this.client.requestSchema(e,"/instances",a.z.array(a.z.unknown()),t).then(t=>t.reduce((t,n)=>{const i=this.normalizeInstance(e,n);return i.instance&&t.items.push(i.instance),i.error&&t.nodeErrors.push(i.error),t},{items:[],nodeErrors:[]}))}createInstance(e,t){return this.client.requestSchema(e,"/instances",Mr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}`,Mr,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/delete`,Gi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}listEnvironmentTemplates(e,t={}){return this.client.requestSchema(e,"/environment-templates",a.z.array(Zi),t)}getEnvironmentTemplate(e,t,n={}){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,Zi,n)}createEnvironmentTemplate(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/environment-templates`,Zi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteEnvironmentTemplate(e,t){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,a.z.object({deleted:a.z.boolean(),templateId:Zi.shape.id}).strict(),{method:"DELETE"})}startInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/start`,Mr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}retryInstanceImageProvisioning(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/image-provisioning/retry`,Mr,{method:"POST"})}stopInstance(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/stop`,Mr,{method:"POST"})}restartInstance(e,t,n={}){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/restart`,Mr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}instanceResourceMetrics(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/metrics`,br)}proxyRawInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/proxy/raw`,Rr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}async listFleetInstances(e,t={}){return this.listFleetFromSnapshots(e,"/instances",t,this.instanceSnapshots,(e,t)=>this.listInstancesWithDiagnostics(e,t))}async listFleetFromSnapshots(e,t,n,i,s){const r=new Set(e.map(e=>e.id));for(const e of i.keys())r.has(e)||i.delete(e);return(await Promise.all(e.map(async e=>{const r=this.fleetConnectionKey(e);try{this.requireFleetNodeReady(e,t);const o=await this.withFleetDeadline(e,t,n,t=>s(e,t));return i.set(e.id,{connectionKey:r,items:[...o.items]}),o}catch(n){const s=i.get(e.id);return{items:s?.connectionKey===r?[...s.items]:[],nodeErrors:[Ga(e,t,"GET",n)]}}}))).reduce((e,t)=>(e.items.push(...t.items),e.nodeErrors.push(...t.nodeErrors),e),{items:[],nodeErrors:[]})}fleetConnectionKey(e){return JSON.stringify([e.id,e.connectionMode,e.controlEndpoint,e.endpoint,e.auth.mode,e.auth.keyId])}requireFleetNodeReady(e,t){const n=e.connectionPhase,i="reverse-wss"!==e.connectionMode&&"control-plane-proxy"!==e.connectionMode;if(!n||"healthy"===n||i)return;const s=new Error(`Node agent ${e.id} is ${n}; serving its latest fleet snapshot.`);throw Object.assign(s,{code:"NODE_AGENT_CONNECTION_PENDING",nodeId:e.id,route:t}),s}async withFleetDeadline(e,t,n,i){const s=new AbortController,r=Object.assign(new Error(`Node agent ${e.id} did not return ${t} before the fleet aggregation deadline.`),{code:"NODE_AGENT_FLEET_TIMEOUT",nodeId:e.id,route:t}),o=new Promise((e,t)=>{const n=()=>t(s.signal.reason||r);s.signal.aborted?n():s.signal.addEventListener("abort",n,{once:!0})}),a=()=>s.abort(n.signal?.reason);n.signal?.aborted?a():n.signal?.addEventListener("abort",a,{once:!0});const d=setTimeout(()=>s.abort(r),this.fleetRequestTimeoutMs);d.unref?.();try{return await Promise.race([i({...n,signal:s.signal}),o])}finally{clearTimeout(d),n.signal?.removeEventListener("abort",a)}}normalizeInstance(e,t){const n=(i=t,Mr.safeParse(function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=new Set(Object.keys(Mr.shape)),i={};for(const[e,s]of Object.entries(t))n.has(e)&&(i[e]=s);if(t.capabilities&&"object"==typeof t.capabilities&&!Array.isArray(t.capabilities)){const e={...t.capabilities};Object.prototype.hasOwnProperty.call(e,"apps")&&delete e.apps,i.capabilities=vi(e)}else i.capabilities=vi(void 0);i.appInventory=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e;Object.keys(t).some(e=>!["observedAt","items","issues"].includes(e));const n={observedAt:t.observedAt,items:Array.isArray(t.items)?t.items.map(e=>{e&&"object"==typeof e&&!Array.isArray(e)&&Object.keys(e).some(e=>!["id","name","kind","source","availability","capabilities","diagnosticCode"].includes(e));const t=Ur(e,["id","name","kind","source","availability","diagnosticCode"]);return!t||"object"!=typeof t||Array.isArray(t)?t:{...t,capabilities:Ur(e.capabilities,["automation","supportsCwdSelection"])}}):t.items,issues:Array.isArray(t.issues)?t.issues.map(e=>Ur(e,["code","message"])):t.issues},i=Xi.safeParse(n);return i.success?i.data:void 0}(t.appInventory,"string"==typeof t.id&&t.id),i.source=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=t.type,i=_s.options.find(e=>e.shape.type.value===n);if(!i)return e;const s="local-folder"===n?["type","localFolderId","path","ownerNodeId"]:"git-template"===n?["type","url","templateId","ref","auth","clone"]:["type","repositoryId","url","provider","ref","auth","clone"],r=Ur(t,s);if("local-folder"!==n){const e=$r(Cs,Ur(t.ref,["type","name","commit"])),n=$r(xs,Ur(t.auth,["type","secretId"])),i=$r(Ns,Ur(t.clone,["depth","submodules","lfs","subdirectory"]));e?r.ref=e:delete r.ref,n?r.auth=n:delete r.auth,i?r.clone=i:delete r.clone}const o=$r(i,r);return o?(Object.keys(t).some(e=>!s.includes(e)),o):r}(t.source,"string"==typeof t.id&&t.id),i.sourceSnapshot=t.sourceSnapshot&&"object"==typeof t.sourceSnapshot&&!Array.isArray(t.sourceSnapshot)?t.sourceSnapshot:{},i.build=$r(ys,t.build,0,0,"string"==typeof t.id&&t.id),i.aiSessions=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=Array.isArray(t.sessions)?t.sessions.flatMap((e,t)=>{const n=$r(Xe,e);return n?[n]:[]}):[],i={runningCount:"number"==typeof t.runningCount&&Number.isInteger(t.runningCount)&&t.runningCount>=0?t.runningCount:0,waitingCount:"number"==typeof t.waitingCount&&Number.isInteger(t.waitingCount)&&t.waitingCount>=0?t.waitingCount:0,staleCount:"number"==typeof t.staleCount&&Number.isInteger(t.staleCount)&&t.staleCount>=0?t.staleCount:0,sessions:n,updatedAt:Ai.safeParse(t.updatedAt).success?t.updatedAt:(new Date).toISOString()};return Object.keys(t).some(e=>!["runningCount","waitingCount","staleCount","sessions","updatedAt"].includes(e)),Ze.parse(i)}(t.aiSessions,"string"==typeof t.id&&t.id),i.triggers=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e;Object.keys(t).some(e=>!["enabledCount","runningCount","errorCount","configs","recentRuns"].includes(e));const n=(e,t,n)=>Array.isArray(e)?e.flatMap((e,n)=>{const i=$r(t,e);return i?[i]:[]}):[],i=Array.isArray(t.configs)?t.configs.flatMap((e,t)=>{if(!e||"object"!=typeof e||Array.isArray(e))return[];const i=e;Object.keys(i).some(e=>!["configHash","config","deployments","runtime"].includes(e));const s=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=Ur(t,["configHash","name","description","createdAt","updatedAt"]);if(t.source&&"object"==typeof t.source&&!Array.isArray(t.source)){const e=t.source,i="schedule"===e.type?"interval"===e.scheduleKind?["type","scheduleKind","intervalMs"]:"daily"===e.scheduleKind?["type","scheduleKind","timeOfDay","timezone"]:["type","scheduleKind","weekdays","timeOfDay","timezone"]:"file-change"===e.type?["type","roots","globs","ignore","debounceMs"]:["type","agent","statuses","phases"];n.source=Ur(e,i)}return n.action=Ur(t.action,["promptTemplate"]),n.policy=Ur(t.policy,["cooldownMs","maxConcurrentRuns","whenBusy"]),$r(fn,n)}(i.config);return"string"==typeof i.configHash&&s?[{configHash:i.configHash,config:s,deployments:n(i.deployments,bn),runtime:n(i.runtime,vn)}]:[]}):[];return{enabledCount:"number"==typeof t.enabledCount&&Number.isInteger(t.enabledCount)&&t.enabledCount>=0?t.enabledCount:0,runningCount:"number"==typeof t.runningCount&&Number.isInteger(t.runningCount)&&t.runningCount>=0?t.runningCount:0,errorCount:"number"==typeof t.errorCount&&Number.isInteger(t.errorCount)&&t.errorCount>=0?t.errorCount:0,configs:i,recentRuns:n(t.recentRuns,wn)}}(t.triggers,"string"==typeof t.id&&t.id),i.apps=$r(Mr.shape.apps.unwrap(),Ur(t.apps,["runningCount","problemCount","updatedAt","revision"]),0,0,"string"==typeof t.id&&t.id)||{runningCount:0,problemCount:0},i.config=$r(Mr.shape.config.unwrap(),Ur(t.config,["autoImportAgentConfigs","defaultCodexPermissionMode","aiSessionHistoryLimit"]),0,0,"string"==typeof t.id&&t.id)||{autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask",aiSessionHistoryLimit:50},i.modelSelection=$r(ji.unwrap(),Ur(t.modelSelection,["codexModelHash","claudeModelHash"]),0,0,"string"==typeof t.id&&t.id)||{},i.imageSnapshot=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,i=gr(n),{reference:s,...r}=i,o=n.requestedReference??s;let a;try{a="string"==typeof o?_i(o):void 0}catch{}const d={img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"},c="string"==typeof n.id?n.id:"string"==typeof t?t:void 0,l="market"===n.origin||c&&d[c]?"market":"custom";return void 0!==n.image||n.reference,{...r,id:c&&d[c]?d[c]:c,origin:l,repository:a?.repository??n.repository,tag:a?.tag??n.tag,requestedReference:a?.reference??o,resolvedDigest:n.resolvedDigest,resolvedReference:n.resolvedReference,downloadSizeBytes:n.downloadSizeBytes,market:"market"===l?Ur(n.market,["catalogId","catalogRevision","publisher","version"])??{catalogId:"task_handoff_embedded",catalogRevision:"legacy",publisher:"task-handoff"}:void 0}}(t.imageSnapshot,t.imageId,"string"==typeof t.id&&t.id);const s="string"==typeof t.imageId?{img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"}[t.imageId]||t.imageId:void 0,r=Ur(t.imageSelection,["imageId","tag"]);i.imageSelection=r||(s?{imageId:s,tag:i.imageSnapshot?.tag}:void 0),i.imageProvisioning=$r(ar,Ur(t.imageProvisioning,["phase","requestedReference","generation","error","startedAt","updatedAt"]),0,0,"string"==typeof t.id&&t.id),i.runtimeVersion=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=e=>{if("string"!=typeof e)return;const t=e.trim();return t&&t.length<=80?t:void 0},i=n(t.desiredVersion);if(!i)return;const s=new Set(ws.shape.phase.options),r="string"==typeof t.phase?t.phase:"pending",o=s.has(r)?r:{idle:"pending",queued:"pending",checking:"pending",downloading:"installing",updating:"installing",completed:"matched",succeeded:"matched",ready:"matched",error:"failed"}[r]||"pending";let a;if(t.error&&"object"==typeof t.error&&!Array.isArray(t.error)){const e=t.error,i="string"==typeof e.message?e.message.trim().slice(0,4096):"";if(i){const t=new Set(vs.shape.code.options),s="string"==typeof e.code&&t.has(e.code)?e.code:"INSTANCE_RUNTIME_INSTALL_FAILED";e.code;const r=n(e.expectedVersion),o=n(e.actualVersion);a={code:s,message:i,...r?{expectedVersion:r}:{},...o?{actualVersion:o}:{},retryable:!0===e.retryable}}}"string"==typeof t.error&&t.error.trim()&&(a={code:"INSTANCE_RUNTIME_INSTALL_FAILED",message:t.error.trim().slice(0,4096),expectedVersion:i,...n(t.actualVersion)?{actualVersion:n(t.actualVersion)}:{},retryable:!1});const d=n(t.actualVersion),c=Ai.safeParse(t.lastAttemptAt),l=Ai.safeParse(t.matchedAt);return void 0!==t.lastAttemptAt&&c.success,void 0!==t.matchedAt&&l.success,{desiredVersion:i,...d?{actualVersion:d}:{},phase:o,attempt:"number"==typeof t.attempt&&Number.isInteger(t.attempt)&&t.attempt>=0?t.attempt:0,...c.success?{lastAttemptAt:c.data}:{},...l.success?{matchedAt:l.data}:{},...a?{error:a}:{}}}(t.runtimeVersion,"string"==typeof t.id&&t.id),i.workspace=$r(Dr,t.workspace,0,0,"string"==typeof t.id&&t.id)||{status:"unknown"},i.environmentSource=$r(Mi,t.environmentSource,0,0,"string"==typeof t.id&&t.id),i.environmentTemplateOrigin=$r(Ui,t.environmentTemplateOrigin,0,0,"string"==typeof t.id&&t.id),i.runtime=$r(Mr.shape.runtime.unwrap(),t.runtime,0,0,"string"==typeof t.id&&t.id)||{labels:{}},i.target=$r(Pr,Ur(t.target??t.endpoints,["strategy","web","api","vnc","tty","logs","status"]),0,0,"string"==typeof t.id&&t.id)||{strategy:"direct-port",status:"unknown"},i.access=$r(jr,Ur(t.access,["strategy","web","api","ws","status"]),0,0,"string"==typeof t.id&&t.id)||{strategy:"control-plane-proxy",status:"unknown"};for(const[e,t]of Object.entries(Mr.shape))Object.prototype.hasOwnProperty.call(i,e)&&!t.safeParse(i[e]).success&&t.safeParse(void 0).success&&delete i[e];return i}(i)));var i;if(n.success)return n.data.protocolVersion&&n.data.protocolVersion!==ui?(this.client.logger?.warn?.({nodeId:e.id,instanceId:n.data.id,expectedProtocolVersion:ui,actualProtocolVersion:n.data.protocolVersion,errorCode:"PROTOCOL_VERSION_MISMATCH"},"node instance protocol version mismatch"),{instance:n.data}):{instance:n.data};const s=t&&"object"==typeof t?t:{},r="string"==typeof s.id?s.id:void 0;return this.client.logger?.warn?.({nodeId:e.id,instanceId:r,errorCode:"NODE_INSTANCE_PAYLOAD_INVALID",issues:n.error.issues.map(e=>({path:e.path.join("."),message:e.message}))},"node instance payload invalid"),{error:{nodeId:e.id,route:"/instances",method:"GET",code:"NODE_INSTANCE_PAYLOAD_INVALID",message:r?`Node instance ${r} payload is invalid.`:"Node instance payload is invalid.",statusCode:502,issues:n.error.issues}}}}function Ja(e){return e.readyState===(e.OPEN??1)}function Ya(e){const t=Buffer.isBuffer(e)?e.toString("utf8"):"string"==typeof e?e:"";if(Buffer.byteLength(t,"utf8")<=123)return t;let n="";for(const e of t){const t=`${n}${e}`;if(Buffer.byteLength(t,"utf8")>123)break;n=t}return n}function Qa(e){if("number"==typeof e&&Number.isInteger(e))return e>=3e3&&e<=4999||e>=1e3&&e<=1014&&1004!==e&&1005!==e&&1006!==e?e:void 0}function Xa(e,t,n){e.close(Qa(t),Ya(n)||void 0)}function Za(e,t,n,i){if(Ja(e))for(const e of t.splice(0))if(i(e),!n(e))return}function ed(e,t,n={}){const i=n.pendingFrameLimit??256,s=n.maxFrameBytes??8388608,r=n.maxTotalBytes??1073741824,o=n.maxBufferedBytes??16777216;let a=!1,d=Ja(t);const c=[],l=[];let p,u=0,m=0,g=0;const h=e=>Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8"),y=(i,o)=>{const a=h(o);return g+=a,n.onFrame?.(i,a),!(a>s||g>r)||(Xa(e,1009,"WebSocket bridge traffic limit exceeded."),Xa(t,1009,"WebSocket bridge traffic limit exceeded."),!1)},f=()=>{p&&(clearTimeout(p),p=void 0)},I=(n,i)=>{const s=i.bytes;if((n.bufferedAmount??0)+s>o)return Xa(e,1013,"WebSocket bridge consumer is too slow."),Xa(t,1013,"WebSocket bridge consumer is too slow."),!1;try{return function(e,t){e.send(t.data,{binary:t.isBinary})}(n,i),!0}catch{return Xa(e,1011,"WebSocket bridge send failed."),Xa(t,1011,"WebSocket bridge send failed."),!1}},b=(n,s,r)=>{if(s.length>=i)return Xa(e,1011,"WebSocket bridge pending frame limit exceeded."),void Xa(t,1011,"WebSocket bridge pending frame limit exceeded.");const a="upstream"===n?u:m;if((("upstream"===n?t:e).bufferedAmount??0)+a+r.bytes>o)return Xa(e,1013,"WebSocket bridge consumer is too slow."),void Xa(t,1013,"WebSocket bridge consumer is too slow.");s.push(r),"upstream"===n?u+=r.bytes:m+=r.bytes};return n.upstreamOpenTimeoutMs&&!d&&(p=setTimeout(()=>{d||a||(Xa(e,1011,"Upstream websocket did not open."),Xa(t))},n.upstreamOpenTimeoutMs)),e.on("open",()=>Za(e,l,t=>I(e,t),e=>{m-=e.bytes})),t.on("open",()=>{f(),d=!0,n.onUpstreamOpen?.(),Za(t,c,e=>I(t,e),e=>{u-=e.bytes})}),e.on("message",(e,n=!1)=>{if(!y("client-to-upstream",e))return;const i={data:e,isBinary:Boolean(n),bytes:h(e)};Ja(t)?I(t,i):b("upstream",c,i)}),t.on("message",(t,n=!1)=>{if(!y("upstream-to-client",t))return;const i={data:t,isBinary:Boolean(n),bytes:h(t)};Ja(e)?I(e,i):b("client",l,i)}),t.on("close",(t,i)=>{f(),n.onUpstreamClose?.(t,i),(d||a||!n.onUpstreamCloseBeforeOpen?.())&&Xa(e,t,i)}),t.on("error",t=>{n.onUpstreamError?.(t),(d||a||!n.onUpstreamErrorBeforeOpen?.(t))&&Xa(e)}),e.on("close",(e,i)=>{f(),a=!0,n.onClientClose?.(e,i),Xa(t,e,i)}),e.on("error",e=>{f(),a=!0,n.onClientError?.(e),Xa(t,1011,"WebSocket bridge client failed.")}),{close:(n,i)=>{f(),Xa(t,n,i),Xa(e,n,i)}}}const td="TASK_HANDOFF_NODE_AGENT_V1",nd=6e4,id="/api/node-tunnel";function sd(e,t){if("paired-hmac"===e.auth.mode&&e.auth.secret){if(!e.auth.keyId){const t=new Error(`Node ${e.id} paired-HMAC auth is missing keyId.`);throw Object.assign(t,{statusCode:500,code:"NODE_AGENT_REMOTE_KEY_ID_MISSING"}),t}return function(e){const t=e.timestamp||(new Date).toISOString(),n=e.nonce||i.randomBytes(18).toString("base64url"),s=rd(e.body||""),r=od(e.secret,{keyId:e.keyId,method:e.method,pathWithQuery:e.pathWithQuery,timestamp:t,nonce:n,bodySha256:s});return{"x-taskhandoff-node-id":e.nodeId,"x-taskhandoff-key-id":e.keyId,"x-taskhandoff-timestamp":t,"x-taskhandoff-nonce":n,"x-taskhandoff-body-sha256":s,"x-taskhandoff-signature":r}}({nodeId:e.id,keyId:e.auth.keyId,secret:e.auth.secret,method:t.method,pathWithQuery:t.pathWithQuery,body:t.body})}const n="local-ipc"!==e.connectionMode&&"local-loopback"!==e.connectionMode||"local-static-key"!==e.auth.mode?void 0:e.auth.secret;return n?{authorization:`Bearer ${n}`}:{}}function rd(e=""){return i.createHash("sha256").update(e).digest("hex")}function od(e,t){return i.createHmac("sha256",e).update(function(e){return[td,e.keyId,e.method.toUpperCase(),e.pathWithQuery,e.timestamp,e.nonce,e.bodySha256].join("\n")}(t)).digest("hex")}function ad(e){if(e.startsWith("ipc://"))return decodeURIComponent(e.slice(6))}function dd(e,t=process.platform){if(!function(e,t=process.platform){if("win32"===t)return e.startsWith("\\\\.\\pipe\\");const i=n.statSync(e),s=process.getuid?.();return void 0===s||i.uid===s}(e,t)){const e=new Error("Local node agent IPC socket is not owned by the current user.");throw Object.assign(e,{statusCode:403,code:"NODE_AGENT_IPC_OWNER_INVALID"}),e}}function cd(e,t,n,i={}){const s=`/api/node-agent${t}`,r={createConnection:()=>u.connect(e),headers:{host:"task-handoff-node-agent.local",...i}};return n&&(Array.isArray(n)?n.length>0:n.trim().length>0)?new l.WebSocket(`ws://task-handoff-node-agent.local${s}`,n,r):new l.WebSocket(`ws://task-handoff-node-agent.local${s}`,r)}function ld(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function pd(e,t){const n=AbortSignal.timeout(t);return e?AbortSignal.any([e,n]):n}async function ud(e,t,n,i={}){const s=ad(t);return s?(dd(s),async function(e,t,n={}){const i=n.method||"GET",s="string"==typeof n.body||n.body instanceof Buffer?n.body:void 0===n.body||null===n.body?void 0:String(n.body),r=new Headers(n.headers||{});return void 0===s||r.has("content-length")||r.set("content-length",String(Buffer.byteLength(s))),new Promise((o,a)=>{const d=p.request({socketPath:e,method:i,path:`/api/node-agent${t}`,headers:Object.fromEntries(r.entries())},e=>{const t=e.statusCode||500;o(new Response("HEAD"!==i&&204!==t&&205!==t&&304!==t?m.Readable.toWeb(e):null,{status:t,headers:e.headers}))});d.on("error",a);const c=()=>d.destroy(new DOMException("The operation was aborted.","AbortError"));n.signal?.aborted?c():n.signal?.addEventListener("abort",c,{once:!0}),d.once("close",()=>n.signal?.removeEventListener("abort",c)),void 0!==s&&d.write(s),d.end()})}(s,n,i)):e(`${t.replace(/\/$/,"")}/api/node-agent${n}`,i)}function md(e){const t=e.controlEndpoint||e.endpoint;if(!t){const e=new Error("Node agent direct HTTP mode requires an endpoint.");throw Object.assign(e,{statusCode:400,code:"NODE_AGENT_ENDPOINT_REQUIRED"}),e}return t}function gd(e,t,n,i){const s=md(e),r=ad(s),o=`/api/node-agent${t}`;if(r)return dd(r),cd(r,t,n,i);const a=new URL(o,s.replace(/\/$/,""));return a.protocol="https:"===a.protocol?"wss:":"ws:",n?new l.WebSocket(a.toString(),n,{headers:i}):new l.WebSocket(a.toString(),{headers:i})}function hd(e,t,n){const i=new Headers(n),s=sd(e,t);for(const[e,t]of Object.entries(s))"authorization"===e&&i.has(e)||i.set(e,t);return Object.fromEntries(i.entries())}function yd(e=fetch,t={}){const n=t.openWebSocket||gd,i=ld(t.requestTimeoutMs,3e4),s=ld(t.streamHeaderTimeoutMs,3e4),r=ld(t.websocketOpenTimeoutMs,1e4);return{request:async(t,n,s={})=>{const r=md(t),o=s.method||"GET",a="string"==typeof s.body||s.body instanceof Buffer?s.body:void 0===s.body||null===s.body?void 0:String(s.body),d=hd(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},s.headers);return ud(e,r,n,{...s,body:a,headers:d,signal:pd(s.signal,i)})},requestStream:async(t,n,i={})=>{const r=md(t),o=i.method||"GET",a="string"==typeof i.body||i.body instanceof Buffer?i.body:void 0===i.body||null===i.body?void 0:String(i.body),d=hd(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},i.headers),c=new AbortController,l=i.signal?AbortSignal.any([i.signal,c.signal]):c.signal;return async function(t,s,o){const c=setTimeout(()=>o.abort(Object.assign(new Error("Node agent response header timed out."),{code:"NODE_AGENT_RESPONSE_HEADER_TIMEOUT"})),s);c.unref?.();try{return await ud(e,r,n,{...i,body:a,headers:d,signal:l})}finally{clearTimeout(c)}}(0,s,c)},proxyWebSocket(e,t,i,s,o={}){const a=hd(e,{method:"GET",pathWithQuery:`/api/node-agent${i}`},o);ed(t,n(e,i,s,a),{upstreamOpenTimeoutMs:r,onUpstreamError:()=>t.close(1011,"Instance websocket proxy failed."),onUpstreamErrorBeforeOpen:()=>!0})}}}class fd{direct;tunnel;proxy;constructor(e){this.direct=e.direct,this.tunnel=e.tunnel,this.proxy=e.proxy}setTunnel(e){this.tunnel=e}setProxy(e){this.proxy=e}resolve(e){if(!1===e.connectionEnabled){const e=new Error("Node agent connection is disabled locally.");throw Object.assign(e,{statusCode:409,code:"NODE_AGENT_CONNECTION_DISABLED"}),e}if("control-plane-proxy"===e.connectionMode){if(!this.proxy){const e=new Error("Control-plane proxy transport is not available.");throw Object.assign(e,{statusCode:503,code:"CONTROL_PLANE_PROXY_TRANSPORT_UNAVAILABLE"}),e}return this.proxy}if("reverse-wss"!==e.connectionMode)return this.direct;if(!this.tunnel){const e=new Error("Reverse node agent transport is not available.");throw Object.assign(e,{statusCode:503,code:"NODE_AGENT_REVERSE_TRANSPORT_UNAVAILABLE"}),e}return this.tunnel}}function Id(e,t,n,i){const s=new Error(e,void 0===i?void 0:{cause:i});return Object.assign(s,{code:t,statusCode:n,retryable:n>=500}),s}function bd(e,t){if("control-plane-proxy"!==e.connectionPath.kind)throw Id("Control-plane proxy transport requires a proxy connection path.","CONTROL_PLANE_PROXY_CONFIGURATION_INVALID",400);const n=t(e);if(!n)throw Id("Control-plane proxy credential is missing.","CONTROL_PLANE_PROXY_CREDENTIAL_REQUIRED",503);if(n.nodeId!==e.id||n.proxyBindingId!==e.connectionPath.proxyBindingId||n.targetNodeId!==e.connectionPath.targetNodeId)throw Id("Control-plane proxy credential does not match the node connection identity.","CONTROL_PLANE_PROXY_CREDENTIAL_MISMATCH",409);return n}function vd(e,t){const n=new Headers(t);n.set($n,Nn),n.set(Bn,e.sourceControlPlaneId),n.set(Un,e.bindingKeyId),n.set(Fn,e.credential);const s=jn.safeParse(n.get("x-request-id"));return n.set("x-request-id",s.success?s.data:`proxy_request_${i.randomUUID().replace(/-/g,"")}`),Object.fromEntries(n.entries())}function wd(e){const t=Mn.safeParse(e);if(t.success)return t.data;const n=Id("Control-plane proxy route is invalid.",Hn.RouteInvalid,400);throw Object.assign(n,{issues:t.error.issues}),n}function Sd(e,t,n){return t?new l.WebSocket(e,t,{headers:n}):new l.WebSocket(e,{headers:n})}class Ad{credentialForNode;fetchImpl;openWebSocket;constructor(e){this.credentialForNode=e.credentialForNode,this.fetchImpl=e.fetchImpl||fetch,this.openWebSocket=e.openWebSocket||Sd}async fetch(e,t,n={}){const i=bd(e,this.credentialForNode),s=function(e,t){const n=new URL(wd(t),"https://node-agent.invalid"),i=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/http${n.pathname}`,e.proxyOrigin);return i.search=n.search,i}(i,t);try{return await this.fetchImpl(s,{...n,headers:vd(i,n.headers)})}catch(e){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(e))throw e;throw Id(`Trusted control-plane proxy ${i.proxyOrigin} is unavailable.`,"CONTROL_PLANE_PROXY_UNAVAILABLE",503,e)}}request(e,t,n={}){return this.fetch(e,t,n)}requestStream(e,t,n={}){return this.fetch(e,t,n)}proxyWebSocket(e,t,n,i,s={}){const r=bd(e,this.credentialForNode),o=this.openWebSocket(function(e,t){const n=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/websocket`,e.proxyOrigin);return n.protocol="wss:",n.searchParams.set("route",wd(t)),n}(r,n).toString(),i,vd(r,s));ed(t,o,{onUpstreamError:()=>t.close(1011,"Control-plane proxy websocket failed."),onUpstreamErrorBeforeOpen:()=>!0})}}const kd=new Set(Object.keys(li.shape)),zd=new Set(Object.keys(pi.shape));function Td(e,t,n){if(!e||"object"!=typeof e||Array.isArray(e))return e;const i=e,s=Object.keys(i).filter(e=>!t.has(e));return s.length&&n?.(s),Object.fromEntries([...t].filter(e=>e in i).map(e=>[e,i[e]]))}function Ed(e){const{credential:t,...n}=e;return n}class Cd{pendingClaims;nodeCredentials;identity;constructor(e,t){this.pendingClaims=new fo(e.pendingClaimsDir,{schema:li,sanitize:e=>function(e){return Td(e,kd,e=>t?.("unknown stored pending proxy claim fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.nodeCredentials=new fo(e.nodeCredentialsDir,{schema:pi,sanitize:e=>function(e){return Td(e,zd,e=>t?.("unknown stored proxy node credential fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.identity=new Io(e.identityPath,()=>({controlPlaneId:ho("control_plane")}),{schema:a.z.object({controlPlaneId:a.z.string().trim().min(1).max(160)}).strip(),logger:t,directoryMode:448,fileMode:384})}init(e=Date.now()){return this.pendingClaims.init(),this.nodeCredentials.init(),this.identity.init(),this.gcPendingClaims(e)}controlPlaneId(){return this.identity.get().controlPlaneId}pendingClaimByClaimId(e){return this.pendingClaims.list().find(t=>t.claimId===e)}putPendingClaim(e){const t=this.pendingClaimByClaimId(e.claimId);if(!t)return this.pendingClaims.put(e);if(t.proxyOrigin!==e.proxyOrigin||t.requestedName!==e.requestedName||t.sourceControlPlaneId!==e.sourceControlPlaneId||t.targetNodeId!==e.targetNodeId||t.bindingKeyId!==e.bindingKeyId||t.credential!==e.credential){const e=new Error("Pending proxy claim identity conflicts with an existing claim.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",statusCode:409}),e}return t}publicPendingClaims(){return this.pendingClaims.list().map(Ed)}nodeCredential(e){return this.nodeCredentials.list().find(t=>t.nodeId===e)}putNodeCredential(e){const t=this.nodeCredential(e.nodeId);if(t&&(t.proxyOrigin!==e.proxyOrigin||t.proxyBindingId!==e.proxyBindingId||t.targetNodeId!==e.targetNodeId||t.sourceControlPlaneId!==e.sourceControlPlaneId||t.bindingKeyId!==e.bindingKeyId||t.credential!==e.credential)){const e=new Error("Proxy node credential conflicts with the existing node identity.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_NODE_IDENTITY_CONFLICT",statusCode:409}),e}return t||this.nodeCredentials.put(e)}deleteNodeCredential(e){const t=this.nodeCredential(e);return!!t&&this.nodeCredentials.delete(t.id)}gcNodeCredentials(e){const t=[];for(const n of this.nodeCredentials.list())e(n)||(this.nodeCredentials.delete(n.id),t.push(n.id));return t}promotePendingClaim(e,t){const n=this.pendingClaimByClaimId(e);if(!n)return;if(n.proxyOrigin!==t.proxyOrigin||n.sourceControlPlaneId!==t.sourceControlPlaneId||void 0!==n.targetNodeId&&n.targetNodeId!==t.targetNodeId||n.bindingKeyId!==t.bindingKeyId||n.credential!==t.credential){const e=new Error("Proxy node credential does not match the pending claim identity.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",statusCode:409}),e}const i=this.putNodeCredential(t);return this.pendingClaims.delete(n.id),i}markCompensationRequired(e){const t=this.pendingClaimByClaimId(e);if(t)return this.pendingClaims.patch(t.id,{status:"compensation-required"})}cancelPendingClaim(e,t){const n=this.pendingClaimByClaimId(e);return n?t?(this.pendingClaims.patch(n.id,{status:"compensation-required"}),{deleted:!1,compensationRequired:!0}):{deleted:this.pendingClaims.delete(n.id),compensationRequired:!1}:{deleted:!1,compensationRequired:!1}}completePendingClaimCompensation(e){const t=this.pendingClaimByClaimId(e);return!(!t||"compensation-required"!==t.status)&&this.pendingClaims.delete(t.id)}gcPendingClaims(e=Date.now()){const t=[];for(const n of this.pendingClaims.list()){if("compensation-required"===n.status)continue;const i=Date.parse(n.expiresAt);!Number.isFinite(i)||i>e||(this.pendingClaims.delete(n.id),t.push(n.id))}return t}}const xd=a.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Nd=a.z.string().datetime(),Od=a.z.object({sessionReadAgents:a.z.array(a.z.string().trim().min(1).max(120)).max(100).default([]),turnReadAgents:a.z.array(a.z.string().trim().min(1).max(120)).max(100).default([]),liveItemAgents:a.z.array(a.z.string().trim().min(1).max(120)).max(100).default([])}).passthrough();const _d=a.z.object({aiSessionTimeline:Od.default(function(){return{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}})}).passthrough(),Rd=a.z.enum(["connecting","handshaking","healthy","reconnecting","suspect","offline"]),Pd=a.z.enum(["start","stop","restart","retry-image"]);a.z.object({instanceId:xd,revision:a.z.number().int().nonnegative(),updatedAt:Nd,status:a.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]),health:a.z.enum(["unknown","ok","degraded","failed"]),connectionStatus:a.z.enum(["unknown","online","offline","endpoint-unreachable"]),ready:a.z.boolean(),lastHeartbeatAt:Nd.optional()}).strip();const jd=a.z.object({code:a.z.string().trim().min(1).max(120),message:a.z.string().trim().min(1).max(2048)}).strict(),Dd=a.z.object({id:xd,name:a.z.string().trim().min(1).max(160),status:a.z.enum(["unknown","online","offline","degraded"]),health:a.z.enum(["unknown","ok","degraded","failed"]),connectionMode:a.z.enum(["local-ipc","local-loopback","direct-http","reverse-wss","control-plane-proxy"]),connectionPhase:Rd.optional(),lastSeenAt:Nd.optional(),observedAt:Nd,capabilities:a.z.array(a.z.string().trim().min(1).max(120)).max(256),error:jd.optional()}).strict();a.z.array(Dd);const Md=a.z.object({id:a.z.string().trim().min(1).max(120),name:a.z.string().trim().min(1).max(120),kind:a.z.enum(["tty","gui","web"]),supportsCwdSelection:a.z.boolean()}).strict(),Ld=a.z.object({id:xd,name:a.z.string().trim().min(1).max(160),nodeId:xd,status:a.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]),health:a.z.enum(["unknown","ok","degraded","failed"]),connectionStatus:a.z.enum(["unknown","online","offline","endpoint-unreachable"]),ready:a.z.boolean(),capabilities:_d.default({aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}),config:a.z.object({defaultCodexPermissionMode:de.default("ask")}).strict().default({defaultCodexPermissionMode:"ask"}),lastHeartbeatAt:Nd.optional(),heartbeatAgeMs:a.z.number().int().nonnegative().optional(),observedAt:Nd,runtime:a.z.object({id:xd,name:a.z.string().trim().min(1).max(160).optional(),type:a.z.enum(["docker","kubernetes","local"]).optional()}).strict(),workspace:a.z.object({status:a.z.enum(["unknown","pending","ready","failed"]),path:a.z.string().trim().max(4096).optional()}).strict(),protocol:a.z.object({version:a.z.string().optional(),compatible:a.z.boolean(),warning:a.z.string().trim().min(1).max(500).optional()}).strict(),aiSessions:tt,availableActions:a.z.array(Pd).max(4).default([]),availableApps:a.z.array(Md).max(256).default([]),availableAgents:a.z.array(Md).max(256),error:jd.optional()}).strict();function qd(e){if(!e||"object"!=typeof e)return;const t=e,n=ys.safeParse(t.build),i=qi.safeParse(t.platform),s=$i.safeParse(t.arch),r=vr.safeParse(t.capabilities);return{..."boolean"==typeof t.ok?{ok:t.ok}:{},..."string"==typeof t.role?{role:t.role}:{},..."string"==typeof t.nodeId?{nodeId:t.nodeId}:{},..."string"==typeof t.protocolVersion?{protocolVersion:t.protocolVersion}:{},...i.success?{platform:i.data}:{},...s.success?{arch:s.data}:{},...r.success?{capabilities:r.data}:{},...n.success?{build:n.data}:{},..."string"==typeof t.serverTime?{serverTime:t.serverTime}:{}}}function $d(e){const{agent:t,...n}=e.capabilities,{secret:i,...s}=e.auth,r=s.pairing?{...s.pairing,joinToken:void 0}:void 0,o=qd(t);return{...e,auth:r?{...s,pairing:r}:s,capabilities:o?{...n,agent:o}:n}}function Bd(e){return"local-folder"===e.type?{mode:"local-bind",path:"/workspace",readOnly:!1}:{mode:"git-clone",path:"/workspace",readOnly:!1}}function Ud(e){return function(e){const{registrationToken:t,target:n,agentStatus:i,targetStatus:s,uiAccessStatus:r,...o}=e;return o}(function(e){const t=`/instances/${encodeURIComponent(e.id)}`,n={strategy:"control-plane-proxy",web:`${t}/`,api:`${t}/api`,ws:`${t}/api`,status:"online"===e.connectionStatus||"online"===e.agentStatus?"reachable":"endpoint-unreachable"};return{...e,access:n}}(e))}function Fd(e){const{key:t,...n}=e;return{...n,keyPreview:(i=e.key,i.length<=8?"set":`${i.slice(0,4)}...${i.slice(-4)}`),keySet:!0};var i}function Hd(){return(new Date).toISOString()}function Wd(e){return e?e instanceof Headers?Object.fromEntries(e.entries()):Array.isArray(e)?Object.fromEntries(e.map(([e,t])=>[e,t])):Object.fromEntries(Object.entries(e).map(([e,t])=>[e,String(t)])):{}}function Gd(e){const t=String(e||"").split(":");if(3===t.length&&"ai"===t[1]&&t[0]&&t[2])return{instanceId:t[0],aiSessionId:t[2]}}function Vd(e){return e instanceof Error?e.message:String(e)}function Kd(e,t){const n=new Error(t);throw Object.assign(n,{statusCode:404,code:e}),n}a.z.array(Ld);const Jd=a.z.object({proxyOrigin:Dn,inviteToken:a.z.string().trim().min(24).max(512),name:a.z.string().trim().min(1).max(160).optional()}).strict(),Yd=a.z.object({data:a.z.object({binding:ei,closed:a.z.object({abortedRequests:a.z.number().int().nonnegative(),closedSockets:a.z.number().int().nonnegative()}).strict()}).strict()}).strict();class Qd{claimOperations=new Map;options;constructor(e){this.options=e}listPendingClaims(){return this.options.privateStore.publicPendingClaims()}async claimNode(e){const t=Jd.parse(e),n=Hd(),i=ho("proxy_claim"),s={id:i,claimId:i,proxyOrigin:t.proxyOrigin,...t.name?{requestedName:t.name}:{},sourceControlPlaneId:this.options.privateStore.controlPlaneId(),bindingKeyId:ho("proxy_key"),credential:yo(),status:"pending",createdAt:n,updatedAt:n,expiresAt:new Date(Date.now()+864e5).toISOString()};return this.options.privateStore.putPendingClaim(s),this.withClaimLock(s.claimId,()=>this.completeClaim(s,t.inviteToken))}async resumeClaim(e){return this.withClaimLock(e,async()=>{const t=this.options.privateStore.pendingClaimByClaimId(e);return t||Kd("CONTROL_PLANE_PROXY_CLAIM_NOT_FOUND",`Proxy claim ${e} was not found.`),this.completeClaim(t)})}async cancelClaim(e){return this.withClaimLock(e,async()=>{const t=this.options.privateStore.pendingClaimByClaimId(e);if(!t)return{deleted:!1,compensationRequired:!1,remoteRevoke:"not-required"};if("pending"===t.status)return{...this.options.privateStore.cancelPendingClaim(e,!1),remoteRevoke:"not-required"};let n;try{n=await this.requestClaim(t)}catch(e){throw this.compensationError(t,"Trusted control-plane proxy is unavailable; claim cancellation requires retry.",e)}const i=await this.responsePayload(n);if(!n.ok){const s=i?.error?.code;if(s===Hn.InviteInvalid||s===Hn.BindingRevoked)return{deleted:this.options.privateStore.completePendingClaimCompensation(e),compensationRequired:!1,remoteRevoke:s===Hn.BindingRevoked?"already-revoked":"not-created"};throw this.compensationError(t,i?.error?.message||`Proxy claim recovery failed with HTTP ${n.status}.`,void 0,n.status,s,i?.error?.retryable)}const s=Uo(ci,i?.data);this.requireClaimResultIdentity(t,s);const r=this.compensationCredential(t,s);let o;try{o=await this.revokeBinding(r)}catch(e){throw this.compensationError(t,"Trusted control-plane proxy is unavailable; binding revocation requires retry.",e)}const a=await this.responsePayload(o);if(!o.ok&&a?.error?.code!==Hn.BindingRevoked)throw this.compensationError(t,a?.error?.message||`Proxy binding revoke failed with HTTP ${o.status}.`,void 0,o.status,a?.error?.code,a?.error?.retryable);if(o.ok)try{this.requireRevocationReceipt(a,r)}catch(e){throw this.compensationError(t,"Proxy binding revocation returned an invalid receipt; compensation requires retry.",e,502,Hn.TransportFailed,!0)}return{deleted:this.options.privateStore.completePendingClaimCompensation(e),compensationRequired:!1,remoteRevoke:o.ok?"revoked":"already-revoked"}})}applyTargetSnapshot(e,t){const n=this.requireProxyNodeIdentity(e,t.binding.id,t.binding.targetNodeId);return this.putTargetState(n,t.target,{reachability:"reachable",bindingStatus:t.binding.status,bindingRevision:t.binding.revision,streamId:t.streamId,revision:t.revision,observedAt:t.observedAt})}applyTargetEvent(e,t){const n=this.requireProxyNodeIdentity(e,void 0,t.targetNodeId),i=n.proxyState;if(!i?.streamId||i.streamId!==t.streamId||void 0===i.revision||t.revision!==i.revision+1){const e=new Error("Proxy target event does not continue the authoritative snapshot cursor.");throw Object.assign(e,{code:Hn.SnapshotRequired,statusCode:409,retryable:!0}),e}return this.putTargetState(n,t.target,{...i,reachability:"reachable",bindingStatus:"revoked"===i.bindingStatus?"revoked":"active",revision:t.revision,observedAt:t.event.createdAt})}markUnavailable(e,t){const n=this.requireProxyNodeIdentity(e),i=Hd();return this.options.nodes.put(fr.parse({...n,status:"degraded",health:"degraded",proxyState:{...n.proxyState,reachability:"unreachable",bindingStatus:n.proxyState?.bindingStatus??"unknown",lastError:t,updatedAt:i},updatedAt:i}))}markBindingRevoked(e,t){const n=this.requireProxyNodeIdentity(e),i=Hd();return this.options.nodes.put(fr.parse({...n,status:"degraded",health:"degraded",proxyState:{...n.proxyState,reachability:"reachable",bindingStatus:"revoked",lastError:t,updatedAt:i},updatedAt:i}))}assertIdentityPatch(e,t){const n=t.connectionMode??e.connectionMode,i=t.connectionPath??e.connectionPath,s=t.auth??e.auth,r="control-plane-proxy"===e.connectionMode||"control-plane-proxy"===e.connectionPath.kind||"proxy-binding"===e.auth.mode,o="control-plane-proxy"===n||"control-plane-proxy"===i.kind||"proxy-binding"===s.mode,a=n!==e.connectionMode||JSON.stringify(i)!==JSON.stringify(e.connectionPath)||JSON.stringify(s)!==JSON.stringify(e.auth);if((r||o)&&a){const e=new Error("Proxy node connection identity can only be changed through the control-plane proxy lifecycle API.");throw Object.assign(e,{statusCode:409,code:"CONTROL_PLANE_PROXY_IDENTITY_IMMUTABLE",retryable:!1}),e}}async deleteNode(e,t=!1){if("control-plane-proxy"!==e.connectionMode)return{deleted:this.options.deleteNode(e.id),revoke:{mode:"not-proxied",orphanRisk:!1}};const n=this.options.privateStore.nodeCredential(e.id);if(!n){if(!t){const e=new Error("Proxy node credential is missing; remote binding cannot be revoked.");throw Object.assign(e,{statusCode:409,code:"CONTROL_PLANE_PROXY_CREDENTIAL_REQUIRED",retryable:!1,details:{forceDeleteAllowed:!0,forceDeleteReason:"credential-missing"}}),e}return this.forceDeleteNode(e.id)}let i;try{i=await this.revokeBinding(n)}catch(n){if(t)return this.forceDeleteNode(e.id);const i=new Error("Trusted control-plane proxy is unavailable; the binding was not revoked.",{cause:n});throw Object.assign(i,{statusCode:503,code:"CONTROL_PLANE_PROXY_REVOKE_UNAVAILABLE",retryable:!0,details:{forceDeleteAllowed:!0,forceDeleteReason:"proxy-unavailable"}}),i}const s=await this.responsePayload(i);if(!i.ok){if(s?.error?.code===Hn.BindingRevoked){const t=s.error.details?.bindingId;if(t===n.proxyBindingId)return this.finishRevokedNodeDelete(e.id)}const t=new Error(s?.error?.message||`Proxy binding revoke failed with HTTP ${i.status}.`);throw Object.assign(t,{statusCode:i.status,code:s?.error?.code||"CONTROL_PLANE_PROXY_REVOKE_FAILED",retryable:s?.error?.retryable??i.status>=500,details:{...(r=s?.error?.details,r&&"object"==typeof r&&!Array.isArray(r)?r:{}),forceDeleteAllowed:!1}}),t}var r;try{this.requireRevocationReceipt(s,n)}catch(e){if(e&&"object"==typeof e){const t=e;t.details={...t.details||{},forceDeleteAllowed:!1}}throw e}return this.finishRevokedNodeDelete(e.id)}async completeClaim(e,t){let n;this.options.privateStore.markCompensationRequired(e.claimId);try{n=await this.requestClaim(e,t)}catch(t){const n=new Error(`Trusted control-plane proxy ${e.proxyOrigin} is unavailable.`,{cause:t});throw Object.assign(n,{statusCode:503,code:"CONTROL_PLANE_PROXY_UNAVAILABLE",retryable:!0,claimId:e.claimId}),n}const i=await this.responsePayload(n);if(!n.ok){const t=i?.error?.retryable??n.status>=500;t||this.options.privateStore.completePendingClaimCompensation(e.claimId);const s=new Error(i?.error?.message||`Proxy claim failed with HTTP ${n.status}.`);throw Object.assign(s,{statusCode:n.status,code:i?.error?.code||"CONTROL_PLANE_PROXY_CLAIM_FAILED",retryable:t,details:i?.error?.details,claimId:e.claimId}),s}const s=Uo(ci,i?.data);this.requireClaimResultIdentity(e,s);const r=this.options.nodes.get(s.target.id),o="control-plane-proxy"===r?.connectionMode&&"control-plane-proxy"===r.connectionPath.kind&&r.connectionPath.proxyBindingId===s.binding.id&&r.connectionPath.targetNodeId===s.target.id;if(r&&!o){this.options.privateStore.markCompensationRequired(e.claimId);const t=new Error(`Node ${s.target.id} already exists with another connection identity.`);throw Object.assign(t,{statusCode:409,code:"CONTROL_PLANE_PROXY_NODE_IDENTITY_CONFLICT",claimId:e.claimId}),t}const a={id:`proxy_credential_${s.target.id}`,nodeId:s.target.id,proxyOrigin:e.proxyOrigin,proxyBindingId:s.binding.id,targetNodeId:s.target.id,sourceControlPlaneId:e.sourceControlPlaneId,bindingKeyId:e.bindingKeyId,credential:e.credential,createdAt:e.createdAt,updatedAt:Hd()},d=r||fr.parse({id:s.target.id,name:e.requestedName||s.target.name,connectionMode:"control-plane-proxy",connectionPath:{kind:"control-plane-proxy",proxyId:new URL(e.proxyOrigin).host,proxyBindingId:s.binding.id,targetNodeId:s.target.id},connectionEnabled:!0,auth:{mode:"proxy-binding"},status:s.target.status,health:s.target.health,capabilities:s.target.capabilities,proxyState:{reachability:"reachable",bindingStatus:s.binding.status,bindingRevision:s.binding.revision,observedAt:Hd(),target:s.target,updatedAt:Hd()},labels:{},lastSeenAt:s.target.lastSeenAt,createdAt:Hd(),updatedAt:Hd()});r||this.options.nodes.put(d);try{this.options.privateStore.promotePendingClaim(e.claimId,a)}catch(e){throw r||this.options.nodes.delete(d.id),e}return{node:$d(d),binding:s.binding}}requireProxyNodeIdentity(e,t,n){const i=this.options.requireNode(e);if("control-plane-proxy"!==i.connectionMode||"control-plane-proxy"!==i.connectionPath.kind||void 0!==t&&i.connectionPath.proxyBindingId!==t||void 0!==n&&i.connectionPath.targetNodeId!==n){const e=new Error("Proxy state identity does not match the node connection path.");throw Object.assign(e,{code:Hn.BindingIdentityConflict,statusCode:409,retryable:!1}),e}return i}putTargetState(e,t,n){const i=Hd();return this.options.nodes.put(fr.parse({...e,name:t.name,status:t.status,health:t.health,capabilities:t.capabilities,lastSeenAt:t.lastSeenAt,proxyState:{...n,target:t,updatedAt:i},updatedAt:i}))}requestClaim(e,t){return this.options.fetchImpl(new URL("/api/node-proxy/claims",e.proxyOrigin),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({protocolVersion:Nn,...t?{inviteToken:t}:{},claimId:e.claimId,sourceControlPlaneId:e.sourceControlPlaneId,...e.targetNodeId?{targetNodeId:e.targetNodeId}:{},bindingKeyId:e.bindingKeyId,credential:e.credential})})}revokeBinding(e){return this.options.fetchImpl(new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}`,e.proxyOrigin),{method:"DELETE",headers:vd(e)})}async responsePayload(e){return e.json().catch(()=>{})}requireRevocationReceipt(e,t){const n=Bo(Yd,e),i=n.success?n.data.data.binding:void 0;if(!i||i.id!==t.proxyBindingId||i.sourceControlPlaneId!==t.sourceControlPlaneId||i.targetNodeId!==t.targetNodeId||i.bindingKeyId!==t.bindingKeyId||"revoked"!==i.status){const e=new Error("Proxy binding revocation receipt does not match the local binding identity.");throw Object.assign(e,{statusCode:502,code:Hn.TransportFailed,retryable:!0,details:{bindingId:t.proxyBindingId}}),e}return i}requireClaimResultIdentity(e,t){if(t.binding.claimId!==e.claimId||t.binding.sourceControlPlaneId!==e.sourceControlPlaneId||t.binding.bindingKeyId!==e.bindingKeyId||t.binding.targetNodeId!==t.target.id||void 0!==e.targetNodeId&&t.binding.targetNodeId!==e.targetNodeId){const t=new Error("Proxy claim response does not match the persisted pending identity.");throw Object.assign(t,{statusCode:409,code:Hn.BindingIdentityConflict,retryable:!1,claimId:e.claimId,compensationRequired:!0}),t}}compensationCredential(e,t){return{id:`proxy_compensation_${t.binding.id}`,nodeId:t.target.id,proxyOrigin:e.proxyOrigin,proxyBindingId:t.binding.id,targetNodeId:t.target.id,sourceControlPlaneId:e.sourceControlPlaneId,bindingKeyId:e.bindingKeyId,credential:e.credential,createdAt:e.createdAt,updatedAt:Hd()}}compensationError(e,t,n,i=503,s="CONTROL_PLANE_PROXY_COMPENSATION_REQUIRED",r=!0){const o=new Error(t,void 0===n?void 0:{cause:n});return Object.assign(o,{statusCode:i,code:s,retryable:r,claimId:e.claimId,compensationRequired:!0}),o}async withClaimLock(e,t){const n=(this.claimOperations.get(e)??Promise.resolve()).catch(()=>{}).then(t);this.claimOperations.set(e,n);try{return await n}finally{this.claimOperations.get(e)===n&&this.claimOperations.delete(e)}}finishRevokedNodeDelete(e){const t=this.options.deleteNode(e);return this.options.privateStore.deleteNodeCredential(e),{deleted:t,revoke:{mode:"revoked",orphanRisk:!1}}}forceDeleteNode(e){const t=this.options.deleteNode(e);return this.options.privateStore.deleteNodeCredential(e),{deleted:t,revoke:{mode:"forced",orphanRisk:!0}}}}const Xd=a.z.object({id:js.shape.id.optional(),name:js.shape.name,source:_s,defaultImageSelection:js.shape.defaultImageSelection,defaultNodeId:js.shape.defaultNodeId,defaultRuntimeId:js.shape.defaultRuntimeId,workspacePolicy:Rs.optional(),labels:js.shape.labels.optional()}).strict(),Zd=Xd.omit({id:!0}).partial().strict();function ec(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"/"!==e&&"\\"!==e}const tc=a.z.string().refine(ec,"Mention trigger must be one printable non-alphanumeric character other than / or \\.");function nc(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"\\"!==e}const ic=a.z.string().refine(nc,"Command trigger must be one printable non-alphanumeric character other than \\."),sc=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:Is.default("stable"),mentionTrigger:tc.default("@"),commandTrigger:ic.default("/"),diagnosticLogs:a.z.boolean().default(!1)}).strict().refine(e=>e.mentionTrigger!==e.commandTrigger,{path:["commandTrigger"],message:"Command and mention triggers must be different."}),rc=a.z.object({publicBaseUrl:a.z.string().trim().max(2048).optional(),updateChannel:Is.optional(),mentionTrigger:tc.optional(),commandTrigger:ic.optional(),diagnosticLogs:a.z.boolean().optional()}).strict(),oc=a.z.object({id:ir.shape.id.optional(),name:ir.shape.name,description:ir.shape.description,cover:ir.shape.cover,reference:ir.shape.reference,pullPolicy:ir.shape.pullPolicy.optional(),capabilities:a.z.array(a.z.string().trim().min(1).max(80)).optional(),optionalApps:a.z.array(a.z.string().trim().min(1).max(120)).optional(),defaultEnv:ir.shape.defaultEnv.optional(),labels:ir.shape.labels.optional()}).strict(),ac=oc.omit({id:!0}).partial().strict(),dc=a.z.object({name:Hr.shape.name.optional(),channel:Hr.shape.channel.optional(),enabled:a.z.boolean().optional(),token:Hr.shape.token,defaultChatId:Hr.shape.defaultChatId,allowedUserIds:a.z.array(a.z.string().trim().min(1).max(240)).optional(),pollIntervalMs:Hr.shape.pollIntervalMs.optional(),settings:Hr.shape.settings.optional()}).strict(),cc=dc.extend({channel:Hr.shape.channel,name:Hr.shape.name.optional()}),lc=fn.extend({id:fn.shape.configHash}),pc=a.z.object({name:fn.shape.name,description:fn.shape.description,source:gn,action:hn,policy:yn.partial().optional()}).strict(),uc=pc,mc=a.z.object({instanceIds:a.z.array(Mr.shape.id).min(1),target:In,enabled:a.z.boolean().optional()}).strict(),gc=a.z.object({configHash:fn.shape.configHash,enabled:a.z.boolean().optional()}).strict(),hc=a.z.object({mode:a.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:fr.shape.id.optional(),secret:a.z.string().trim().max(4096).optional(),pairedAt:fr.shape.createdAt.optional(),pairing:a.z.object({status:a.z.enum(["pending","paired","expired"]).default("pending"),joinToken:a.z.string().trim().max(4096).optional(),expiresAt:fr.shape.createdAt.optional()}).strict().optional()}).strict(),yc=a.z.object({autoImportAgentConfigs:a.z.boolean().optional(),defaultCodexPermissionMode:de.optional(),aiSessionHistoryLimit:a.z.number().int().min(1).max(Ve).optional()}).strict(),fc=a.z.object({id:Mr.shape.id.optional(),name:Mr.shape.name.optional(),projectId:Mr.shape.projectId,source:_s.optional(),sourceSnapshot:a.z.record(a.z.string(),a.z.unknown()).optional(),nodeId:Mr.shape.nodeId.optional(),runtimeId:Mr.shape.runtimeId.optional(),environmentSource:Mi.optional(),imageSelection:Mr.shape.imageSelection,config:yc.optional(),modelSelection:Mr.shape.modelSelection.optional(),start:a.z.boolean().default(!1)}).strict().superRefine((e,t)=>{e.environmentSource&&e.imageSelection&&t.addIssue({code:"custom",path:["environmentSource"],message:"environmentSource and imageSelection are mutually exclusive."})}),Ic=a.z.object({name:Mr.shape.name.optional(),config:yc.optional(),modelSelection:Mr.shape.modelSelection.optional()}).strict(),bc=a.z.object({name:Ds.shape.name,endpoint:Ds.shape.endpoint,key:Ds.shape.key,model:Ds.shape.model,app:Ds.shape.app,enabled:Ds.shape.enabled.optional(),order:Ds.shape.order.optional(),labels:Ds.shape.labels.optional()}).strict(),vc=bc.partial().strict(),wc=a.z.object({endpoint:Ds.shape.endpoint,key:Ds.shape.key.optional(),existingModelId:Ds.shape.id.optional()}).strict(),Sc=wc.extend({model:Ds.shape.model,app:Ds.shape.app}).strict(),Ac=a.z.object({id:fr.shape.id.optional(),name:fr.shape.name,connectionMode:fr.shape.connectionMode.optional(),connectionPath:fr.shape.connectionPath.optional(),connectionEnabled:fr.shape.connectionEnabled.optional(),auth:hc.optional(),joinToken:a.z.string().trim().min(1).max(4096).optional(),endpoint:fr.shape.endpoint,controlEndpoint:fr.shape.controlEndpoint,containerEndpoint:fr.shape.containerEndpoint,publicWebBase:fr.shape.publicWebBase,status:a.z.enum(["unknown","online","offline","degraded"]).optional(),health:a.z.enum(["unknown","ok","degraded","failed"]).optional(),capabilities:fr.shape.capabilities.optional(),labels:fr.shape.labels.optional(),lastSeenAt:fr.shape.lastSeenAt}).strict(),kc=a.z.object({name:fr.shape.name.optional(),connectionMode:fr.shape.connectionMode.unwrap().optional(),connectionPath:fr.shape.connectionPath.unwrap().optional(),connectionEnabled:fr.shape.connectionEnabled.unwrap().optional(),auth:hc.optional(),endpoint:fr.shape.endpoint,controlEndpoint:fr.shape.controlEndpoint,containerEndpoint:fr.shape.containerEndpoint,publicWebBase:fr.shape.publicWebBase,status:fr.shape.status.unwrap().optional(),health:fr.shape.health.unwrap().optional(),capabilities:fr.shape.capabilities.unwrap().optional(),labels:fr.shape.labels.unwrap().optional(),lastSeenAt:fr.shape.lastSeenAt}).strict(),zc=a.z.object({controlPlaneUrl:a.z.string().trim().url().max(2048),joinToken:a.z.string().trim().min(1).max(4096),controlPlaneName:a.z.string().trim().min(1).max(160).optional(),activate:a.z.boolean().optional()}).strict(),Tc=a.z.object({nodeName:a.z.string().trim().min(1).max(160).optional(),expiresInMs:a.z.number().int().positive().max(36e5).optional()}).strict(),Ec=a.z.object({id:a.z.string().min(1),endpoint:a.z.string().min(1),nodeId:a.z.string().min(1),keyId:a.z.string().min(1),secret:a.z.string().min(1),pairedAt:a.z.string().min(1),createdAt:a.z.string().min(1),updatedAt:a.z.string().min(1)}).strict();class Cc{options;activePendingPairingRevokes=new Set;constructor(e){this.options=e}async syncLocal(){const e={[this.options.localNodeLabel]:"true",[this.options.builtinNodeLabel]:"true"},t=process.env.TASK_HANDOFF_NODE_AGENT_TOKEN?.trim()||void 0,n=process.env.TASK_HANDOFF_NODE_AGENT_CONTROL_ENDPOINT||process.env.TASK_HANDOFF_NODE_AGENT_ENDPOINT||"http://127.0.0.1:8091",i=function(e){return ad(e)?"local-ipc":"local-loopback"}(n),s=fr.parse({id:"node_local_probe",name:"Local Node Probe",connectionMode:i,auth:{mode:"local-static-key",secret:t},labels:e,createdAt:Hd(),updatedAt:Hd()}),r=await this.inspect(n,s),o=Hd(),a=this.options.nodes.get(r.nodeId);for(const e of this.options.nodes.list())"true"===e.labels[this.options.localNodeLabel]&&e.id!==r.nodeId&&this.options.nodes.delete(e.id);return this.options.nodes.put(fr.parse({...a||{},id:r.nodeId,name:a?.name||"Local Node",connectionMode:i,auth:{mode:"local-static-key",secret:t},endpoint:n,controlEndpoint:n,containerEndpoint:process.env.TASK_HANDOFF_NODE_AGENT_CONTAINER_URL,publicWebBase:process.env.TASK_HANDOFF_INSTANCE_PUBLIC_WEB_BASE,status:"online",health:"ok",capabilities:{...a?.capabilities||{},agent:qd(r.data)},labels:{...a?.labels||{},...e},createdAt:a?.createdAt||o,updatedAt:o}))}async create(e){const t=Ac.parse(e),n=Hd(),i=t.connectionMode||"direct-http";let s="auth"in(e&&"object"==typeof e&&!Array.isArray(e)?e:{})?t.auth:{mode:"local-ipc"===i||"local-loopback"===i?"local-static-key":"paired-hmac"};const r="direct-http"===i||"reverse-wss"===i;if(r&&"paired-hmac"!==s.mode)throw xc("Remote node connections require paired-HMAC authentication.","NODE_AGENT_REMOTE_REQUIRES_PAIRED_HMAC");const o=t.controlEndpoint||t.endpoint;if(!o&&"reverse-wss"!==i)throw xc("Node agent direct HTTP mode requires an endpoint.","NODE_AGENT_ENDPOINT_REQUIRED");const a=t.joinToken&&o?await this.completePairing(o,t.joinToken):void 0;let d,c=!1;try{if(d=a&&o?this.pendingPairingRevoke(o,a):void 0,d&&(this.activePendingPairingRevokes.add(d.id),this.options.pendingPairingRevokes?.put(d)),a){if(a.invalidResponse||a.unsafePublicIdentifiers)throw Object.assign(new Error("Node agent pairing response reflected secret material in a public identifier."),{statusCode:502,code:"NODE_AGENT_PAIRING_RESPONSE_INVALID"});s={mode:"paired-hmac",keyId:a.keyId,secret:a.secret,pairedAt:a.pairedAt,pairing:{status:"paired"}}}if(r&&!s.secret)throw xc("Remote node connections require a paired node secret or join token.","NODE_AGENT_REMOTE_SECRET_REQUIRED");if(r&&!s.keyId)throw xc("Remote node connections require a paired key id.","NODE_AGENT_REMOTE_KEY_ID_REQUIRED");const e=t.id||a?.nodeId||ho("node"),u=fr.parse({id:e,name:t.name,connectionMode:i,auth:s,labels:t.labels||{},createdAt:n,updatedAt:n}),m="reverse-wss"===i&&(t.id||a?.nodeId)?void 0:await this.inspect(o||"",u),g=t.id||a?.nodeId||m?.nodeId||e;if(!g)throw xc("Node id is required.","NODE_ID_REQUIRED");if(a&&t.id&&t.id!==a.nodeId)throw xc(`Paired node id ${a.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(t.id&&m?.nodeId&&m.nodeId!==t.id)throw xc(`Node agent id ${m.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(a&&m?.nodeId&&m.nodeId!==a.nodeId)throw Object.assign(new Error("Node agent health identity did not match the completed pairing."),{statusCode:502,code:"NODE_AGENT_PAIRING_IDENTITY_MISMATCH"});const{joinToken:h,...y}=t,f=fr.parse({...y,id:g,connectionMode:i,auth:s,endpoint:o,controlEndpoint:o,status:t.status||(m?"online":"unknown"),health:t.health||(m?"ok":"unknown"),capabilities:{...t.capabilities||{},...m?{agent:qd(m.data)}:{}},labels:t.labels||{},createdAt:n,updatedAt:n});if(a&&(l=f,p=a.secret,Pc($d(l),p)))throw Object.assign(new Error("Node agent health response reflected pairing secret material."),{statusCode:502,code:"NODE_AGENT_PAIRING_SECRET_REFLECTED"});c=!0;const I=this.options.nodes.put(f);return this.clearPendingPairingRevoke(d,a),I}catch(e){if(a&&o){const t=this.pairingPersistence(a);if("present"===t.state)return this.clearPendingPairingRevoke(d,a),t.node;if("unknown"===t.state&&c)throw jc(Object.assign(new Error("Node creation persistence outcome is uncertain; pairing compensation is pending."),{statusCode:503,code:"NODE_AGENT_PAIRING_PERSISTENCE_UNCERTAIN",retryable:!0}),a.secret);throw await this.compensatePairing(o,a,e),this.clearPendingPairingRevoke(d,a),jc(e,a.secret)}throw e}finally{d&&this.activePendingPairingRevokes.delete(d.id)}var l,p}async recoverPendingPairingRevokes(){const e=(this.options.pendingPairingRevokes?.list()||[]).filter(e=>!this.activePendingPairingRevokes.has(e.id));await Promise.all(e.map(async e=>{try{const t={nodeId:e.nodeId,keyId:e.keyId,secret:e.secret,pairedAt:e.pairedAt,invalidResponse:!1,unsafePublicIdentifiers:!1},n=this.pairingPersistence(t);if("present"===n.state)return void this.clearPendingPairingRevoke(e,t);if("unknown"===n.state)return;await this.compensatePairing(e.endpoint,t,Object.assign(new Error("Recovering a pending pairing revocation."),{code:"NODE_AGENT_PAIRING_REVOCATION_PENDING"})),this.clearPendingPairingRevoke(e,t)}catch{}}))}pendingPairingRevoke(e,t){if(!this.options.pendingPairingRevokes)return;const n=Hd();return Ec.parse({id:ho("pairing_revoke"),endpoint:e,nodeId:t.nodeId,keyId:t.keyId,secret:t.secret,pairedAt:t.pairedAt,createdAt:n,updatedAt:n})}pairingPersistence(e){let t;try{t=this.options.nodes.get(e.nodeId)}catch{return{state:"unknown"}}return"paired-hmac"===t?.auth.mode&&t.auth.keyId===e.keyId&&t.auth.secret===e.secret?{state:"present",node:t}:{state:"absent"}}clearPendingPairingRevoke(e,t){if(e)try{this.options.pendingPairingRevokes?.delete(e.id)}catch(e){try{this.options.warn({nodeId:t?_c(t.nodeId,t.secret):void 0,keyId:t?_c(t.keyId,t.secret):void 0,errorCode:"NODE_AGENT_PAIRING_OUTBOX_CLEANUP_FAILED"},"node agent pairing outbox cleanup failed; recovery will retry")}catch{}}}async inspect(e,t){const n="/health",i=t?sd(t,{method:"GET",pathWithQuery:`/api/node-agent${n}`}):{},s=await ud(this.options.fetchImpl,e,n,{headers:i}),r=await s.json().catch(()=>({}));if(!s.ok)throw this.options.warn(Rc({nodeEndpoint:e,statusCode:s.status,errorCode:"NODE_AGENT_HEALTH_FAILED"},t?.auth.secret),"node agent health check failed"),Object.assign(new Error(r.error?.message||`Node agent health check failed with HTTP ${s.status}`),{statusCode:s.status,code:"NODE_AGENT_HEALTH_FAILED"});const o="string"==typeof r.data?.nodeId&&r.data.nodeId.trim()?r.data.nodeId.trim():void 0;if(!o)throw this.options.warn(Rc({nodeEndpoint:e,errorCode:"NODE_AGENT_ID_MISSING"},t?.auth.secret),"node agent health response missing node id"),Object.assign(new Error("Node agent health response did not include nodeId."),{statusCode:502,code:"NODE_AGENT_ID_MISSING"});const a=Bo(ys,r.data?.build);return r.data?.protocolVersion!==ui&&this.options.warn(Rc({nodeId:o,nodeEndpoint:e,expectedProtocolVersion:ui,actualProtocolVersion:r.data?.protocolVersion,build:a.success?a.data:void 0,errorCode:"PROTOCOL_VERSION_MISMATCH"},t?.auth.secret),"node agent protocol version mismatch"),this.options.info(Rc({nodeId:o,nodeEndpoint:e,protocolVersion:r.data.protocolVersion,build:a.success?a.data:void 0},t?.auth.secret),"node agent health check ok"),{nodeId:o,data:r.data||{}}}async completePairing(e,t){const n=await this.options.fetchImpl(`${e.replace(/\/$/,"")}/api/node-agent/pairing/complete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({joinToken:t,controlPlaneName:"Control Plane"})}),i=await n.json().catch(()=>({}));if(!n.ok)throw Object.assign(new Error(i.error?.message||`Node agent pairing failed with status ${n.status}.`),{statusCode:n.status,code:"NODE_AGENT_PAIRING_FAILED"});const s=i.data;if("string"!=typeof s?.nodeId||!s.nodeId.trim()||"string"!=typeof s?.keyId||!s.keyId.trim()||"string"!=typeof s?.secret||!s.secret.trim())throw Object.assign(new Error("Node agent pairing response did not include nodeId, keyId, and secret."),{statusCode:502,code:"NODE_AGENT_PAIRING_RESPONSE_INVALID"});const r=Bo(kr,s),o=s.nodeId.trim(),a=s.keyId.trim(),d=s.secret.trim();return{nodeId:o,keyId:a,secret:d,pairedAt:r.success?r.data.pairedAt:Hd(),invalidResponse:!r.success,unsafePublicIdentifiers:o.includes(d)||a.includes(d)}}async compensatePairing(e,t,n){const i="/pairing/current",s=`/api/node-agent${i}`,r={id:t.nodeId,connectionMode:"direct-http",auth:{mode:"paired-hmac",keyId:t.keyId,secret:t.secret}};try{const o=await ud(this.options.fetchImpl,e,i,{method:"DELETE",headers:sd(r,{method:"DELETE",pathWithQuery:s}),signal:AbortSignal.timeout(1e4)}),a=await o.json().catch(()=>({}));if(!o.ok)throw Object.assign(new Error(`Node agent pairing revoke failed with HTTP ${o.status}.`),{statusCode:o.status,code:Oc(a.error?.code,t.secret,"NODE_AGENT_PAIRING_REVOKE_FAILED"),retryable:408===o.status||429===o.status||o.status>=500});const d=Bo(Tr,a.data);if(!d.success)throw Object.assign(new Error("Node agent pairing revoke receipt was invalid."),{statusCode:502,code:"NODE_AGENT_PAIRING_REVOKE_RECEIPT_INVALID",retryable:!1});if(d.data.keyId!==t.keyId)throw Object.assign(new Error("Node agent pairing revoke receipt did not match the paired key."),{statusCode:502,code:"NODE_AGENT_PAIRING_REVOKE_RECEIPT_MISMATCH",retryable:!1});try{this.options.info({nodeId:_c(t.nodeId,t.secret),keyId:_c(t.keyId,t.secret),originalErrorCode:Nc(n,t.secret)},"node agent pairing revoked after node creation failed")}catch{}}catch(e){const i={nodeId:_c(t.nodeId,t.secret),keyId:_c(t.keyId,t.secret),originalErrorCode:Nc(n,t.secret),compensationErrorCode:Nc(e,t.secret)};try{this.options.warn(i,"node agent pairing compensation failed")}catch{}throw Object.assign(new Error("Node creation failed after pairing, and the remote pairing could not be revoked."),{statusCode:502,code:"NODE_AGENT_PAIRING_COMPENSATION_FAILED",retryable:(o=e,!o||"object"!=typeof o||!("retryable"in o)||"boolean"!=typeof o.retryable||o.retryable),details:i})}var o}}function xc(e,t){return Object.assign(new Error(e),{statusCode:400,code:t})}function Nc(e,t){return Oc(e&&"object"==typeof e&&"code"in e?e.code:void 0,t,"UNKNOWN_ERROR")}function Oc(e,t,n){return"string"!=typeof e||!/^[A-Z][A-Z0-9_]{0,127}$/.test(e)||e.includes(t)?n:e}function _c(e,t){return e.includes(t)?"[redacted]":e}function Rc(e,t){if(!t)return e;const n=e=>"string"==typeof e?e.includes(t)?"[redacted]":e:Array.isArray(e)?e.map(n):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).map(([e,i])=>[e.includes(t)?"[redacted-key]":e,n(i)])):e;return n(e)}function Pc(e,t){return"string"==typeof e?e.includes(t):Array.isArray(e)?e.some(e=>Pc(e,t)):!(!e||"object"!=typeof e)&&Object.entries(e).some(([e,n])=>e.includes(t)||Pc(n,t))}function jc(e,t){const n=e instanceof Error&&!e.message.includes(t)?e.message:"Node creation failed after pairing.",i=e&&"object"==typeof e&&"statusCode"in e&&"number"==typeof e.statusCode?e.statusCode:502,s=Object.assign(new Error(n),{statusCode:i,code:Nc(e,t)});return e&&"object"==typeof e&&"retryable"in e&&"boolean"==typeof e.retryable&&Object.assign(s,{retryable:e.retryable}),s}class Dc{values=new Map;put(e,t){this.prune(),this.values.set(e,t)}take(e){this.prune();const t=this.values.get(e);return t&&this.values.delete(e),t}prune(e=Date.now()){for(const[t,n]of this.values)Date.parse(n.expiresAt)<=e&&this.values.delete(t)}}const Mc=a.z.object({joinToken:a.z.string().trim().min(1).max(4096),nodeId:fr.shape.id,nodeName:fr.shape.name.optional(),keyId:a.z.string().trim().min(1).max(160),secret:a.z.string().trim().min(1).max(4096),pairedAt:a.z.string().datetime().optional()}).strict();class Lc{options;invites=new Dc;constructor(e){this.options=e}createInvite(e={}){const t=Tc.parse(e&&"object"==typeof e?e:{}),n=yo(),i={id:ho("node_join"),tokenHash:qc(n),expiresAt:new Date(Date.now()+(t.expiresInMs||6e5)).toISOString(),...t.nodeName?{nodeName:t.nodeName}:{}};return this.invites.put(i.tokenHash,i),{id:i.id,joinToken:n,expiresAt:i.expiresAt}}complete(e){const t=Mc.parse(e),n=qc(t.joinToken),i=this.invites.take(n);if(!i)throw Object.assign(new Error("Node join token is invalid or expired."),{statusCode:401,code:"NODE_JOIN_TOKEN_INVALID"});const s=Hd();if(this.options.nodes.get(t.nodeId))throw Object.assign(new Error(`Node ${t.nodeId} already exists in this control-plane.`),{statusCode:409,code:"NODE_JOIN_NODE_ALREADY_EXISTS"});return this.options.nodes.put(fr.parse({id:t.nodeId,name:t.nodeName||i.nodeName||t.nodeId,connectionMode:"reverse-wss",auth:{mode:"paired-hmac",keyId:t.keyId,secret:t.secret,pairedAt:t.pairedAt||s,pairing:{status:"paired"}},status:"unknown",health:"unknown",capabilities:{},labels:{},createdAt:s,updatedAt:s}))}}function qc(e){return i.createHash("sha256").update(e).digest("hex")}function $c(e,t){const n=Bc(e);return n.pathname=`${n.pathname.replace(/\/+$/,"")}/${t.replace(/^\/+/,"")}`,n.search="",n.hash="",n.toString()}function Bc(e){let t;try{t=new URL(e.trim())}catch{throw Wc("MODEL_ENDPOINT_INVALID","The model endpoint must be a valid HTTP or HTTPS URL.",400)}if("http:"!==t.protocol&&"https:"!==t.protocol||t.username||t.password)throw Wc("MODEL_ENDPOINT_INVALID","The model endpoint must be an HTTP or HTTPS URL without embedded credentials.",400);return t}async function Uc(e,t,n){try{return await e(t,{...n,redirect:"error",signal:AbortSignal.timeout(15e3)})}catch(e){const t=e&&"object"==typeof e&&"name"in e&&"TimeoutError"===e.name;throw Wc(t?"MODEL_ENDPOINT_TIMEOUT":"MODEL_ENDPOINT_UNREACHABLE",t?"The model endpoint timed out.":"The model endpoint could not be reached.",t?504:502)}}async function Fc(e,t){const n=await e.text();if(n.length>1e6)throw Wc(t,"The model endpoint response was too large.",502);try{const e=JSON.parse(n);if(!e||"object"!=typeof e||Array.isArray(e))throw new Error("not an object");return e}catch{throw Wc(t,"The model endpoint returned invalid JSON.",502)}}function Hc(e,t){return Wc(e,401===t||403===t?"The model endpoint rejected the API key.":"The model endpoint rejected the request.",502,t)}function Wc(e,t,n,i){return Object.assign(new Error(t),{code:e,statusCode:n,...i?{details:{upstreamStatus:i}}:{}})}function Gc(e,t){e.includes(t)||e.push(t)}function Vc(e){const t=new Set;return e.filter(e=>!t.has(e.id)&&(t.add(e.id),!0))}class Kc{options;constructor(e){this.options=e}list(){return this.listAll().map(Fd)}async listFederated(e){const t=await this.options.gateway.listFleetModels(this.options.listNodes(),{signal:e}),n=new Map;for(const e of this.listAll())n.set(e.id,{id:e.id,model:Fd(e),locations:[{type:"control-plane",name:e.name,enabled:e.enabled,order:e.order}],referenceCount:0});for(const{nodeId:e,model:i}of t.items){const{referenceCount:t,...s}=i,r=n.get(i.id);r?(r.locations.push({type:"node",nodeId:e,name:i.name,enabled:i.enabled,order:i.order,referenceCount:i.referenceCount}),r.referenceCount+=i.referenceCount):n.set(i.id,{id:i.id,model:s,locations:[{type:"node",nodeId:e,name:i.name,enabled:i.enabled,order:i.order,referenceCount:i.referenceCount}],referenceCount:i.referenceCount})}return Fs.parse({models:[...n.values()].sort((e,t)=>e.model.order-t.model.order||e.model.name.localeCompare(t.model.name)),nodeDiagnostics:t.nodeErrors.map(e=>({nodeId:e.nodeId,code:e.code,message:e.message})),updatedAt:Hd()})}create(e){const t=bc.parse(e),n=Hd(),i=Hs(t),s=this.options.models.get(i),r=Ds.parse({...t,id:i,enabled:t.enabled??!0,order:t.order??this.nextOrder(),labels:t.labels||{},createdAt:s?.createdAt||n,updatedAt:n});return Fd(this.options.models.put(r))}update(e,t){const n=vc.parse(t),i=this.requireSecret(e),s=Ds.parse({...i,...n,key:n.key?.trim()?n.key:i.key,createdAt:i.createdAt,updatedAt:Hd()}),r=Hs(s);return Fd(this.options.models.put(Ds.parse({...s,id:r})))}delete(e){return this.requireSecret(e),this.options.models.delete(e)}reorder(e){const t=[...new Set(e)],n=new Map(this.options.models.list().map(e=>[e.id,e]));for(const e of t)n.has(e)||Kd("MODEL_NOT_FOUND",`Model ${e} was not found.`);return t.forEach((e,t)=>{const i=n.get(e);this.options.models.put(Ds.parse({...i,order:100*(t+1),updatedAt:Hd()}))}),this.list()}createOnNode(e,t){return this.options.gateway.createModel(this.options.requireNode(e),t)}updateOnNode(e,t,n){return this.options.gateway.updateModel(this.options.requireNode(e),t,n)}deleteOnNode(e,t){return this.options.gateway.deleteModel(this.options.requireNode(e),t)}discover(e){const t=wc.parse(e);return async function(e,t){const n=function(e){const t=Bc(e),n=[],i=t.pathname.split("/").filter(Boolean).at(-1)||"";return Gc(n,$c(t.toString(),/^v\d+$/.test(i)?"models":"v1/models")),Gc(n,new URL("/v1/models",t.origin).toString()),Gc(n,new URL("/models",t.origin).toString()),n}(t.endpoint),i=Date.now();let s;for(const r of n){const n=await Uc(e,r,{method:"GET",headers:{accept:"application/json",authorization:`Bearer ${t.key}`}});if(404===n.status||405===n.status){s=n.status;continue}if(!n.ok)throw Hc("MODEL_DISCOVERY_FAILED",n.status);const o=await Fc(n,"MODEL_DISCOVERY_RESPONSE_INVALID"),a=Array.isArray(o.data)?o.data:void 0;if(!a)throw Wc("MODEL_DISCOVERY_RESPONSE_INVALID","The model endpoint returned an invalid model list.",502);return{models:Vc(a.flatMap(e=>{if(!e||"object"!=typeof e||Array.isArray(e))return[];const t=e,n="string"==typeof t.id?t.id.trim():"";if(!n)return[];const i="string"==typeof t.owned_by?t.owned_by.trim():"";return[{id:n,...i?{ownedBy:i}:{}}]}).sort((e,t)=>e.id.localeCompare(t.id))),latencyMs:Date.now()-i}}throw Wc("MODEL_DISCOVERY_UNSUPPORTED","No compatible model-list endpoint was found for this endpoint.",502,s)}(this.options.fetchImpl,this.resolvePrivateInput(t))}test(e){const t=Sc.parse(e);return async function(e,t){const n=Date.now(),i="codex"===t.app?await Uc(e,$c(t.endpoint,"responses"),{method:"POST",headers:{accept:"application/json",authorization:`Bearer ${t.key}`,"content-type":"application/json"},body:JSON.stringify({model:t.model,input:"Reply with OK.",max_output_tokens:32,stream:!1})}):await Uc(e,function(e){const t=Bc(e),n=t.pathname.split("/").filter(Boolean).at(-1)||"";return $c(t.toString(),/^v\d+$/.test(n)?"messages":"v1/messages")}(t.endpoint),{method:"POST",headers:{accept:"application/json","anthropic-version":"2023-06-01","content-type":"application/json","x-api-key":t.key},body:JSON.stringify({model:t.model,max_tokens:8,messages:[{role:"user",content:"Reply with OK."}]})});if(!i.ok)throw Hc("MODEL_TEST_FAILED",i.status);if((await Fc(i,"MODEL_TEST_RESPONSE_INVALID")).error)throw Wc("MODEL_TEST_RESPONSE_INVALID","The model endpoint returned an error payload.",502);return{success:!0,latencyMs:Date.now()-n}}(this.options.fetchImpl,this.resolvePrivateInput(t))}discoverOnNode(e,t){const n=this.options.requireNode(e);return Jc(n),this.options.gateway.discoverModels(n,t)}testOnNode(e,t){const n=this.options.requireNode(e);return Jc(n),this.options.gateway.testModel(n,t)}require(e,t=!1){const n=this.requireSecret(e);return t?n:Fd(n)}async prepareAssignment(e,t){const n=await this.options.gateway.listModels(e),i={...null===t.codexModelHash?{codexModelHash:null}:t.codexModelHash?.trim()?{codexModelHash:t.codexModelHash.trim()}:{},...null===t.claudeModelHash?{claudeModelHash:null}:t.claudeModelHash?.trim()?{claudeModelHash:t.claudeModelHash.trim()}:{}},s=async(t,i)=>{if(null===i)return;const s=i?this.listAll().find(e=>e.id===i):this.listAll().find(e=>e.enabled&&e.app===t);if(s)return Yc(s,t),await this.options.gateway.deployModel(e,s.id,s),s.id;if(!i)return;const r=n.find(e=>e.id===i);return r||Kd("MODEL_NOT_FOUND",`Model ${i} was not found on control-plane or node ${e.id}.`),Yc(r,t),r.id};return{modelSelection:i,codexModelHash:await s("codex",i.codexModelHash),claudeModelHash:await s("claude",i.claudeModelHash)}}async ensureInstanceAssignment(e){const t=this.options.requireNode(e.nodeId),n=await this.prepareAssignment(t,e.modelSelection);return this.options.gateway.assignInstanceModels(t,e.id,n)}listAll(){return this.options.models.list().map(e=>this.normalize(e)).sort((e,t)=>e.order-t.order||e.createdAt.localeCompare(t.createdAt)||e.id.localeCompare(t.id))}requireSecret(e){const t=this.options.models.get(e);return t||Kd("MODEL_NOT_FOUND",`Model ${e} was not found.`),this.normalize(t)}normalize(e){const t=function(e){if(e&&"object"==typeof e&&!Array.isArray(e)){const t={...e};if(!("app"in t)){const e=Array.isArray(t.apps)?t.apps:[];t.app=e.includes("claude")&&!e.includes("codex")?"claude":"codex"}return delete t.apps,Ds.parse(t)}return Ds.parse(e)}(e);return t!==e&&this.options.models.put(t),t}nextOrder(){return this.options.models.list().reduce((e,t)=>Math.max(e,t.order),0)+100}resolvePrivateInput(e){const t=e.key?.trim()||(e.existingModelId?this.requireSecret(e.existingModelId).key:"");if(!t)throw Object.assign(new Error("An API key is required to contact the model endpoint."),{statusCode:400,code:"MODEL_API_KEY_REQUIRED"});return{...e,key:t}}}function Jc(e){const t=e.capabilities.agent,n=t&&"object"==typeof t&&!Array.isArray(t)?t.capabilities:void 0;if(!n||"object"!=typeof n||Array.isArray(n)||!0!==n.modelEndpointProbe)throw Object.assign(new Error("This node agent does not support model endpoint discovery or testing."),{statusCode:409,code:"NODE_MODEL_ENDPOINT_PROBE_UNSUPPORTED"})}function Yc(e,t){if(e.app!==t)throw Object.assign(new Error(`Model ${e.id} is not a ${t} model.`),{statusCode:400,code:"MODEL_APP_MISMATCH"});if(!e.enabled)throw Object.assign(new Error(`Model ${e.id} is disabled.`),{statusCode:400,code:"MODEL_DISABLED"})}class Qc{requireNode;nodeAgentTransport;constructor(e){this.requireNode=e.requireNode,this.nodeAgentTransport=e.nodeAgentTransport}async request(e,t,n={}){if(!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_UNREACHABLE"}),t}Xc(e);const i=this.requireNode(e.nodeId),s=await this.nodeAgentTransport(i).request(i,`/instances/${encodeURIComponent(e.id)}/proxy`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({path:`/api/${t.replace(/^\/+/,"")}`,method:n.method||"GET",headers:Wd(n.headers),body:(r=n.body,"string"==typeof r?r:null==r?void 0:String(r))})});var r;const o=await s.json().catch(()=>({}));if(!s.ok){const n=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n="string"==typeof t.code&&t.code.trim()?t.code:void 0,i="string"==typeof t.message&&t.message?t.message:void 0,s=t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?t.details:void 0;return n||i?{code:n,message:i,details:s}:void 0}(o.error),i=n?.message||function(e){if(!e||"object"!=typeof e||Array.isArray(e))return"";const t=e.message;return"string"==typeof t?t:""}(o.error)||`Instance request failed with HTTP ${s.status}`,r=new Error(i);throw Object.assign(r,{statusCode:s.status,code:n?.code||"INSTANCE_REQUEST_FAILED",...n?.details?{details:n.details}:{},instanceId:e.id,nodeId:e.nodeId,route:t}),r}return o.data??o}async proxyHttp(e,t,n={}){if("online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_UNREACHABLE"}),t}if(!e.target.web){const t=new Error(`Instance ${e.name} web endpoint is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_WEB_UNREACHABLE"}),t}Xc(e);const i=this.requireNode(e.nodeId),s=await this.nodeAgentTransport(i).requestStream(i,`/instances/${encodeURIComponent(e.id)}/proxy/stream`,{method:"POST",headers:{"content-type":"application/json"},signal:n.signal,body:JSON.stringify({path:t,method:n.method||"GET",headers:Wd(n.headers),...(r=n.body,null==r?{}:"string"==typeof r?{body:r}:Buffer.isBuffer(r)?{bodyBase64:r.toString("base64")}:r instanceof Uint8Array?{bodyBase64:Buffer.from(r).toString("base64")}:{body:String(r)})})});var r;return{status:s.status||502,headers:Object.fromEntries(s.headers.entries()),body:s.body}}proxyWebSocket(e,t,n,i,s={}){if(!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} web endpoint is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_WEB_UNREACHABLE"}),t}Xc(e);const r=this.requireNode(e.nodeId),o=n.startsWith("/")?n.slice(1):n;this.nodeAgentTransport(r).proxyWebSocket(r,t,`/instances/${encodeURIComponent(e.id)}/proxy/ws/${o}`,i,s)}async reportHeartbeat(e,t){if(!e.registrationToken)return;const n=this.requireNode(e.nodeId),i=`/instances/${encodeURIComponent(e.id)}/heartbeat`,s={method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.registrationToken}`},body:JSON.stringify(t)},r=await this.nodeAgentTransport(n).request(n,i,s),o=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(o.error?.message||`Instance heartbeat sync failed with HTTP ${r.status}`);throw Object.assign(e,{statusCode:r.status,code:"INSTANCE_HEARTBEAT_SYNC_FAILED"}),e}}}function Xc(e){if(Kr(e))return;const t=new Error(`Instance ${e.name} is not ready.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_NOT_READY",runtimePhase:e.runtimeVersion?.phase}),t}class Zc{read(e){const t=new Map(e.projects.map(e=>[e.id,e])),n=new Map(e.images.map(e=>[e.id,e])),i=new Map(e.nodes.map(e=>[e.id,e])),s=new Map(e.runtimes.map(e=>[`${e.nodeId}:${e.id}`,e])),r=Date.now();return{items:e.instances.map(e=>function(e){const t=e.instance.lastHeartbeatAt?e.currentTime-Date.parse(e.instance.lastHeartbeatAt):void 0,n=void 0!==t&&t>3e4?"offline":e.instance.connectionStatus,i=Ud(e.instance);return{...i,aiSessions:nt(i.aiSessions),connectionStatus:n,heartbeatAgeMs:t,project:e.project,image:e.image,node:e.node?$d(e.node):void 0,runtime:e.runtime,protocolCompatible:!e.instance.protocolVersion||e.instance.protocolVersion===ui}}({instance:e,currentTime:r,project:e.projectId?t.get(e.projectId):void 0,image:e.imageSnapshot||(e.imageSelection?n.get(e.imageSelection.imageId):void 0),node:i.get(e.nodeId),runtime:s.get(`${e.nodeId}:${e.runtimeId}`)})),nodeErrors:e.nodeErrors||[]}}}class el{options;constructor(e){this.options=e}async create(e){const t=fc.parse(e),n=t.projectId?this.options.requireProject(t.projectId):void 0,i=t.runtimeId||n?.defaultRuntimeId||"runtime_local_docker",s=t.nodeId||n?.defaultNodeId||this.options.defaultNodeId();if(!s)throw nl("At least one node connection is required before creating an instance.",400,"NODE_REQUIRED");const r=this.options.requireNode(s),o=await this.options.requireRuntime(r.id,i),a=o.capabilities.requiresImage??"local"!==o.type,d=t.environmentSource||(t.imageSelection?{type:"image",imageSelection:t.imageSelection}:void 0)||(a&&n?.defaultImageSelection?{type:"image",imageSelection:n.defaultImageSelection}:void 0);if("template"===d?.type&&"docker"!==o.type)throw nl(`Runtime ${o.name} does not support environment templates.`,409,"ENVIRONMENT_TEMPLATE_RUNTIME_UNSUPPORTED");const c="image"===d?.type?d.imageSelection:void 0,l=c?this.options.resolveImageSelection(c):void 0,p="template"===d?.type?await this.options.gateway.getEnvironmentTemplate(r,d.environmentTemplateId):void 0;if(p&&"ready"!==p.status)throw nl(`Environment template ${p.id} is ${p.status}.`,409,"ENVIRONMENT_TEMPLATE_NOT_READY");if(p&&p.nodeId!==r.id)throw nl(`Environment template ${p.id} belongs to node ${p.nodeId}.`,409,"ENVIRONMENT_TEMPLATE_NODE_MISMATCH");if(a&&!l&&!p)throw nl(`Runtime ${o.name} requires an image.`,400,"RUNTIME_IMAGE_REQUIRED");const u=await this.resolveSource({node:r,runtime:o,project:n,source:t.source,sourceSnapshot:t.sourceSnapshot,imageOption:l}),m=await this.options.prepareModels(r,t.modelSelection||{}),g=l?function(e){const t=Hd();return{id:e.id,origin:e.origin,name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover,repository:e.repository,tag:e.tag,requestedReference:e.reference,resolvedDigest:e.digest,resolvedReference:e.digest?`${e.repository}@${e.digest}`:void 0,downloadSizeBytes:e.downloadSizeBytes,pullPolicy:"if-not-present",capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,market:e.market,createdAt:t,updatedAt:t}}(l):void 0,h=await this.options.gateway.createInstance(r,{id:t.id,name:t.name,runtimeId:i,...d?{environmentSource:d}:{},...l&&g?{image:g}:{},projectId:n?.id,source:u.value,sourceSnapshot:u.snapshot,config:t.config,modelSelection:{}});let y=h;try{y=(await this.options.gateway.assignInstanceModels(r,h.id,m)).instance}catch(e){throw await this.options.gateway.deleteInstance(r,h.id,{deleteVolumes:!0}).catch(()=>{}),e}let f={status:"not-requested"};if(t.start)try{y=await this.options.gateway.startInstance(r,y.id),f={status:"started"}}catch(e){f={status:"failed",error:tl(e,"INSTANCE_START_FAILED")},y=await this.options.gateway.listInstances(r).then(e=>e.find(e=>e.id===y.id)||y).catch(()=>y)}return{...Ud(y),registrationToken:y.registrationToken,startOutcome:f}}async resolveSource(e){let t=e.source||e.project?.source,n=e.sourceSnapshot||(e.project?e.project:{});if(!t)throw nl("Instance source is required.",400,"INSTANCE_SOURCE_REQUIRED");if("local"===e.runtime.type&&"local-folder"!==t.type)throw nl("Localhost runtime currently supports local folder sources only.",400,"LOCAL_RUNTIME_REQUIRES_LOCAL_FOLDER");if("local-folder"!==t.type)return{value:t,snapshot:n};if(t.ownerNodeId&&t.ownerNodeId!==e.node.id)throw nl(`Local folder ${t.path} belongs to node ${t.ownerNodeId}, not ${e.node.id}.`,400,"LOCAL_FOLDER_REQUIRES_OWNER_NODE");const i=t.localFolderId?await this.options.requireLocalFolder(e.node,t.localFolderId):await this.options.gateway.createLocalFolder(e.node,{name:"string"==typeof n.name?n.name:"Local folder",path:t.path,defaultImageSelection:e.imageOption?{imageId:e.imageOption.id,tag:e.imageOption.tag}:void 0});return t={...t,localFolderId:i.id,ownerNodeId:i.nodeId,path:i.path},n=i,{value:t,snapshot:n}}}function tl(e,t){const n=e&&"object"==typeof e?e:{};return{code:"string"==typeof n.code&&n.code.trim()?n.code:t,message:"string"==typeof n.message&&n.message.trim()?n.message:String(e)}}function nl(e,t,n){return Object.assign(new Error(e),{statusCode:t,code:n})}class il{triggers;listInstances;requireInstance;instanceRequest;constructor(e){this.triggers=e.triggers,this.listInstances=e.listInstances,this.requireInstance=e.requireInstance,this.instanceRequest=e.instanceRequest}async listTriggers(){const e=await this.listInstances(),t=new Map;for(const e of this.triggers.list())t.set(e.configHash,{configHash:e.configHash,config:sl(e),deploymentCount:0,enabledCount:0,runningCount:0,errorCount:0,ownedByControlPlane:!0,controlPlaneDeploymentCount:0,deployments:[],recentRuns:[]});for(const n of e){const e=n.triggers;for(const i of e?.configs||[]){const s=t.get(i.configHash)||{configHash:i.configHash,config:i.config,deploymentCount:0,enabledCount:0,runningCount:0,errorCount:0,ownedByControlPlane:!1,controlPlaneDeploymentCount:0,deployments:[],recentRuns:[]},r=(i.deployments||[]).map(e=>({instanceId:n.id,instanceName:n.name,deployment:e,runtime:(i.runtime||[]).find(t=>t.deploymentId?t.deploymentId===e.deploymentId:t.configHash===e.configHash)}));s.deploymentCount+=r.length,s.enabledCount+=r.filter(e=>Boolean(e.deployment.enabled)).length,s.controlPlaneDeploymentCount+=r.filter(e=>"control-plane"===e.deployment.origin).length,s.runningCount+=(i.runtime||[]).filter(e=>"running"===e.status).length,s.errorCount+=(i.runtime||[]).filter(e=>"error"===e.status).length,s.deployments.push(...r),s.recentRuns.push(...(e.recentRuns||[]).filter(e=>e.configHash===i.configHash).map(e=>({...e,instanceId:n.id,instanceName:n.name}))),t.set(i.configHash,s)}}return zn.parse({updatedAt:(new Date).toISOString(),triggers:[...t.values()].sort((e,t)=>String(e.config.name||e.configHash).localeCompare(String(t.config.name||t.configHash)))})}createTrigger(e){const t=pc.parse(e||{}),n=Hd(),i={maxConcurrentRuns:t.policy?.maxConcurrentRuns??1,whenBusy:t.policy?.whenBusy??"skip",cooldownMs:t.policy?.cooldownMs},s=Tn({source:t.source,action:t.action,policy:i}),r=lc.parse({id:s,configHash:s,name:t.name,description:t.description,source:t.source,action:t.action,policy:i,createdAt:n,updatedAt:n});return this.triggers.put(r)}async updateTrigger(e,t){const n=this.requireTrigger(e),i=uc.parse(t||{}),s=Hd(),r={maxConcurrentRuns:i.policy?.maxConcurrentRuns??1,whenBusy:i.policy?.whenBusy??"skip",cooldownMs:i.policy?.cooldownMs},o=Tn({source:i.source,action:i.action,policy:r});if(o!==e&&this.triggers.get(o)){const e=new Error(`Trigger ${o} already exists.`);throw Object.assign(e,{statusCode:409,code:"TRIGGER_ALREADY_EXISTS"}),e}const a=lc.parse({id:o,configHash:o,name:i.name,description:i.description,source:i.source,action:i.action,policy:r,createdAt:n.createdAt,updatedAt:s}),d=await this.listInstances(),c=[];for(const t of d){const n=t.triggers?.configs?.find(t=>t.configHash===e),i=(n?.deployments||[]).filter(e=>"control-plane"===e.origin);if(o!==e)for(const n of i){const i="ai-session"===n.target.type?rl(n.target.aiSessionId,o):n.deploymentId,s=await this.instanceRequest(t,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:a.name,description:a.description,source:a.source,action:a.action,policy:a.policy,deployment:{deploymentId:i,origin:"control-plane",enabled:n.enabled,target:n.target,localName:n.localName}})}),r=n.deploymentId||n.configHash;await this.instanceRequest(t,`/triggers/${encodeURIComponent(e)}/deployments/${encodeURIComponent(r)}`,{method:"DELETE"}),c.push({instanceId:t.id,deploymentId:i,data:s})}else i.length&&c.push({instanceId:t.id,data:await this.instanceRequest(t,`/triggers/${encodeURIComponent(e)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({name:a.name,description:a.description??null})})})}return this.triggers.put(a),o!==e&&this.triggers.delete(e),{previousConfigHash:e,trigger:a,results:c}}async deleteTrigger(e){const t=this.triggers.delete(e),n=await this.listInstances(),i=[];for(const t of n){const n=t.triggers?.configs?.find(t=>t.configHash===e);if(!n)continue;const s=(n.deployments||[]).filter(e=>"control-plane"===e.origin);if(!s.length)continue;const r=n.deployments.every(e=>"control-plane"===e.origin);for(const n of s)try{const s=n.deploymentId?`/triggers/${encodeURIComponent(e)}/deployments/${encodeURIComponent(n.deploymentId)}`:r?`/triggers/${encodeURIComponent(e)}`:void 0;if(!s){i.push({instanceId:t.id,configHash:e,deploymentId:n.deploymentId,deleted:!1,skipped:"missing-deployment-id"});continue}const o=await this.instanceRequest(t,s,{method:"DELETE"});if(i.push({instanceId:t.id,configHash:e,deploymentId:n.deploymentId,deleted:!0,data:o}),!n.deploymentId)break}catch(s){i.push({instanceId:t.id,configHash:e,deploymentId:n.deploymentId,deleted:!1,error:s instanceof Error?s.message:String(s)})}}return t||i.length||Kd("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),{configHash:e,deletedTemplate:t,results:i}}async applyTrigger(e,t){const n=this.requireTrigger(e),i=mc.parse(t||{}),s=[];for(const e of i.instanceIds){const t=await this.requireInstance(e);s.push({instanceId:e,data:await this.instanceRequest(t,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:n.name,description:n.description,source:n.source,action:n.action,policy:n.policy,deployment:{origin:"control-plane",enabled:i.enabled??!0,target:i.target}})})})}return{configHash:e,results:s}}async listInstanceTriggers(e){const t=await this.requireInstance(e);return this.instanceRequest(t,"/triggers")}async bindAiSessionTrigger(e,t,n){const i=gc.parse(n||{}),s=this.requireTrigger(i.configHash),r=await this.requireInstance(e);return this.instanceRequest(r,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:s.name,description:s.description,source:s.source,action:s.action,policy:s.policy,deployment:{deploymentId:rl(t,i.configHash),origin:"control-plane",enabled:i.enabled??!0,target:{type:"ai-session",aiSessionId:t}}})})}async unbindAiSessionTrigger(e,t,n){const i=await this.requireInstance(e),s=rl(t,n);return this.instanceRequest(i,`/triggers/${encodeURIComponent(n)}/deployments/${encodeURIComponent(s)}`,{method:"DELETE"})}async runInstanceTrigger(e,t,n={}){const i=await this.requireInstance(e);return this.instanceRequest(i,`/triggers/${encodeURIComponent(t)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n||{})})}requireTrigger(e){const t=this.triggers.get(e);return t||Kd("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),t}}function sl(e){return{configHash:e.configHash,name:e.name,...void 0!==e.description?{description:e.description}:{},source:e.source,action:e.action,policy:e.policy,createdAt:e.createdAt,updatedAt:e.updatedAt}}function rl(e,t){return`ai_${Buffer.from(e).toString("base64url")}_${t}`}class ol{options;constructor(e){this.options=e}getSettings(){return sc.parse(this.options.settings.get())}updateSettings(e){const t=rc.parse(e),n=sc.parse({...this.getSettings(),...t,..."publicBaseUrl"in t?{publicBaseUrl:t.publicBaseUrl?.trim()||void 0}:{}});return this.options.settings.put(n)}seedDefaults(){}listProjects(){return this.options.projects.list().map(e=>this.normalizeProjectRecord(e))}getProject(e){const t=this.options.projects.get(e);return t?this.normalizeProjectRecord(t):void 0}createProject(e){const t=Xd.parse(e),n=Hd(),i=_s.parse(t.source);return this.options.projects.put(js.parse({...t,id:t.id||ho("proj"),source:i,defaultImageSelection:t.defaultImageSelection||{imageId:"market_taskhandoff_browser"},defaultNodeId:t.defaultNodeId||this.options.defaultNodeId(),defaultRuntimeId:t.defaultRuntimeId||"runtime_local_docker",workspacePolicy:Rs.parse(t.workspacePolicy||Bd(i)),labels:t.labels||{},createdAt:n,updatedAt:n}))}updateProject(e,t){const n=Zd.parse(t),i=this.requireProject(e),s=n.source?_s.parse(n.source):i.source;return this.options.projects.put(js.parse({...i,...n,id:e,source:s,workspacePolicy:n.workspacePolicy?Rs.parse(n.workspacePolicy):i.workspacePolicy,createdAt:i.createdAt,updatedAt:Hd()}))}deleteProject(e){return this.options.projects.delete(e)}requireProject(e){const t=this.getProject(e);return t||Kd("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}listImages(){return this.options.images.list()}getMarketCatalog(){return{catalog:this.options.market.getCatalog(),status:this.options.market.getStatus()}}listImageOptions(e){return[...this.options.market.getCatalog().items.map(t=>this.marketImageOption(t,void 0,e,!0)),...this.listImages().map(e=>this.customImageOption(e))]}resolveImageSelection(e,t){const n=this.options.market.getCatalog().items.find(t=>t.id===e.imageId);if(n)return this.marketImageOption(n,e.tag,t);const i=this.options.images.get(e.imageId);if(i||Kd("IMAGE_NOT_FOUND",`Image ${e.imageId} was not found.`),e.tag&&e.tag!==i.tag)throw Object.assign(new Error(`Custom image ${i.id} cannot override its stored tag.`),{statusCode:400,code:"CUSTOM_IMAGE_TAG_OVERRIDE"});return this.customImageOption(i)}createImage(e){const t=oc.parse(e),n=Hd(),i=_i(t.reference);return this.options.images.put(ir.parse({...t,id:t.id||ho("img"),origin:"custom",reference:i.reference,repository:i.repository,tag:i.tag,pullPolicy:t.pullPolicy||"if-not-present",capabilities:t.capabilities||[],optionalApps:t.optionalApps||[],defaultEnv:t.defaultEnv||{},labels:t.labels||{},createdAt:n,updatedAt:n}))}updateImage(e,t){const n=ac.parse(t),i=this.requireImage(e),s=_i(n.reference||i.reference);return this.options.images.put(ir.parse({...i,...n,id:e,origin:"custom",reference:s.reference,repository:s.repository,tag:s.tag,createdAt:i.createdAt,updatedAt:Hd()}))}deleteImage(e){return this.options.images.delete(e)}requireImage(e){if(this.options.market.getCatalog().items.some(t=>t.id===e))throw Object.assign(new Error(`Market image ${e} is read-only.`),{statusCode:403,code:"MARKET_IMAGE_READ_ONLY"});const t=this.options.images.get(e);return t||Kd("IMAGE_NOT_FOUND",`Image ${e} was not found.`),t}normalizeProjectRecord(e){const t=function(e){if(e&&"object"==typeof e&&!Array.isArray(e)){const t={...Ji(e)};return"defaultRuntimeId"in t||(t.defaultRuntimeId="runtime_local_docker"),js.parse(t)}return js.parse(e)}(e);return t!==e&&this.options.projects.put(t),t}customImageOption(e){return rr.parse({id:e.id,origin:"custom",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||Ks,repository:e.repository,tag:e.tag,availableTags:e.tag?[{name:e.tag,reference:e.reference,status:"active"}]:[],reference:e.reference,capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,readOnly:!1})}marketImageOption(e,t,n,i=!1){if("yanked"===e.status&&!i)throw Object.assign(new Error(`Market image ${e.id} is no longer selectable.`),{statusCode:409,code:"MARKET_IMAGE_YANKED"});const s=t||e.defaultTag,r=e.tags.find(e=>e.name===s);if(!r)throw Object.assign(new Error(`Market image ${e.id} does not provide tag ${s}.`),{statusCode:400,code:"MARKET_IMAGE_TAG_NOT_FOUND"});if("yanked"===r.status&&!i)throw Object.assign(new Error(`Market image tag ${e.id}:${s} is no longer selectable.`),{statusCode:409,code:"MARKET_IMAGE_TAG_YANKED"});const o=r.platforms.find(e=>!(n?.os&&e.os!==n.os||n?.architecture&&e.architecture!==n.architecture)),a=this.options.market.getCatalog();return rr.parse({id:e.id,origin:"market",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||Ks,repository:e.repository,tag:r.name,availableTags:e.tags.map(e=>({name:e.name,version:e.version,reference:e.reference,manifestDigest:e.manifestDigest,status:e.status})),reference:r.reference,digest:o?.digest||r.manifestDigest,downloadSizeBytes:o?.downloadSizeBytes,unpackedSizeBytes:o?.unpackedSizeBytes,capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,readOnly:!0,lifecycleStatus:"yanked"===r.status||"yanked"===e.status?"yanked":"deprecated"===r.status||"deprecated"===e.status?"deprecated":"active",market:{catalogId:a.catalogId,catalogRevision:a.revision,publisher:e.publisher,version:r.version}})}}function al(e){const t=_i(e.reference),n=t.tag||"latest";return{id:e.id,publisher:"task-handoff",slug:e.slug,name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:Ks,repository:t.repository,defaultTag:n,tags:[{name:n,reference:t.reference,platforms:[],status:"active"}],capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:{},labels:{"task-handoff.image.kind":"controlled-instance","task-handoff.image.profile":e.slug},status:"active"}}function dl(){const e=(t=process.env.TASK_HANDOFF_BUILT_AT)&&!Number.isNaN(Date.parse(t))?new Date(t).toISOString():(new Date).toISOString();var t;return tr.parse({protocolVersion:"2026-07-29",catalogId:"task_handoff_embedded",revision:process.env.TASK_HANDOFF_VERSION||"0.0.1",source:"embedded",generatedAt:e,items:[al({id:"market_taskhandoff_codex",slug:"codex",name:"TaskHandoff Codex",description:"Minimal Codex runtime with terminal and Codex.",localizedDescriptions:{"zh-CN":"最小 Codex 运行环境,包含终端和 Codex。"},reference:process.env.TASK_HANDOFF_CONTROLLED_CODEX_IMAGE||"huadream/task-handoff-controlled-codex:latest",capabilities:["terminal","codex"],optionalApps:["terminal-tty"]}),al({id:"market_taskhandoff_ai",slug:"ai",name:"TaskHandoff Codex + Claude",description:"AI development runtime with Codex, Claude, and terminal.",localizedDescriptions:{"zh-CN":"AI 开发运行环境,包含 Codex、Claude 和终端。"},reference:process.env.TASK_HANDOFF_CONTROLLED_AI_IMAGE||"huadream/task-handoff-controlled-ai:latest",capabilities:["terminal","codex","claude"],optionalApps:["terminal-tty"]}),al({id:"market_taskhandoff_webcap",slug:"webcap",name:"TaskHandoff WebCap",description:"Browser automation runtime with WebCap, Codex, Claude, Chromium, and VNC.",localizedDescriptions:{"zh-CN":"浏览器自动化运行环境,包含 WebCap、Codex、Claude、Chromium 和 VNC。"},reference:process.env.TASK_HANDOFF_CONTROLLED_WEB_CAP_IMAGE||"huadream/task-handoff-controlled-webcap:latest",capabilities:["browser","terminal","gui-terminal","web-cap","codex","claude"],optionalApps:["chromium","terminal-tty","gui-terminal"]}),al({id:"market_taskhandoff_browser",slug:"browser",name:"TaskHandoff Browser",description:"Full runtime with Codex, Claude, Chromium, VNC, and code-server.",localizedDescriptions:{"zh-CN":"完整运行环境,包含 Codex、Claude、Chromium、VNC 和 code-server。"},reference:process.env.TASK_HANDOFF_CONTROLLED_BROWSER_IMAGE||"huadream/task-handoff-controlled-browser:latest",capabilities:["browser","terminal","gui-terminal","vscode-web","codex","claude"],optionalApps:["chromium","terminal-tty","gui-terminal","vscode-web"]})]})}class cl{async loadCatalog(){return dl()}}class ll{snapshot;status;constructor(e=dl()){this.snapshot=tr.parse(e),this.status=nr.parse({source:this.snapshot.source,state:"ready",revision:this.snapshot.revision,updatedAt:this.snapshot.generatedAt})}getCatalog(){return this.snapshot}getStatus(){return this.status}acceptCandidate(e){const t=tr.safeParse(e);return t.success?(this.snapshot=t.data,this.status=nr.parse({source:t.data.source,state:"ready",revision:t.data.revision,updatedAt:(new Date).toISOString()}),{accepted:!0,snapshot:t.data}):(this.status=nr.parse({...this.status,state:"failed",updatedAt:(new Date).toISOString(),error:t.error.message}),{accepted:!1,error:t.error})}recordRefreshFailure(e){return this.status=nr.parse({...this.status,state:this.snapshot?"stale":"failed",updatedAt:(new Date).toISOString(),error:e instanceof Error?e.message:String(e)}),this.snapshot}async refresh(e){try{const t=await e.loadCatalog();return this.acceptCandidate(t)}catch(e){return this.recordRefreshFailure(e),{accepted:!1,error:e}}}}class pl{records=new Map;options;constructor(e){this.options=e}create(e){const t=i.randomBytes(this.options.tokenBytes).toString("base64url"),n={...e,token:t,expiresAt:new Date(Date.now()+(e.ttlMs||this.options.ttlMs)).toISOString()};return this.records.set(t,n),n}resolve(e,t){const n=this.records.get(e);if(!n)throw this.invalidError();if(n.expiresAt<=(new Date).toISOString())throw this.records.delete(e),this.invalidError();if(t&&!t(n))throw this.invalidError();return n}revoke(e,t){const n=this.resolve(e,t);return this.records.delete(e),n}invalidError(){const e=new Error(this.options.invalidMessage);return Object.assign(e,{statusCode:this.options.invalidStatusCode||400,code:this.options.invalidCode}),e}}class ul{requireInstance;listAppSessions;tokens=new pl({invalidMessage:"App access link is invalid or expired.",invalidCode:"APP_ACCESS_TOKEN_INVALID",invalidStatusCode:401,tokenBytes:24,ttlMs:9e5});constructor(e){this.requireInstance=e.requireInstance,this.listAppSessions=e.listAppSessions}createToken(e){return this.tokens.create({instanceId:e.instanceId,sessionId:e.sessionId,mode:e.mode,ttlMs:e.ttlMs})}async createSessionToken(e){await this.requireInstance(e.instanceId);const t=await this.requireSession(e.instanceId,e.sessionId),n=Dt(t);if("vnc"!==n){const e=new Error("This app session does not expose a VNC view.");throw Object.assign(e,{statusCode:409,code:"APP_SESSION_ACCESS_UNAVAILABLE"}),e}if("running"!==t.status){const e=new Error("The app session is not running.");throw Object.assign(e,{statusCode:409,code:"APP_SESSION_NOT_RUNNING"}),e}return this.createToken({...e,mode:n})}resolveToken(e,t){return this.tokens.resolve(e,e=>!t||e.mode===t)}revokeToken(e,t){this.tokens.revoke(e,e=>e.instanceId===t.instanceId&&e.sessionId===t.sessionId)}async proxyTarget(e,t,n=""){const i=this.resolveToken(e,t),s=await this.requireInstance(i.instanceId),r=await this.requireSession(i.instanceId,i.sessionId);return{access:i,instance:s,session:r,path:ml(t,i.sessionId,r,n)}}async requireSession(e,t){const n=await this.listAppSessions(),i=n.instances.find(t=>t.instanceId===e)?.appSessions.sessions.find(e=>hl(e.id)===t);if(i)return i;const s=new Error("App session was not found.");throw Object.assign(s,{statusCode:404,code:"APP_SESSION_NOT_FOUND"}),s}}function ml(e,t,n,i=""){return"tty"===e?`/api/apps/sessions/${encodeURIComponent(t)}/tty`:"vnc"===e?i?function(e,t){const n=`/${t.replace(/^\/+/,"")}`,i=n.split("?",1)[0]||"/",s=encodeURIComponent(e);if(!["/api/novnc/",`/api/apps/sessions/${s}/web/`,`/api/apps/sessions/${s}/vnc`,`/api/apps/sessions/${s}/novnc/`].some(e=>i===e.replace(/\/$/,"")||i.startsWith(e))){const e=new Error("App access token cannot be used for this path.");throw Object.assign(e,{statusCode:403,code:"APP_ACCESS_PATH_FORBIDDEN"}),e}return n}(t,i):hl(gl(n.vnc).noVncPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`:hl(gl(n.web).webPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`}function gl(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function hl(e){return"string"==typeof e&&e.trim()?e.trim():void 0}const yl={allow:"a",deny:"d",skip:"s"};function fl(e){return i.createHash("sha256").update(e).digest("base64url").slice(0,Math.ceil(16))}class Il{tokens=new pl({invalidMessage:"Chat action expired.",invalidCode:"CHAT_ACTION_TOKEN_INVALID",tokenBytes:9,ttlMs:6e5});create(e){return this.tokens.create({type:e.type,instanceId:"instanceId"in e?e.instanceId:void 0,appId:"appId"in e?e.appId:void 0,routeId:"routeId"in e?e.routeId:void 0,decision:"decision"in e?e.decision:void 0,ttlMs:e.ttlMs})}resolve(e,t){return this.tokens.resolve(e,e=>!t||e.type===t)}pendingDecisionCallbackData(e,t){return`task_handoff:cp_p:v1:${yl[t]}:${fl(e)}`}}function bl(e){const{token:t,...n}=e;return{...n,settings:wl(e.settings),tokenSet:Boolean(e.token)}}function vl(e,t){if(!t)return e;const n={...e};for(const[e,i]of Object.entries(t))void 0!==i&&""!==i&&(n[e]=i);return n}function wl(e){const t={...e};return"string"==typeof t.clientSecret&&t.clientSecret&&(delete t.clientSecret,t.clientSecretSet=!0),"string"==typeof t.appSecret&&t.appSecret&&(delete t.appSecret,t.appSecretSet=!0),t}class Sl{chatBridges;chatSessions;constructor(e){this.chatBridges=e.chatBridges,this.chatSessions=e.chatSessions}list(){return this.chatBridges.list().map(bl)}require(e){const t=this.chatBridges.get(e);return t||Kd("CHAT_BRIDGE_NOT_FOUND",`Chat bridge ${e} was not found.`),t}create(e){const t=cc.parse(e),n=Hd(),i=Hr.parse({...t,id:ho(`chat_${t.channel}`),name:t.name||(s=t.channel,r=this.chatBridges.list().filter(e=>e.channel===t.channel).length+1,`${"telegram"===s?"Telegram":"wechat"===s?"WeChat":"dingding"===s?"DingDing":"lark"===s?"Lark":"Web"} ${r}`),enabled:t.enabled??!1,allowedUserIds:t.allowedUserIds||[],pollIntervalMs:t.pollIntervalMs||3e3,settings:vl({},t.settings),createdAt:n,updatedAt:n});var s,r;return this.chatBridges.put(i),bl(i)}update(e,t){const n=dc.parse(t),i=this.require(e),s=vl(i.settings,n.settings),r=Hr.parse({...i,...n,id:e,channel:i.channel,name:n.name||i.name,settings:s,updatedAt:Hd()});return this.chatBridges.put(r),bl(r)}delete(e){const t=this.chatBridges.delete(e);if(t)for(const t of this.chatSessions.list())t.bridgeId===e&&this.chatSessions.delete(t.id);return t}}class Al{chatSessions;constructor(e){this.chatSessions=e.chatSessions}list(){return this.chatSessions.list()}require(e){const t=this.chatSessions.get(e);return t||Kd("CHAT_SESSION_NOT_FOUND",`Chat session ${e} was not found.`),t}upsert(e){const t=Hd(),n=(i=e.channel,s=e.chatSessionId,`${e.bridgeId||i}:${s.replace(/[^a-zA-Z0-9_.:-]/g,"_")}`);var i,s;const r=this.chatSessions.get(n),o=Wr.parse({...r||{},...e,id:n,channel:e.channel,bridgeId:e.bridgeId,chatSessionId:e.chatSessionId,lastUsedAt:t,createdAt:r?.createdAt||t,updatedAt:t});return this.chatSessions.put(o),o}}function kl(e){return{inline_keyboard:e.map(e=>e.map(e=>({text:e.text,...e.url?{url:e.url}:{callback_data:e.callbackData||""}})))}}function zl(e,t=40){return kl(e.slice(0,t).map(e=>[e]))}function Tl(e){return Buffer.from(e,"utf8").toString("base64url")}function El(e){const t=xl(e).inline_keyboard,n=Array.isArray(t)?t:[],i=[];for(const e of n)if(Array.isArray(e))for(const t of e){const e=xl(t),n=String(e.callback_data||""),s=String(e.text||"").trim();s&&n&&i.push({text:s,id:`th_cb_${Tl(n)}`})}return i.slice(0,40)}function Cl(e,t){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function xl(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Nl(e){return(e.aiSessions?.sessions||[]).filter(t=>function(e,t){const n=(e.apps?.sessions||[]).filter(Dl);if(t.appSessionId&&n.some(e=>e.id===t.appSessionId))return!0;const i=new Set(t.appBindingKeys||[]);return Boolean(i.size&&n.some(e=>function(e){return[...Rt(e).bindings.map(Mt),...qt(e)].filter(Boolean)}(e).some(e=>i.has(e))))}(e,t))}function Ol(e){return"waiting"===e.status?4:"failed"===e.status?3:"running"===e.status?2:"idle"===e.status?1:0}function _l(e){return[e.cwd||"",e.agent||"",e.providerSessionId||e.id].join("\0")}function Rl(e){const t=e.session.title||e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=t?` - ${Cl(t,18)}`:"";return`${e.instance.name} - ${e.session.agent} ${e.session.status}${n}`}function Pl(e,t=(e,t)=>`task_handoff:approval:${e.id}:${t}`){return zl(e.flatMap(e=>"approval"!==e.kind?[]:[{text:Cl(`Allow ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"allow")},{text:Cl(`Skip ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"skip")},{text:Cl(`Deny ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"deny")}]))}function jl(e){const t=`${e.project?.name||e.projectId} / ${e.instance?.name||e.instanceId}`,n="approval"===e.kind?`/approve ${e.id} | /deny ${e.id} | /skip ${e.id}`:`/reply ${e.id} <message>`;return`[${t}] ${e.kind} ${e.id}: ${e.result}\n${n}`}function Dl(e){const t=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return jt("string"==typeof t.status?t.status:void 0)}class Ml{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleAiSessionsCommand(e){const t=await this.targets.aiSessionChoices(e),n=t.find(e=>e.active),i=t.map(e=>function(e){const t=e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=e.active?"* ":"",i=e.session.phase&&"unknown"!==e.session.phase?`/${e.session.phase}`:"";return`${n}${e.index+1}. ${e.projectName} / ${e.instance.name} - ${e.session.agent} - ${e.session.status}${i} - ${e.session.id}${t?` - ${t}`:""}`}(e));return{accepted:!0,routed:!1,binding:e,instances:t.map(e=>e.instance),reply:t.length?["Select AI session",`Current ${n?`${n.projectName} / ${n.instance.name} / ${n.session.id}`:await this.targets.renderChatTarget(e)}, total ${t.length}`,"",...i].join("\n"):"No AI sessions found.",replyMarkup:t.length?zl(t.map(e=>({text:`${e.active?"✓ ":""}${Rl(e)}`,callbackData:`task_handoff:cp_session:${e.index}`}))):void 0}}async handleAiSessionCommand(e,t){const n=String(t[0]||"").trim();if(!n)return this.handleAiSessionsCommand(e);const i=await this.targets.findAiSession(n);if(!i)return{accepted:!1,routed:!1,binding:e,reply:`AI session ${n} was not found. Try /sessions.`};const s=i.instance.projectId?this.deps.getProject(i.instance.projectId):void 0;return{accepted:!0,routed:!1,binding:this.deps.upsertChatSession({...e,activeProjectId:s?.id||e.activeProjectId,activeInstanceId:i.instance.id,activeAiSessionId:i.session.id}),instance:i.instance,aiSession:i.session,reply:`Active AI session: ${i.instance.name} / ${i.session.agent} ${i.session.id}`}}async handleAiSessionIndexAction(e,t){const n=(await this.targets.aiSessionChoices(e)).find(e=>e.index===t);if(!n)return{accepted:!1,routed:!1,binding:e,reply:"AI session was not found. Use /session to refresh the list.",replyMarkup:void 0};const i=this.deps.upsertChatSession({...e,activeProjectId:n.projectId||e.activeProjectId,activeInstanceId:n.instance.id,activeAiSessionId:n.session.id}),s=await this.handleAiSessionsCommand(i);return{...s,accepted:!0,binding:i,instance:n.instance,aiSession:n.session,message:`selected ${n.session.id}`,reply:[`Current chat is bound to AI session ${n.session.id}`,"",s.reply].join("\n")}}async handleAiSessionInterruptCommand(e){if(!e.activeInstanceId||!e.activeAiSessionId)return{accepted:!1,routed:!1,binding:e,reply:"No active AI session is selected. Use /sessions and /session <id> first."};const t=await this.deps.requireControlledInstance(e.activeInstanceId,!0),n=await this.deps.interruptAiSession(t.id,e.activeAiSessionId);return{accepted:!0,routed:!0,binding:e,instance:Ud(t),aiSession:n,reply:`Interrupt sent to ${t.name} / ${e.activeAiSessionId}.`}}}function Ll(e){return e.providerTurnId||e.turnId||""}function ql(e){return jt(Fl(e.status))}function $l(e,t){const n=Fl(t.appId)||"App",i=Fl(t.title).trim();if(i&&i!==n)return i;const s=function(e,t){for(const n of e.appInventory?.items||[])if(n.id===t)return n.name;return""}(e,n);return s||n}function Bl(e){const t=function(e){return"online"!==e.connectionStatus?[]:(e.appInventory?.items||[]).filter(e=>"available"===e.availability)}(e),n=new Map;for(const e of t){const t=Hl(e);t&&!n.has(t.id)&&n.set(t.id,t)}return[...n.values()]}function Ul(e,t,n,i){const s=Fl(t.id)&&function(e,t){const n=Dt(e);if(!n)return;return`/apps/access/${n}?token=${encodeURIComponent(t(n))}`}(t,i)||`/instances/${encodeURIComponent(e.id)}/`,r=function(e,t){const n=Fl(t);if(n&&new RegExp("^https?://","i").test(n))return new URL(e,n.endsWith("/")?n:n+"/").toString()}(s,n);return{text:r||s,url:r}}function Fl(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function Hl(e){if("string"==typeof e&&e.trim())return{id:e,label:Wl(e)};const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e),n=Fl(t.id).trim();return n?{id:n,label:Fl(t.name).trim()||Wl(n)}:void 0}function Wl(e){return{"terminal-tty":"Terminal","gui-terminal":"GUI Terminal",chromium:"Chromium",browser:"Browser","vscode-web":"VS Code"}[e]||e.replace(/[-_]+/g," ").replace(/\b\w/g,e=>e.toUpperCase())}class Gl{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleInstancesCommand(e){const t=await this.targets.instancesForBinding(e);return{accepted:!0,routed:!1,binding:e,instances:t,reply:(n=t.length,0===n?"No controlled instances are registered yet.":`Instances: ${n}. Tap an instance to create an app.`),replyMarkup:t.length?zl(t.map(e=>{return{text:Cl(e.name||e.id,56),callbackData:(t=this.deps.createChatActionToken({type:"instance-app-menu",instanceId:e.id}).token,`task_handoff:cp_i:${t}`)};var t})):void 0};var n}async handleInstanceAppMenuAction(e,t){const n=(await this.targets.instancesForBinding(e)).find(e=>e.id===t);if(!n)return{accepted:!1,routed:!1,binding:e,reply:"Instance not found."};const i=Bl(n);return{accepted:!0,routed:!1,binding:e,instance:n,message:`Select an app for ${n.name}.`,reply:i.length?`New app for ${n.name}`:`No launchable apps for ${n.name}.`,replyMarkup:i.length?zl(i.map(e=>{return{text:Cl(e.label,56),callbackData:(t=this.deps.createChatActionToken({type:"launch-app",instanceId:n.id,appId:e.id}).token,`task_handoff:cp_a:${t}`)};var t})):void 0}}async handleLaunchAppAction(e,t,n){const i=(await this.targets.instancesForBinding(e)).find(e=>e.id===t);if(!i)return{accepted:!1,routed:!1,binding:e,reply:"Instance not found."};const s=Bl(i).find(e=>e.id===n);return s?{accepted:!0,routed:!1,binding:e,instance:i,session:await this.deps.launchAppSession(i.id,s.id),message:`${s.label} launched`,reply:`Launched ${s.label} on ${i.name}.`}:{accepted:!1,routed:!1,binding:e,reply:`App ${n} is not launchable for ${i.name}.`}}async handleAppsCommand(e){const t=await this.deps.boardAsync(),n=new Map(t.map(e=>[e.id,e])),i=(await this.deps.listAppSessions()).instances.flatMap(e=>{const t=n.get(e.instanceId);return t?e.appSessions.sessions.filter(ql).filter(e=>Boolean(Fl(e.id))).map(e=>({instance:t,session:e,link:Ul(t,e,this.deps.controlPlanePublicBaseUrl(),n=>this.deps.createAppAccessToken({instanceId:t.id,sessionId:Fl(e.id)||"",mode:n}).token)})):[]}),s=i.filter(e=>e.link.url).map(e=>({text:Cl(`${e.instance.name} · ${$l(e.instance,e.session)}`,56),url:e.link.url}));return{accepted:!0,routed:!1,binding:e,instances:t,reply:(r=i.length,o=s.length,0===r?"No app sessions found.":0===o?`App sessions: ${r}. Set the control plane public URL in Settings > Appearance to open them from chat.`:`App sessions: ${r}. Tap a button to open.`),replyMarkup:s.length?zl(s):void 0};var r,o}}class Vl{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async forwardChatMessage(e,t){const n=t.target?.instanceId||e.activeInstanceId||"",i=t.target?.aiSessionId||e.activeAiSessionId,s=await this.deps.requireControlledInstance(n,!0),r=s.projectId?this.deps.requireProject(s.projectId):void 0;if("online"!==s.connectionStatus){const e=new Error(`Instance ${s.name} is not reachable.`);throw Object.assign(e,{statusCode:409,code:"CHAT_TARGET_UNREACHABLE"}),e}if(i){const n=await this.trySendAiSessionMessage(e,s.id,i,t.message.text,t.message.attachments,!t.target);return n.ok?this.sentResult(e,r,s,i,n.aiSession):this.failedSendResult(n.binding,r,s,n.reply)}const o=await this.targets.defaultAiSessionIdForInstance(s.id);if(o){const n=this.deps.upsertChatSession({...e,activeAiSessionId:o}),i=await this.trySendAiSessionMessage(n,s.id,o,t.message.text,t.message.attachments);return i.ok?this.sentResult(n,r,s,o,i.aiSession):this.failedSendResult(i.binding,r,s,i.reply)}return{accepted:!1,routed:!1,binding:e,project:r||void 0,instance:Ud(s),reply:`No active AI session is selected for ${s.name}. Use /sessions and /session <id> first.`}}async trySendAiSessionMessage(e,t,n,i,s=[],r=!0){try{return{ok:!0,binding:e,aiSession:await this.deps.sendAiSessionMessage(t,n,i||"请查看附件。",void 0,s)}}catch(t){return function(e){return"AI_SESSION_NOT_FOUND"===(e&&"object"==typeof e?e:{}).code}(t)?{ok:!1,binding:r?this.deps.upsertChatSession({...e,activeAiSessionId:void 0}):e,reply:`The selected AI session ${n} no longer exists. Use /session to choose an active AI session.`}:{ok:!1,binding:e,reply:`Failed to send to AI session ${n}: ${Vd(t)}`}}}failedSendResult(e,t,n,i){return{accepted:!1,routed:!1,binding:e,project:t||void 0,instance:Ud(n),reply:i}}sentResult(e,t,n,i,s){return{accepted:!0,routed:!0,binding:e,project:t||void 0,instance:Ud(n),aiSession:s,instanceId:n.id,aiSessionId:i,turnId:(r=s,r.turnId||r.providerTurnId||r.session.activeTurnId||""),providerTurnId:Ll(s),reply:`Sent to ${t?.name||n.sourceSnapshot.name||"Source"} / ${n.name} / ${i}.`};var r}}class Kl{deps;constructor(e){this.deps=e}async handlePendingCommand(e){const t=await this.deps.listPendingRoutes(),n=e.activeInstanceId?t.filter(t=>t.instanceId===e.activeInstanceId):t;return{accepted:!0,routed:!1,binding:e,pending:n,reply:n.length?n.map(jl).join("\n"):"No pending routes.",replyMarkup:n.length?Pl(n,(e,t)=>this.deps.pendingDecisionCallbackData(e.id,t)):void 0}}async handlePendingDecisionCommand(e,t,n){const i=Gd(t[0]);return i?i.aiSessionId?{accepted:!0,routed:!0,binding:e,pending:i,aiSession:await this.deps.resolveAiSessionApproval(i.instanceId,i.aiSessionId,n),reply:`${n} sent for ${i.instanceId}:${i.aiSessionId}.`}:{accepted:!1,routed:!1,binding:e,pending:i,reply:"Only AI session pending routes are supported here."}:{accepted:!1,routed:!1,binding:e,reply:`Usage: /${"allow"===n?"approve":n} <instance-id:pending-id>`}}async handlePendingReplyCommand(e,t){const n=Gd(t[0]),i=t.slice(1).join(" ").trim();return n&&i?n.aiSessionId?{accepted:!0,routed:!0,binding:e,pending:n,aiSession:await this.deps.sendAiSessionMessage(n.instanceId,n.aiSessionId,i),reply:`Reply sent for ${n.instanceId}:${n.aiSessionId}.`}:{accepted:!1,routed:!1,binding:e,pending:n,reply:"Only AI session pending routes are supported here."}:{accepted:!1,routed:!1,binding:e,reply:"Usage: /reply <instance-id:pending-id> <message>"}}}class Jl{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleUseCommand(e,t){if(0===t.length)return{accepted:!0,routed:!1,binding:e,instances:await this.targets.instancesForBinding(e),reply:await this.targets.renderUseHelp(e)};if(t.length>=2){const n=this.targets.resolveProject(t[0]),i=await this.targets.resolveInstance(t[1],n.id),s=this.deps.upsertChatSession({...e,activeProjectId:n.id,activeInstanceId:i.id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(i.id)});return{accepted:!0,routed:!1,binding:s,reply:await this.targets.renderTargetSelected(s)}}const n=t[0],i=await this.targets.findInstance(n);if(i){const t=i.projectId?this.deps.requireProject(i.projectId):void 0,n=this.deps.upsertChatSession({...e,activeProjectId:t?.id,activeInstanceId:i.id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(i.id)});return{accepted:!0,routed:!1,binding:n,reply:await this.targets.renderTargetSelected(n)}}const s=this.targets.resolveProject(n),r=(await this.deps.boardAsync()).filter(e=>e.projectId===s.id),o=r.filter(e=>"running"===e.status&&"online"===e.connectionStatus);if(1===o.length){const t=this.deps.upsertChatSession({...e,activeProjectId:s.id,activeInstanceId:o[0].id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(o[0].id)});return{accepted:!0,routed:!1,binding:t,reply:await this.targets.renderTargetSelected(t)}}return{accepted:!0,routed:!1,binding:this.deps.upsertChatSession({...e,activeProjectId:s.id,activeInstanceId:void 0,activeAiSessionId:void 0}),instances:r,reply:`${s.name} selected. Choose an instance with /use ${s.id} <instance-id-or-name>.\n${this.targets.renderInstanceLines(r)}`}}async handleProjectCommand(e,t){if(0===t.length)return{accepted:!1,routed:!1,binding:e,reply:"Usage: /project <project-id-or-name>"};const n=this.targets.resolveProject(t[0]),i=e.activeInstanceId?await this.deps.requireControlledInstance(e.activeInstanceId).catch(()=>{}):void 0,s=this.deps.upsertChatSession({...e,activeProjectId:n.id,activeInstanceId:i?.projectId===n.id?i.id:void 0,activeAiSessionId:i?.projectId===n.id?e.activeAiSessionId:void 0});return{accepted:!0,routed:!1,binding:s,reply:`Active project: ${n.name}${s.activeInstanceId?"":". Choose an instance with /use."}`}}}class Yl{deps;constructor(e){this.deps=e}async instancesForBinding(e){const t=await this.deps.boardAsync();return e.activeProjectId?t.filter(t=>t.projectId===e.activeProjectId):t}async fullInstancesForBinding(e){const t=await this.deps.listNodeInstances();return e.activeProjectId?t.filter(t=>t.projectId===e.activeProjectId):t}async renderUseHelp(e){return`Active target: ${await this.renderChatTarget(e)}\nUse /instances to list targets, then /use <instance-id-or-name>. Use /sessions to choose an AI session when there is more than one.`}async renderChatStatus(e){const t=e.activeInstanceId?(await this.deps.boardAsync()).find(t=>t.id===e.activeInstanceId):void 0;return t?`Active target: ${await this.renderChatTarget(e)}\nStatus: ${t.status}, connection: ${t.connectionStatus}`:`Active target: ${await this.renderChatTarget(e)}`}async renderChatHelp(e){return["TaskHandoff chat commands:","/help - show this help","/status or /target - show the active project, instance, and AI session","/instances - list controlled instances","/apps - list app sessions","/use <instance-id-or-name> - choose an active instance","/use <project-id-or-name> <instance-id-or-name> - choose a project and instance","/project <project-id-or-name> - narrow instance selection to a project","/sessions - list all AI sessions","/session <ai-session-id> - choose an active AI session","/pending - list waiting approvals","/approve <instance-id:pending-id>, /deny <...>, /skip <...> - answer approvals","/reply <instance-id:pending-id> <message> - reply to a waiting session","/cancel - interrupt the active AI session","","Send normal text after selecting a target; if there is only one AI session, it is selected automatically.",`Current target: ${await this.renderChatTarget(e)}`].join("\n")}renderInstanceLines(e){return e.map(e=>`${e.name} (${e.id}) - ${e.status}/${e.connectionStatus}`).join("\n")}async renderChatTarget(e){const t=e.activeProjectId?this.deps.getProject(e.activeProjectId):void 0,n=e.activeInstanceId?await this.deps.requireControlledInstance(e.activeInstanceId).catch(()=>{}):void 0,i=e.activeAiSessionId||"none";return`${t?.name||e.activeProjectId||"none"} / ${n?.name||e.activeInstanceId||"none"} / ${i}`}async renderTargetSelected(e){const t=await this.renderChatTarget(e);return e.activeAiSessionId?`Active target: ${t}`:`Active target: ${t}\nNo AI session selected yet. Use /sessions and /session <id>, or send a message once exactly one session is available.`}async defaultAiSessionIdForInstance(e){const t=await this.aiSessionSnapshotForInstance(e),n=(await this.deps.boardAsync()).find(t=>t.id===e),i=(await this.deps.listAppSessions()).instances.find(t=>t.instanceId===e),s=n?{...n,apps:{...n.apps,sessions:i?.appSessions.sessions||[]}}:void 0,r=t&&n?Nl({...s,aiSessions:t}):t?.sessions||[];return 1===r.length?r[0].id:void 0}async aiSessionChoices(e){return(await this.boardInstancesForBinding({},{refresh:!0})).flatMap(t=>Nl(t).map(n=>({index:0,projectId:t.projectId,projectName:t.project?.name||("string"==typeof t.sourceSnapshot.name?t.sourceSnapshot.name:"Source"),instance:t,session:n,active:e.activeInstanceId===t.id&&e.activeAiSessionId===n.id}))).sort((e,t)=>{const n=Ol(t.session)-Ol(e.session);return n||(String(e.instance.name||"").localeCompare(String(t.instance.name||""))||e.instance.id.localeCompare(t.instance.id)||_l(e.session).localeCompare(_l(t.session)))}).map((e,t)=>({...e,index:t}))}async boardInstancesForBinding(e,t={}){const n=await this.deps.boardAsync(),i=await this.deps.listAiSessions(t),s=await this.deps.listAppSessions(t),r=new Map(i.instances.map(e=>[e.instanceId,e.aiSessions])),o=new Map(s.instances.map(e=>[e.instanceId,e.appSessions])),a=n.map(e=>{return{...e,apps:{...e.apps,sessions:o.get(e.id)?.sessions||[]},aiSessions:r.get(e.id)||(t=e.aiSessions.updatedAt,{runningCount:0,waitingCount:0,staleCount:0,sessions:[],updatedAt:t})};var t});return e.activeProjectId?a.filter(t=>t.projectId===e.activeProjectId):a}async findAiSession(e){const t=await this.boardInstancesForBinding({},{refresh:!0});for(const n of t){const t=(n.aiSessions?.sessions||[]).find(t=>t.id===e||t.providerSessionId===e);if(t)return{instance:n,session:t}}}async aiSessionSnapshotForInstance(e){const t=await this.deps.listAiSessions();return t.instances.find(t=>t.instanceId===e)?.aiSessions}resolveProject(e){const t=this.deps.getProject(e)||this.deps.listProjects().find(t=>t.name===e);return t||Kd("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}async resolveInstance(e,t){const n=await this.findInstance(e,t);return n||Kd("CONTROLLED_INSTANCE_NOT_FOUND",`Controlled instance ${e} was not found.`),n}async findInstance(e,t){return(await this.deps.listNodeInstances()).find(n=>!(n.id!==e&&n.name!==e||t&&n.projectId!==t))}}class Ql{deps;targets;sender;appCommands;pendingCommands;aiSessionCommands;targetCommands;constructor(e){this.deps=e,this.targets=new Yl(e),this.sender=new Vl(e,this.targets),this.appCommands=new Gl(e,this.targets),this.pendingCommands=new Kl(e),this.aiSessionCommands=new Ml(e,this.targets),this.targetCommands=new Jl(e,this.targets)}async handleChatGatewayMessage(e){const t=Gr.parse(e),n=this.deps.upsertChatSession({channel:t.source.channel,bridgeId:t.source.bridgeId,chatSessionId:t.source.chatSessionId,userId:t.source.userId}),i=t.message.text.trim();return i.startsWith("/")?this.handleChatCommand(n,i):i||t.message.attachments.length?n.activeInstanceId?this.sender.forwardChatMessage(n,t):{accepted:!1,routed:!1,binding:n,reply:await this.targets.renderUseHelp(n)}:{accepted:!1,routed:!1,binding:n,reply:""}}async handleChatGatewayAction(e){const t=this.deps.upsertChatSession({channel:e.source.channel,bridgeId:e.source.bridgeId,chatSessionId:e.source.chatSessionId,userId:e.source.userId});return"ai-session"===e.action.type?this.aiSessionCommands.handleAiSessionIndexAction(t,e.action.index):"instance-app-menu"===e.action.type?this.appCommands.handleInstanceAppMenuAction(t,e.action.instanceId):"launch-app"===e.action.type?this.appCommands.handleLaunchAppAction(t,e.action.instanceId,e.action.appId):"pending-decision"===e.action.type?this.pendingCommands.handlePendingDecisionCommand(t,[e.action.routeId],e.action.decision):{accepted:!1,routed:!1,binding:t,reply:"Unknown action."}}async handleChatCommand(e,t){const[n="",...i]=t.split(/\s+/),s=n.replace(/@[\w_]+$/,"");switch(s.toLowerCase()){case"/help":case"/start":return{accepted:!0,routed:!1,binding:e,reply:await this.targets.renderChatHelp(e)};case"/sessions":return this.aiSessionCommands.handleAiSessionsCommand(e);case"/session":return this.aiSessionCommands.handleAiSessionCommand(e,i);case"/cancel":case"/interrupt":return this.aiSessionCommands.handleAiSessionInterruptCommand(e);case"/pending":return this.pendingCommands.handlePendingCommand(e);case"/approve":return this.pendingCommands.handlePendingDecisionCommand(e,i,"allow");case"/deny":return this.pendingCommands.handlePendingDecisionCommand(e,i,"deny");case"/skip":return this.pendingCommands.handlePendingDecisionCommand(e,i,"skip");case"/reply":return this.pendingCommands.handlePendingReplyCommand(e,i);case"/instances":return this.appCommands.handleInstancesCommand(e);case"/apps":return this.appCommands.handleAppsCommand(e);case"/use":return this.targetCommands.handleUseCommand(e,i);case"/project":return this.targetCommands.handleProjectCommand(e,i);case"/status":case"/target":return{accepted:!0,routed:!1,binding:e,instance:e.activeInstanceId?(await this.deps.boardAsync()).find(t=>t.id===e.activeInstanceId):void 0,reply:await this.targets.renderChatStatus(e)};default:return{accepted:!1,routed:!1,binding:e,reply:`Unknown command: ${s||n}. Try /help.`}}}}const Xl=a.z.object({id:a.z.string().trim().min(1),preferences:Yo,createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict();function Zl(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=t.preferences&&"object"==typeof t.preferences&&!Array.isArray(t.preferences)?t.preferences:{};return{id:t.id,preferences:{import:"string"==typeof n.import&&n.import.trim()?n.import:".",export:"string"==typeof n.export&&n.export.trim()?n.export:"."},createdAt:t.createdAt,updatedAt:t.updatedAt}}function ep(){return Yo.parse({})}function tp(e){return/^[a-z]:[\\/]/i.test(e)||/^[\\/]{2}[^\\/]+[\\/]+[^\\/]+/.test(e)}function np(e){return tp(e)?t.win32:t.posix}class ip{retiredRoot;legacyControlledInstancesDir;legacyNodeRuntimesDir;legacyNodeJoinInvitesDir;paths;options;constructor(e,n={}){this.paths=e,this.options=n,this.retiredRoot=t.join(e.dataDir,"retired-persistence"),this.legacyControlledInstancesDir=t.join(e.dataDir,"controlled-instances"),this.legacyNodeRuntimesDir=t.join(e.dataDir,"node-runtimes"),this.legacyNodeJoinInvitesDir=t.join(e.dataDir,"node-join-invites")}run(){return this.removePersistedInvites(),this.retireLegacyProjection("controlled-instances",this.legacyControlledInstancesDir,!0),this.retireLegacyProjection("node-runtimes",this.legacyNodeRuntimesDir,!1),function(e){if(!n.existsSync(e.trashRoot))return[];const t=e.nowMs??Date.now(),i=e.retentionMs??Jr,s=[];for(const r of n.readdirSync(e.trashRoot,{withFileTypes:!0})){const o=Yr(e.trashRoot,r.name);try{const e=Number(r.name.split("-",1)[0]);if(!Number.isFinite(e)||e+i>t)continue;const a=n.lstatSync(o);a.isSymbolicLink()?n.unlinkSync(o):a.isDirectory()?n.rmSync(o,{recursive:!0,force:!0}):n.unlinkSync(o),s.push(o)}catch(t){e.logger?.("retired persistence entry cleanup failed",{path:o,error:t instanceof Error?t.message:String(t)})}}return s}({trashRoot:this.retiredRoot,retentionMs:this.options.retentionMs??Jr,nowMs:this.now(),logger:this.options.logger})}removePersistedInvites(){n.existsSync(this.legacyNodeJoinInvitesDir)&&n.rmSync(this.legacyNodeJoinInvitesDir,{recursive:!0,force:!0})}retireLegacyProjection(e,i,s){if(!n.existsSync(i))return;const r=n.lstatSync(i);if(!r.isDirectory()||r.isSymbolicLink())return n.rmSync(i,{force:!0}),void this.options.logger?.("invalid legacy persistence path was removed",{store:e});n.readdirSync(i).length?(s&&this.redactLegacyInstanceCredentials(i),function(e){const t=Yr(e.sourceRoot,e.entryName);if(!n.existsSync(t))return;const i=n.lstatSync(t);if(!i.isDirectory()||i.isSymbolicLink())throw new Error(`Retention source must be a real directory: ${t}`);Qr(e.trashRoot);const s=e.nowMs??Date.now();let r=0,o=`${s}-${e.entryName}`;for(;n.existsSync(Yr(e.trashRoot,o));)r+=1,o=`${s}-${r}-${e.entryName}`;const a=Yr(e.trashRoot,o);n.renameSync(t,a)}({sourceRoot:this.paths.dataDir,entryName:t.basename(i),trashRoot:this.retiredRoot,nowMs:this.now()}),this.options.logger?.("legacy control-plane persistence was retired",{store:e})):n.rmdirSync(i)}redactLegacyInstanceCredentials(e){for(const i of n.readdirSync(e,{withFileTypes:!0})){if(!i.isFile()||i.isSymbolicLink())continue;const s=t.join(e,i.name);try{const e=JSON.parse(n.readFileSync(s,"utf8"));delete e.registrationToken,c.sync(s,`${JSON.stringify(e,null,2)}\n`,{encoding:"utf8",mode:384}),n.chmodSync(s,384)}catch(e){n.rmSync(s,{force:!0}),this.options.logger?.("unreadable legacy instance record was removed",{filePath:s,error:e instanceof Error?e.message:String(e)})}}Qr(e)}now(){return this.options.now?.()??Date.now()}}const sp="task-handoff.control-plane.local",rp="task-handoff.control-plane.builtin";function op(e){return"true"===e.labels[sp]}function ap(e){return"true"===e.labels[rp]}class dp{projects;models;modelService;images;nodes;pendingPairingRevokes;chatSessions;chatBridges;triggers;nodeJoinService;configSyncPreferences;settings;paths;fetchImpl;dockerCommandRunner;logger;diagnosticLogsState;nodeConnectionRuntime;appAccessService;persistenceMaintenance;chatActionTokenService=new Il;nodeAgentTransportResolver;proxyPrivateStore;proxyLifecycle;nodeConnectionManager;nodeAgentGateway;controlledInstanceGateway;aiSessionActionService;controlledInstanceCreator;instanceBoardReader=new Zc;controlPlaneTriggerService;catalogService;marketCatalogService;chatBridgeService;chatSessionService;chatSessionRuntime;aiSessionSnapshotProvider;appSessionSnapshotProvider;constructor(e,n={}){this.paths=e,this.fetchImpl=n.fetchImpl||fetch,this.dockerCommandRunner=n.dockerCommandRunner,this.nodeConnectionRuntime=n.nodeConnectionRuntime,this.persistenceMaintenance=new ip(e,{logger:(e,t)=>this.logWarn(t,e)});const i=e=>({schema:e,logger:(e,t)=>this.logWarn(t,e)});this.proxyPrivateStore=new Cd(function(e){const n=t.resolve(e,"control-plane-proxy");return{pendingClaimsDir:t.join(n,"pending-claims"),nodeCredentialsDir:t.join(n,"node-credentials"),identityPath:t.join(n,"identity.json")}}(e.dataDir),(e,t)=>this.logWarn(t,e)),this.nodeAgentTransportResolver=new fd({direct:yd(this.fetchImpl),tunnel:n.nodeAgentTransport,proxy:new Ad({credentialForNode:e=>this.proxyPrivateStore.nodeCredential(e.id),fetchImpl:this.fetchImpl})});const s=(r=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(r||"").trim().toLowerCase()));var r;this.diagnosticLogsState=s,this.settings=new Io(e.settingsPath,()=>sc.parse({diagnosticLogs:s}),{...i(sc),sanitize:e=>function(e,t={}){if(!e||"object"!=typeof e||Array.isArray(e))return{};const n={...e};return"string"==typeof n.mentionTrigger&&ec(n.mentionTrigger)||(n.mentionTrigger="@"),"string"==typeof n.commandTrigger&&nc(n.commandTrigger)&&n.commandTrigger!==n.mentionTrigger||(n.commandTrigger="/"),"boolean"!=typeof n.diagnosticLogs&&(n.diagnosticLogs=t.diagnosticLogs??!1),n}(e,{diagnosticLogs:s})}),this.logger=n.logger?{info:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.info?.(e,t)},warn:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.warn?.(e,t)},error:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.error?.(e,t)}}:void 0;const o=new Va({request:(e,t,n)=>this.nodeAgentFetch(e,t,n),logger:this.logger});this.nodeAgentGateway=new Ka(o),this.controlledInstanceGateway=new Qc({requireNode:e=>this.requireNode(e),nodeAgentTransport:e=>this.nodeAgentTransportResolver.resolve(e)}),this.aiSessionActionService=new La({requireInstance:e=>this.requireControlledInstance(e,!0),request:(e,t,n)=>this.instanceRequest(e,t,n),requireRuntime:(e,t)=>this.requireNodeRuntimeOnNode(e,t),refreshSnapshots:()=>Promise.all([this.listAppSessions({refresh:!0}),this.listAiSessions({refresh:!0})]),warn:(e,t)=>this.logWarn(e,t)}),this.projects=new fo(e.projectsDir,{...i(js),sanitize:Ji}),this.models=new fo(e.modelsDir,i(Ds)),this.modelService=new Kc({models:this.models,gateway:this.nodeAgentGateway,listNodes:()=>this.listNodes(),requireNode:e=>this.requireNode(e),fetchImpl:this.fetchImpl}),this.images=new fo(e.imagesDir,{...i(ir),sanitize:e=>gr(e,e=>this.logWarn(e,"legacy image profile field was migrated"))}),this.nodes=new fo(e.nodesDir,{...i(fr),sanitize:e=>function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,i=new Set(["id","name","connectionMode","connectionPath","connectionEnabled","auth","endpoint","controlEndpoint","containerEndpoint","publicWebBase","status","health","capabilities","proxyState","appInventory","labels","lastSeenAt","createdAt","updatedAt"]);for(const e of Object.keys(n))i.has(e)||t?.({field:e});const s=n.auth&&"object"==typeof n.auth&&!Array.isArray(n.auth)?Ur(n.auth,["mode","keyId","secret","pairedAt","pairing"]):n.auth;s&&"object"==typeof s&&"pairing"in s&&(s.pairing=Ur(s.pairing,["status","joinToken","expiresAt"]));const r=n.connectionPath&&"object"==typeof n.connectionPath&&!Array.isArray(n.connectionPath)?"control-plane-proxy"===n.connectionPath.kind?Ur(n.connectionPath,["kind","proxyId","proxyBindingId","targetNodeId"]):Ur(n.connectionPath,["kind"]):{kind:"direct"},o=n.proxyState&&"object"==typeof n.proxyState&&!Array.isArray(n.proxyState)?Ur(n.proxyState,["reachability","bindingStatus","bindingRevision","streamId","revision","observedAt","target","lastError","updatedAt"]):n.proxyState;if(o&&"object"==typeof o){const e=o;e.target=Ur(e.target,["id","name","status","health","lastSeenAt","capabilities"]),e.lastError=Ur(e.lastError,["code","message","retryable","details"])}return{...Object.fromEntries(Object.entries(n).filter(([e])=>i.has(e))),auth:s,connectionPath:r,proxyState:o}}(e,e=>this.logWarn(e,"unknown stored node field was ignored"))}),this.pendingPairingRevokes=new fo(e.pendingPairingRevokesDir,i(Ec)),this.proxyLifecycle=new Qd({nodes:this.nodes,privateStore:this.proxyPrivateStore,fetchImpl:this.fetchImpl,requireNode:e=>this.requireNode(e),deleteNode:e=>this.deleteNode(e)}),this.nodeConnectionManager=new Cc({nodes:this.nodes,pendingPairingRevokes:this.pendingPairingRevokes,fetchImpl:this.fetchImpl,localNodeLabel:sp,builtinNodeLabel:rp,info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.chatSessions=new fo(e.chatSessionsDir,i(Wr)),this.chatBridges=new fo(e.chatBridgesDir,i(Hr)),this.triggers=new fo(e.triggersDir,i(lc)),this.nodeJoinService=new Lc({nodes:this.nodes}),this.configSyncPreferences=new fo(t.join(e.dataDir,"config-sync-preferences"),{...i(Xl),sanitize:Zl}),this.marketCatalogService=new ll,this.catalogService=new ol({projects:this.projects,images:this.images,market:this.marketCatalogService,settings:this.settings,defaultNodeId:()=>this.defaultNodeId()}),this.controlledInstanceCreator=new el({gateway:this.nodeAgentGateway,defaultNodeId:()=>this.defaultNodeId(),requireProject:e=>this.requireProject(e),requireNode:e=>this.requireNode(e),requireRuntime:(e,t)=>this.requireNodeRuntimeOnNode(e,t),requireLocalFolder:(e,t)=>this.requireNodeLocalFolder(e,t),resolveImageSelection:e=>this.catalogService.resolveImageSelection(e),prepareModels:(e,t)=>this.modelService.prepareAssignment(e,t)}),this.controlPlaneTriggerService=new il({triggers:this.triggers,listInstances:()=>this.listNodeInstances(),requireInstance:async e=>this.requireControlledInstance(e,!0),instanceRequest:(e,t,n)=>this.instanceRequest(e,t,n)}),this.appAccessService=new ul({requireInstance:async e=>this.requireControlledInstance(e,!0),listAppSessions:()=>this.listAppSessions()}),this.chatBridgeService=new Sl({chatBridges:this.chatBridges,chatSessions:this.chatSessions}),this.chatSessionService=new Al({chatSessions:this.chatSessions}),this.chatSessionRuntime=new Ql({upsertChatSession:e=>this.upsertChatSession(e),boardAsync:()=>this.boardAsync(),listAiSessions:e=>this.listAiSessions(e),listAppSessions:e=>this.listAppSessions(e),listNodeInstances:()=>this.listNodeInstances(),listPendingRoutes:()=>this.listPendingRoutes(),pendingDecisionCallbackData:(e,t)=>this.pendingDecisionCallbackData(e,t),createChatActionToken:e=>this.createChatActionToken(e),createAppAccessToken:e=>this.createAppAccessToken(e),controlPlanePublicBaseUrl:()=>this.getSettings().publicBaseUrl||process.env.TASK_HANDOFF_CONTROL_PLANE_URL||process.env.TASK_HANDOFF_PUBLIC_BASE||process.env.TASK_HANDOFF_CONTROL_PLANE_PUBLIC_URL,requireControlledInstance:(e,t)=>this.requireControlledInstance(e,t),requireProject:e=>this.requireProject(e),getProject:e=>this.catalogService.getProject(e),listProjects:()=>this.catalogService.listProjects(),resolveAiSessionApproval:(e,t,n)=>this.resolveAiSessionApproval(e,t,n),sendAiSessionMessage:(e,t,n,i,s)=>this.sendAiSessionMessage(e,t,n,i,s),interruptAiSession:(e,t)=>this.interruptAiSession(e,t),launchAppSession:(e,t,n)=>this.launchAppSession(e,t,n)})}logInfo(e,t){this.logger?.info?.(e,t)}logWarn(e,t){this.logger?.warn?.(e,t)}logError(e,t){this.logger?.error?.(e,t)}setNodeAgentTransport(e){this.nodeAgentTransportResolver.setTunnel(e)}resolveNodeAgentTransport(e){return this.nodeAgentTransportResolver.resolve(e)}setAiSessionSnapshotProvider(e){this.aiSessionSnapshotProvider=e}async listAiSessions(e={}){return this.aiSessionSnapshotProvider?this.aiSessionSnapshotProvider(e):this.bootstrapAiSessionsFromInstances()}setAppSessionSnapshotProvider(e){this.appSessionSnapshotProvider=e}async listAppSessions(e={}){return this.appSessionSnapshotProvider?this.appSessionSnapshotProvider(e):this.bootstrapAppSessionsFromInstances()}init(){this.runPersistenceMaintenance(),this.projects.init(),this.models.init(),this.images.init(),this.nodes.init(),this.pendingPairingRevokes.init(),this.chatSessions.init(),this.chatBridges.init(),this.triggers.init(),this.proxyPrivateStore.init(),this.proxyPrivateStore.gcNodeCredentials(e=>{const t=this.nodes.get(e.nodeId);return"control-plane-proxy"===t?.connectionMode&&"control-plane-proxy"===t.connectionPath.kind&&t.connectionPath.proxyBindingId===e.proxyBindingId&&t.connectionPath.targetNodeId===e.targetNodeId}),this.settings.init();const e=this.settings.put(this.settings.get());this.diagnosticLogsState=e.diagnosticLogs,this.migrateLegacyImageCatalog(),this.seedDefaults()}runPersistenceMaintenance(){try{return this.persistenceMaintenance.run()}catch(e){return this.logWarn({error:e instanceof Error?e.message:String(e)},"control-plane persistence maintenance failed"),[]}}migrateLegacyImageCatalog(){const e=Object.keys(Vi),i=[];for(const t of e){const e=this.images.filePath(t);if(n.existsSync(e))try{i.push({id:t,filePath:e,record:JSON.parse(n.readFileSync(e,"utf8"))})}catch(e){return this.writeMarketMigrationState("failed",{code:"LEGACY_IMAGE_BACKUP_READ_FAILED",legacyId:t,error:Vd(e)}),void this.logWarn({legacyId:t,error:Vd(e)},"legacy embedded image migration was not applied")}}if(!i.length)return;const s=n.readdirSync(this.paths.projectsDir).filter(e=>e.endsWith(".json")).sort().map(e=>t.join(this.paths.projectsDir,e)),r=[];for(const e of s)try{const t=JSON.parse(n.readFileSync(e,"utf8")),i=js.parse(Ji(t));r.push({filePath:e,raw:t,migrated:i})}catch(t){return this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_VALIDATION_FAILED",filePath:e,error:Vd(t)}),void this.logWarn({filePath:e,error:Vd(t)},"legacy embedded image migration was not applied")}const o=r.find(({migrated:t})=>{const n=t.defaultImageSelection?.imageId;return!!n&&e.includes(n)});if(o)this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_MIGRATION_INCOMPLETE",filePath:o.filePath});else{n.mkdirSync(this.paths.marketDir,{recursive:!0}),c.sync(this.paths.marketMigrationBackupPath,`${JSON.stringify({version:ui,createdAt:Hd(),images:i.map(({id:e,record:t})=>({id:e,record:t})),projects:r.map(({filePath:e,raw:n})=>({file:t.basename(e),record:n}))},null,2)}\n`,{encoding:"utf8"});for(const{migrated:e}of r)this.projects.put(e);for(const{id:e}of i)this.images.delete(e),this.logWarn({legacyId:e,marketId:Vi[e]},"embedded image profile migrated to Market");this.writeMarketMigrationState("complete",{code:"LEGACY_IMAGE_MIGRATION_COMPLETE",migratedImageIds:i.map(({id:e})=>e),backupPath:this.paths.marketMigrationBackupPath})}}writeMarketMigrationState(e,t){n.mkdirSync(this.paths.marketDir,{recursive:!0}),c.sync(this.paths.marketStatePath,`${JSON.stringify({status:e,updatedAt:Hd(),...t},null,2)}\n`,{encoding:"utf8"})}getSettings(){return this.catalogService.getSettings()}diagnosticLogsEnabled(){return this.diagnosticLogsState}updateSettings(e){const t=this.catalogService.updateSettings(e);return this.diagnosticLogsState=t.diagnosticLogs,t}seedDefaults(){return this.catalogService.seedDefaults()}listProjects(){return this.catalogService.listProjects()}defaultNodeId(){return this.nodes.list().find(op)?.id||this.nodes.list()[0]?.id}async syncLocalNodeConnection(){const e=await this.nodeConnectionManager.syncLocal();return this.nodeConnectionRuntime?.observedReachable(e),this.projectNodeConnection(e)}recoverPendingPairingRevokes(){return this.nodeConnectionManager.recoverPendingPairingRevokes()}listModels(){return this.modelService.list()}listFederatedModels(e){return this.modelService.listFederated(e)}createModel(e){return this.modelService.create(e)}updateModel(e,t){return this.modelService.update(e,t)}deleteModel(e){return this.modelService.delete(e)}reorderModels(e){return this.modelService.reorder(e)}createNodeModel(e,t){return this.modelService.createOnNode(e,t)}updateNodeModel(e,t,n){return this.modelService.updateOnNode(e,t,n)}deleteNodeModel(e,t){return this.modelService.deleteOnNode(e,t)}discoverModels(e){return this.modelService.discover(e)}testModel(e){return this.modelService.test(e)}discoverNodeModels(e,t){return this.modelService.discoverOnNode(e,t)}testNodeModel(e,t){return this.modelService.testOnNode(e,t)}createProject(e){return this.catalogService.createProject(e)}updateProject(e,t){return this.catalogService.updateProject(e,t)}deleteProject(e){return this.catalogService.deleteProject(e)}listImages(){return this.catalogService.listImages()}getMarketCatalog(){return this.catalogService.getMarketCatalog()}async refreshMarketCatalog(){return await this.marketCatalogService.refresh(new cl),this.getMarketCatalog()}listImageOptions(){return this.catalogService.listImageOptions()}createImage(e){return this.catalogService.createImage(e)}async listNodeDockerImages(e){const t=this.requireNode(e);return this.nodeAgentGateway.listDockerImages(t)}async listNodeImageAvailability(e){const t=this.requireNode(e),n=t.capabilities.agent&&"object"==typeof t.capabilities.agent?t.capabilities.agent:{},i={os:"string"==typeof n.platform?n.platform:void 0,architecture:"string"==typeof n.arch?"x64"===n.arch?"amd64":n.arch:void 0},s=this.catalogService.listImageOptions(i);try{const e=await this.nodeAgentGateway.listDockerImages(t);return s.map(t=>{const n=e.find(e=>e.reference===t.reference||!!t.digest&&e.repoDigests.some(e=>e.endsWith(`@${t.digest}`))||e.repoDigests.includes(t.reference));return Or.parse({image:t,status:n?"available":"pull-required",localImage:n,localSizeBytes:n?.sizeBytes,downloadSizeBytes:n?void 0:t.downloadSizeBytes,unpackedSizeBytes:n?void 0:t.unpackedSizeBytes})})}catch(e){const t=e instanceof Error?e.message:String(e);return s.map(e=>Or.parse({image:e,status:"unknown",error:t}))}}async listNodeLocalFolders(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.listLocalFolders(n,{signal:t})}async listNodeFolderTree(e,t={}){const n=this.requireNode(e);return this.nodeAgentGateway.listFolderTree(n,t)}async createNodeLocalFolder(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.createLocalFolder(n,t)}async deleteNodeLocalFolder(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteLocalFolder(n,t)}async checkNode(e){const t=this.requireNode(e);try{const e=await this.nodeAgentGateway.health(t),n=e&&"object"==typeof e?e:{},i="string"==typeof n.nodeId&&n.nodeId.trim()?n.nodeId.trim():t.id,s=fr.parse({...t,id:i,status:"online",health:"ok",capabilities:"object"==typeof e&&e?{...t.capabilities,agent:qd(e)}:t.capabilities,lastSeenAt:Hd(),updatedAt:Hd()});return i!==t.id&&this.nodes.delete(t.id),this.nodes.put(s),this.nodeConnectionRuntime?.observedReachable(s),{id:s.id,status:"online",checkedAt:Hd(),agent:e}}catch(e){const n=fr.parse({...t,status:"offline",health:"failed",updatedAt:Hd()});return this.nodes.put(n),this.nodeConnectionRuntime?.observedFailure(n,Vd(e)),{id:t.id,status:"offline",checkedAt:Hd(),error:e instanceof Error?e.message:String(e)}}}async checkNodeUpdate(e,t){return this.nodeAgentGateway.checkUpdate(this.requireNode(e),t)}async applyNodeUpdate(e,t){return this.nodeAgentGateway.applyUpdate(this.requireNode(e),t)}async listNodeUpdateJobs(e){return this.nodeAgentGateway.listUpdateJobs(this.requireNode(e))}async getLocalNodeExternalListener(e){return this.nodeAgentGateway.getExternalListener(this.requireLocalListenerNode(e))}async updateLocalNodeExternalListener(e,t){return this.nodeAgentGateway.updateExternalListener(this.requireLocalListenerNode(e),t)}async createNodePairingInvite(e,t={}){const n=this.requireNode(e);return this.nodeAgentGateway.createPairingInvite(n,t)}requireLocalListenerNode(e){const t=this.requireNode(e);if(!ap(t)||!op(t)){const e=new Error("Node agent TCP listener settings are available only for the built-in local node.");throw Object.assign(e,{statusCode:403,code:"LOCAL_NODE_LISTENER_ONLY"}),e}return t}createNodeJoinInvite(e={}){return this.nodeJoinService.createInvite(e)}completeNodeJoin(e){return this.nodeJoinService.complete(e)}async connectNodeToControlPlane(e,t){const n=this.requireNode(e),i=zc.parse(t);return this.nodeAgentGateway.createControlPlaneConnection(n,i)}async listNodeControlPlanePairings(e){const t=this.requireNode(e);return this.nodeAgentGateway.listControlPlanePairings(t)}async deleteNodeControlPlanePairing(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteControlPlanePairing(n,t)}async listNodeControlPlaneConnections(e){const t=this.requireNode(e);return this.nodeAgentGateway.listControlPlaneConnections(t)}async deleteNodeControlPlaneConnection(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteControlPlaneConnection(n,t)}updateImage(e,t){return this.catalogService.updateImage(e,t)}async deleteImage(e){this.catalogService.requireImage(e);const t=this.listProjects().find(t=>t.defaultImageSelection?.imageId===e);if(t)throw Object.assign(new Error(`Image ${e} is the default for project ${t.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});const n=(await Promise.all(this.listNodes().map(e=>this.nodeAgentGateway.listLocalFolders(e)))).flat().find(t=>t.defaultImageSelection?.imageId===e);if(n)throw Object.assign(new Error(`Image ${e} is the default for local folder ${n.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});const i=(await this.listNodeInstances()).find(t=>t.imageSelection?.imageId===e);if(i)throw Object.assign(new Error(`Image ${e} is used by instance ${i.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});return this.catalogService.deleteImage(e)}listNodes(){return this.nodes.list()}listPublicNodes(){return this.listNodes().map(e=>$d(this.projectNodeConnection(e)))}projectNodeConnection(e){return this.nodeConnectionRuntime?.project(e)||e}createNode(e){return this.nodeConnectionManager.create(e)}listPendingProxyClaims(){return this.proxyLifecycle.listPendingClaims()}claimProxyNode(e){return this.proxyLifecycle.claimNode(e)}resumeProxyClaim(e){return this.proxyLifecycle.resumeClaim(e)}cancelProxyClaim(e){return this.proxyLifecycle.cancelClaim(e)}applyProxyTargetSnapshot(e,t){return this.proxyLifecycle.applyTargetSnapshot(e,t)}applyProxyTargetEvent(e,t){return this.proxyLifecycle.applyTargetEvent(e,t)}markProxyUnavailable(e,t){return this.proxyLifecycle.markUnavailable(e,t)}markProxyBindingRevoked(e,t){return this.proxyLifecycle.markBindingRevoked(e,t)}updateNode(e,t){const n=kc.parse(t),i=this.requireNode(e);this.proxyLifecycle.assertIdentityPatch(i,n);const s=fr.parse({...i,...n,id:e,createdAt:i.createdAt,updatedAt:Hd()});return this.nodes.put(s)}deleteNode(e){if(ap(this.requireNode(e))){const e=new Error("The built-in local node connection cannot be deleted.");throw Object.assign(e,{statusCode:400,code:"LOCAL_NODE_CANNOT_BE_DELETED"}),e}return this.nodes.delete(e)}async deleteNodeWithProxyLifecycle(e,t=!1){return this.proxyLifecycle.deleteNode(this.requireNode(e),t)}async listNodeRuntimes(e,t){const n=e?[this.requireNode(e)]:this.listNodes();return e?this.nodeAgentGateway.listRuntimes(n[0],{signal:t}):(await this.nodeAgentGateway.listFleetRuntimes(n,{signal:t})).items}async listNodeRuntimesWithDiagnostics(e){return this.nodeAgentGateway.listFleetRuntimes(this.listNodes().map(e=>this.projectNodeConnection(e)),{signal:e})}async createNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.createRuntime(n,t)}async updateNodeRuntime(e,t,n){const i=this.requireNode(e);return this.nodeAgentGateway.updateRuntime(i,t,n)}async deleteNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteRuntime(n,t)}async checkNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.checkRuntime(n,t)}async listControlledInstances(){return(await this.listNodeInstances()).map(Ud)}async listControlledInstancesWithDiagnostics(){const e=await this.listNodeInstancesWithDiagnostics();return{items:e.items.map(Ud),nodeErrors:e.nodeErrors}}async instanceResourceMetrics(e){const t=await this.requireNodeInstance(e);return this.nodeAgentGateway.instanceResourceMetrics(this.requireNode(t.nodeId),t.id)}async nodeOwnsInstance(e,t){const n=this.requireNode(e);return(await this.nodeAgentGateway.listInstances(n)).some(n=>n.id===t&&n.nodeId===e)}createControlledInstance(e){return this.controlledInstanceCreator.create(e)}async updateControlledInstance(e,t){const n=Ic.parse(t),i=await this.requireNodeInstance(e),s=this.requireNode(i.nodeId);void 0!==n.config?.aiSessionHistoryLimit&&function(e,t){const n=e.capabilities.agent,i=n&&"object"==typeof n&&!Array.isArray(n)?n.capabilities:void 0;if(!Boolean(i&&"object"==typeof i&&!Array.isArray(i)&&!0===i.aiSessionHistoryLimit)||!vi(t.capabilities).features.aiSessionPersistenceSettings)throw Object.assign(new Error("This instance does not support managed AI session history retention settings."),{statusCode:409,code:"AI_SESSION_HISTORY_LIMIT_UNSUPPORTED"})}(s,i);const{modelSelection:r,...o}=n;let a=Object.keys(o).length?await this.nodeAgentGateway.updateInstance(s,e,o):i;if(r){const t=await this.modelService.prepareAssignment(s,r);a=(await this.nodeAgentGateway.assignInstanceModels(s,e,t)).instance}return Ud(a)}async deleteControlledInstance(e,t){const n=Hi.parse(t),i=await this.requireNodeInstance(e),s=this.requireNode(i.nodeId),r=await this.nodeAgentGateway.deleteInstance(s,e,n);return r.completed&&this.configSyncPreferences.delete(e),r}listEnvironmentTemplates(e){return this.nodeAgentGateway.listEnvironmentTemplates(this.requireNode(e))}getEnvironmentTemplate(e,t){return this.nodeAgentGateway.getEnvironmentTemplate(this.requireNode(e),t)}async createEnvironmentTemplate(e,t){const n=await this.requireNodeInstance(e);return this.nodeAgentGateway.createEnvironmentTemplate(this.requireNode(n.nodeId),e,t)}deleteEnvironmentTemplate(e,t){return this.nodeAgentGateway.deleteEnvironmentTemplate(this.requireNode(e),t)}async startControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return await this.modelService.ensureInstanceAssignment(t),Ud(await this.nodeAgentGateway.startInstance(n,e))}async stopControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return Ud(await this.nodeAgentGateway.stopInstance(n,e))}async restartControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return await this.modelService.ensureInstanceAssignment(t),Ud(await this.nodeAgentGateway.restartInstance(n,e))}async retryControlledInstanceImageProvisioning(e){const t=await this.requireNodeInstance(e);return Ud(await this.nodeAgentGateway.retryInstanceImageProvisioning(this.requireNode(t.nodeId),e))}async boardAsync(){return(await this.boardWithDiagnostics()).items}async boardWithDiagnostics(e){const[t,n]=await Promise.all([this.listNodeRuntimesWithDiagnostics(e),this.listNodeInstancesWithDiagnostics(e)]);return this.instanceBoardReader.read({projects:this.listProjects(),images:this.listImageOptions(),nodes:this.nodes.list().map(e=>this.projectNodeConnection(e)),runtimes:t.items,instances:n.items,nodeErrors:[...t.nodeErrors,...n.nodeErrors]})}async bootstrapAiSessionsFromInstances(){const e=await this.listNodeInstances(),t=await Promise.all(e.map(async e=>{if(!Kr(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus)return{streamId:`bootstrap:${e.id}:ai.sessions`,revision:0,lastEventAt:e.aiSessions.updatedAt,snapshot:e.aiSessions};try{return Uo(et,await this.instanceRequest(e,"/ai-sessions/state"))}catch(t){return this.logWarn({instanceId:e.id,error:Vd(t),errorCode:"AI_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live AI sessions"),{streamId:`bootstrap:${e.id}:ai.sessions`,revision:0,lastEventAt:e.aiSessions.updatedAt,snapshot:e.aiSessions}}}));return{updatedAt:(new Date).toISOString(),instances:e.map((e,n)=>({instanceId:e.id,streamId:t[n].streamId,aiSessions:t[n].snapshot,revision:t[n].revision,lastEventAt:t[n].lastEventAt}))}}async bootstrapAppSessionsFromInstances(){const e=await this.listNodeInstances(),t=await Promise.all(e.map(async e=>{if(!Kr(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=Ft();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:t.updatedAt,snapshot:t}}try{return Uo(kt,await this.instanceRequest(e,"/apps/sessions/state"))}catch(t){this.logWarn({instanceId:e.id,error:Vd(t),errorCode:"APP_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live app sessions");const n=Ft();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:n.updatedAt,snapshot:n}}}));return{updatedAt:(new Date).toISOString(),instances:e.map((e,n)=>({instanceId:e.id,streamId:t[n].streamId,appSessions:t[n].snapshot,revision:t[n].revision,lastEventAt:t[n].lastEventAt}))}}async recoverAiSessionDelta(e,t,n){const i=await this.requireControlledInstance(e,!0),s=new URLSearchParams({streamId:t,sinceRevision:String(n)});return Uo(lt,await this.instanceRequest(i,`/ai-sessions?${s}`))}async recoverAiSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return Uo(et,await this.instanceRequest(t,"/ai-sessions/state"))}async recoverAppSessionDelta(e,t,n){const i=await this.requireControlledInstance(e,!0),s=new URLSearchParams({streamId:t,sinceRevision:String(n)});return Uo(Nt,await this.instanceRequest(i,`/apps/sessions?${s}`))}async recoverAppSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return Uo(kt,await this.instanceRequest(t,"/apps/sessions/state"))}async listTriggers(){return this.controlPlaneTriggerService.listTriggers()}createTrigger(e){return this.controlPlaneTriggerService.createTrigger(e)}async updateTrigger(e,t){return this.controlPlaneTriggerService.updateTrigger(e,t)}async deleteTrigger(e){return this.controlPlaneTriggerService.deleteTrigger(e)}async applyTrigger(e,t){return this.controlPlaneTriggerService.applyTrigger(e,t)}async listInstanceTriggers(e){return this.controlPlaneTriggerService.listInstanceTriggers(e)}async bindAiSessionTrigger(e,t,n){return this.controlPlaneTriggerService.bindAiSessionTrigger(e,t,n)}async unbindAiSessionTrigger(e,t,n){return this.controlPlaneTriggerService.unbindAiSessionTrigger(e,t,n)}async runInstanceTrigger(e,t,n={}){return this.controlPlaneTriggerService.runInstanceTrigger(e,t,n)}listChatSessions(){return this.chatSessionService.list()}createAppAccessToken(e){return this.appAccessService.createToken(e)}createAppSessionAccessToken(e){return this.appAccessService.createSessionToken(e)}revokeAppSessionAccessToken(e,t){this.appAccessService.revokeToken(e,t)}resolveAppAccessToken(e,t){return this.appAccessService.resolveToken(e,t)}createChatActionToken(e){return this.chatActionTokenService.create(e)}resolveChatActionToken(e,t){return this.chatActionTokenService.resolve(e,t)}pendingDecisionCallbackData(e,t){return this.chatActionTokenService.pendingDecisionCallbackData(e,t)}async appAccessProxyTarget(e,t,n=""){return this.appAccessService.proxyTarget(e,t,n)}listChatBridges(){return this.chatBridgeService.list()}requireChatBridge(e){return this.chatBridgeService.require(e)}createChatBridge(e){return this.chatBridgeService.create(e)}updateChatBridge(e,t){return this.chatBridgeService.update(e,t)}deleteChatBridge(e){return this.chatBridgeService.delete(e)}requireChatSession(e){return this.chatSessionService.require(e)}upsertChatSession(e){return this.chatSessionService.upsert(e)}async handleChatGatewayMessage(e){return this.chatSessionRuntime.handleChatGatewayMessage(e)}async handleChatGatewayAction(e){return this.chatSessionRuntime.handleChatGatewayAction(e)}async handleChatCommand(e,t){return this.chatSessionRuntime.handleChatCommand(e,t)}async listPendingRoutes(){const e=Hd(),t=[],n=await this.listAiSessions(),i=new Map(n.instances.map(e=>[e.instanceId,e.aiSessions])),s=await this.nodeAgentGateway.listFleetInstances(this.listNodes());for(const n of s.items){if("online"!==n.connectionStatus&&"online"!==n.agentStatus||!n.target.web)continue;const s=n.projectId?this.catalogService.getProject(n.projectId):void 0;for(const r of i.get(n.id)?.sessions||[]){if("waiting"!==r.status)continue;const i=Vr.parse({id:`${n.id}:ai:${r.id}`,instanceId:n.id,projectId:n.projectId,aiSessionId:r.id,providerSessionId:r.providerSessionId,result:r.summary||r.currentTool?.inputPreview||r.lastMessage||`${r.agent} is waiting for approval`,source:r.agent,kind:"approval",status:"pending",lastSeenAt:e});t.push({...i,project:s,instance:Ud(n)})}}return t}async listAiSessionInstanceNames(){return(await this.nodeAgentGateway.listFleetInstances(this.listNodes())).items.map(e=>({id:e.id,name:e.name}))}resolveAiSessionApproval(e,t,n){return this.aiSessionActionService.resolveApproval(e,t,n)}listAiSessionHistory(e){return this.aiSessionActionService.listHistory(e)}getAiSessionHistoryDetail(e,t){return this.aiSessionActionService.historyDetail(e,t)}getAiSessionTimeline(e,t){return this.aiSessionActionService.timeline(e,t)}getAiSessionTurnTimeline(e,t,n){return this.aiSessionActionService.turnTimeline(e,t,n)}resumeAiSession(e,t){return this.aiSessionActionService.resume(e,t)}async createAiSession(e,t){const n=await this.requireControlledInstance(e,!0),{cwdFolderId:i,...s}=t,r={type:"runtime-path",path:t.cwdFolderId?await this.runtimeCwdForFolderId(n,t.cwdFolderId):n.runtime.workspacePath||n.workspace.path||Bd(n.source).path||"/workspace"};return this.aiSessionActionService.create(e,{...s,cwd:r,...t.cwdFolderId?{cwdFolderId:t.cwdFolderId}:{}})}async inspectAiSessionWorkspace(e,t){const n=await this.requireControlledInstance(e,!0),i={type:"runtime-path",path:await this.runtimeCwdForFolderId(n,t)};return this.aiSessionActionService.inspectWorkspace(e,i)}forkAiSession(e,t,n){return this.aiSessionActionService.fork(e,t,n)}openAiSessionApp(e,t,n){return this.aiSessionActionService.openApp(e,t,n)}closeAiSession(e,t,n){return this.aiSessionActionService.close(e,t,n)}aiSessionActionDiagnostics(){return this.aiSessionActionService.diagnostics()}async launchAppSession(e,t="terminal-tty",n={}){const i=await this.requireControlledInstance(e,!0);if("online"!==i.connectionStatus&&"online"!==i.agentStatus){const e=new Error(`Instance ${i.name} is still starting. Wait for it to connect before launching apps.`);throw Object.assign(e,{statusCode:409,code:"INSTANCE_NOT_CONNECTED"}),e}const s=await this.resolveAppLaunchOptions(i,n),r=await this.instanceRequest(i,"/apps/sessions",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({appId:t,...s})});return await this.listAppSessions({refresh:!0}),r}async stopAppSession(e,t){const n=await this.requireControlledInstance(e,!0),i=await this.instanceRequest(n,`/apps/sessions/${encodeURIComponent(t)}/stop`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});return await this.listAppSessions({refresh:!0}),i}async instanceAppManagement(e){const t=await this.requireControlledInstance(e,!0);try{return function(e){try{return Uo(ms,e)}catch(e){if(e instanceof a.z.ZodError){const e=new Error("This controlled instance does not support managed app operations.");throw Object.assign(e,{statusCode:409,code:"INSTANCE_APP_MANAGEMENT_UNSUPPORTED"}),e}throw e}}(await this.instanceRequest(t,"/apps/management"))}catch(e){const t=e&&"object"==typeof e?e:{};if(e instanceof a.z.ZodError||404===t.statusCode){const e=new Error("This controlled instance does not support managed app operations.");throw Object.assign(e,{statusCode:409,code:"INSTANCE_APP_MANAGEMENT_UNSUPPORTED"}),e}throw e}}async requestInstanceAppOperation(e,t,n,i={}){const s=await this.requireControlledInstance(e,!0);return Uo(hs,await this.instanceRequest(s,`/apps/${encodeURIComponent(t)}/${n}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(i)}))}async instanceAppManagementJob(e,t){const n=await this.requireControlledInstance(e,!0);return Uo(hs,await this.instanceRequest(n,`/apps/jobs/${encodeURIComponent(t)}`))}async renameAppSession(e,t,n){const i=await this.requireControlledInstance(e,!0),s=await this.instanceRequest(i,`/apps/sessions/${encodeURIComponent(t)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({title:n})});return await this.listAppSessions({refresh:!0}),s}sendAiSessionMessage(e,t,n,i,s=[],r=[],o){return this.aiSessionActionService.sendMessage(e,t,n,i,s,r,o)}aiSessionMentionCatalog(e,t){return this.aiSessionActionService.mentionCatalog(e,t)}searchAiSessionMentionFiles(e,t,n){return this.aiSessionActionService.searchMentionFiles(e,t,n)}executeAiSessionCommand(e,t,n){return this.aiSessionActionService.executeCommand(e,t,n)}aiSessionQueue(e,t){return this.aiSessionActionService.queue(e,t)}steerAiSessionQueuedMessage(e,t,n){return this.aiSessionActionService.steerQueuedMessage(e,t,n)}retryAiSessionQueuedMessage(e,t,n){return this.aiSessionActionService.retryQueuedMessage(e,t,n)}removeAiSessionQueuedMessage(e,t,n){return this.aiSessionActionService.removeQueuedMessage(e,t,n)}editAiSessionQueuedMessage(e,t,n,i){return this.aiSessionActionService.editQueuedMessage(e,t,n,i)}reorderAiSessionQueuedMessages(e,t,n){return this.aiSessionActionService.reorderQueuedMessages(e,t,n)}interruptAiSession(e,t){return this.aiSessionActionService.interrupt(e,t)}async proxyInstanceHttp(e,t,n={}){const i=await this.requireControlledInstance(e,!0);return this.controlledInstanceGateway.proxyHttp(i,t,n)}async proxyInstanceWebSocket(e,t,n,i,s={}){const r=await this.requireControlledInstance(e,!0);this.controlledInstanceGateway.proxyWebSocket(r,t,n,i,s)}async instanceConfigSyncState(e){const t=await this.requireControlledInstance(e,!0),n=a.z.array(Ko).parse(await this.instanceRequest(t,"/config-sync/programs"));return Qo.parse({programs:n,preferences:this.configSyncPreferences.get(e)?.preferences||ep()})}async listInstanceConfigSyncFolders(e,t={}){const n=await this.requireControlledInstance(e,!0),i=new URLSearchParams;return t.path&&i.set("path",t.path),void 0!==t.depth&&i.set("depth",String(t.depth)),a.z.array(_r).parse(await this.instanceRequest(n,"/config-sync/folders"+(i.size?`?${i}`:"")))}async syncInstanceConfigs(e,t){const n=Jo.parse(t),i=await this.requireControlledInstance(e,!0);if("export"===n.direction&&"local-folder"!==i.source.type){const e=new Error("Exporting instance config is only available for local folder projects.");throw Object.assign(e,{statusCode:400,code:"CONFIG_SYNC_EXPORT_REQUIRES_LOCAL_PROJECT"}),e}const s=function(e){const t=function(e){const t=[];for(const n of e.split("/"))if(n&&"."!==n)if(".."===n){if(!t.length)return"..";t.pop()}else t.push(n);return t.join("/")||"."}(e.trim().replace(/\\/g,"/")||".");if(t.startsWith("/")||".."===t||t.startsWith("../")){const e=new Error("Config sync folder must stay inside the instance workspace.");throw Object.assign(e,{statusCode:400,code:"CONFIG_SYNC_FOLDER_INVALID"}),e}return t||"."}(n.workspaceFolder),r={...n,workspaceFolder:s},o=Uo(ea,await this.instanceRequest(i,"/config-sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})),a=Hd(),d=this.configSyncPreferences.get(e);return this.configSyncPreferences.put({id:e,preferences:{...d?.preferences||ep(),[n.direction]:s},createdAt:d?.createdAt||a,updatedAt:a}),o}async instanceRequest(e,t,n={}){return this.controlledInstanceGateway.request(e,t,n)}async reportInstanceHeartbeat(e,t){await this.controlledInstanceGateway.reportHeartbeat(e,t)}async nodeAgentFetch(e,t,n={}){const i="reverse-wss"!==e.connectionMode&&"control-plane-proxy"!==e.connectionMode;try{const s=await this.nodeAgentTransportResolver.resolve(e).request(e,t,n);return i&&this.nodeConnectionRuntime?.observedReachable(e),s}catch(t){throw!i||n.signal?.aborted||function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(t)||this.nodeConnectionRuntime?.observedFailure(e,Vd(t)),t}}async listNodeInstances(){return(await this.listNodeInstancesWithDiagnostics()).items}async listNodeInstancesWithDiagnostics(e){return this.nodeAgentGateway.listFleetInstances(this.listNodes().map(e=>this.projectNodeConnection(e)),{signal:e})}async requireNodeInstance(e){for(const t of this.listNodes())try{const n=(await this.nodeAgentGateway.listInstances(t)).find(t=>t.id===e);if(n)return n}catch{}Kd("CONTROLLED_INSTANCE_NOT_FOUND",`Controlled instance ${e} was not found.`)}async requireNodeRuntimeOnNode(e,t){const n=(await this.listNodeRuntimes(e)).find(e=>e.id===t);return n||Kd("NODE_RUNTIME_NOT_FOUND",`Runtime ${t} was not found on node ${e}.`),n}async requireNodeLocalFolder(e,t){return this.nodeAgentGateway.requireLocalFolder(e,t)}async resolveAppLaunchOptions(e,t){const n="string"==typeof t.cwdFolderId?t.cwdFolderId.trim():"",i={...t};return delete i.cwdFolderId,n?{...i,cwd:await this.runtimeCwdForFolderId(e,n)}:i}async runtimeCwdForFolderId(e,t){const n=this.requireNode(e.nodeId),i=await this.requireNodeLocalFolder(n,t);if(i.nodeId!==e.nodeId){const t=new Error(`Local folder ${i.id} belongs to node ${i.nodeId}, not ${e.nodeId}.`);throw Object.assign(t,{statusCode:400,code:"LOCAL_FOLDER_REQUIRES_INSTANCE_NODE"}),t}const s=await this.requireNodeRuntimeOnNode(e.nodeId,e.runtimeId);return this.appLaunchCwdForFolder(e,i,s)}appLaunchCwdForFolder(e,n,i){const s=function(e,n,i){if("local"===i.type)return np(s=n).resolve(s);var s;if("local-folder"!==e.source.type)return;const r=function(e,t){if(tp(e)!==tp(t))return;const n=np(e),i=n.resolve(e),s=n.resolve(t),r=n.relative(i,s);return r?".."===r||r.startsWith(`..${n.sep}`)||n.isAbsolute(r)?void 0:r.split(n.sep).filter(Boolean):[]}(e.source.path,n);if(!r)return;const o=e.runtime.workspacePath||e.workspace.path||Bd(e.source).path||"/workspace";return r.length?t.posix.join(o,...r):o}(e,n.path,i);if(s)return s;if("local-folder"!==e.source.type){const e=new Error("App cwd folder selection is only supported for local-folder instances.");throw Object.assign(e,{statusCode:400,code:"APP_CWD_REQUIRES_LOCAL_FOLDER_SOURCE"}),e}const r=new Error(`Local folder ${n.path} is outside the instance workspace ${e.source.path}.`);throw Object.assign(r,{statusCode:400,code:"APP_CWD_OUTSIDE_WORKSPACE"}),r}requireProject(e){return this.catalogService.requireProject(e)}requireModel(e,t=!1){return this.modelService.require(e,t)}requireImage(e){return this.catalogService.requireImage(e)}requireNode(e){const t=this.nodes.get(e);return t||Kd("NODE_NOT_FOUND",`Node ${e} was not found.`),t}requirePublicNode(e){return $d(this.projectNodeConnection(this.requireNode(e)))}async requireControlledInstance(e,t=!1){const n=await this.requireNodeInstance(e);return t?n:Ud(n)}}function cp(e){return g(String(e),"escape").replace(/\n+$/,"")}function lp(e){const[t,...n]=String(e).split("\n");return[`*${cp(t)}*`,...n.map(cp)].join("\n")}function pp(e,t=4e3){const n=String(e),i=lp(n);if(i.length<=t)return i;const[s,...r]=n.split("\n"),o=r.join("\n"),a="...\n";let d=s;for(;lp(`${d}\n${a}`).length>t&&d.length>0;)d=d.slice(0,Math.floor(.8*d.length));let c=0,l=o.length,p=0,u=lp(`${d}\n${a}`);for(;c<=l;){const e=Math.floor((c+l)/2),n=lp(`${d}\n${a}${o.slice(-e)}`);n.length<=t?(u=n,p=e,c=e+1):l=e-1}const m=o.slice(-p),g=m.indexOf("\n");return g>=0&&g<200&&(u=lp(`${d}\n${a}${m.slice(g+1)}`)),u}function up(e){return String(e).replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g,"$1")}async function mp(e,t,n,i,s={}){if(!t.token)return;const r=n=>e(`https://api.telegram.org/bot${t.token}/sendMessage`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)}),o=function(e,t={}){const n=String(e),i=t.rawMarkdownV2?e=>e:cp;if(i(n).length<=4e3)return[n];const s=[];let r=n;for(;r;){let e=1,t=r.length,n=1;for(;e<=t;){const s=Math.floor((e+t)/2);i(r.slice(0,s)).length<=4e3?(n=s,e=s+1):t=s-1}if(n<r.length){const e=r.slice(0,n),t=Math.max(e.lastIndexOf("\n"),e.lastIndexOf(" "));t>=Math.floor(.6*n)&&(n=t+1)}s.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return s.filter(Boolean)}(i,s);let a;for(const[e,t]of o.entries())a=await hp(r,"sendMessage",t,{chat_id:n,...0===e&&s.replyToMessageId?{reply_to_message_id:s.replyToMessageId,allow_sending_without_reply:!0}:{},...e===o.length-1&&s.replyMarkup?{reply_markup:s.replyMarkup}:{}},s);return a}async function gp(e,t,n){if(!t.token||!n)throw new Error("Telegram file id is required.");const i=await e(`https://api.telegram.org/bot${t.token}/getFile`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({file_id:n})}),s=await i.json().catch(()=>({}));if(!i.ok||!1===s.ok||!s.result?.file_path)throw new Error(s.description||`Telegram getFile failed with HTTP ${i.status}`);return`https://api.telegram.org/file/bot${t.token}/${s.result.file_path}`}async function hp(e,t,n,i,s){const r=s.parseMode||"MarkdownV2",o=s.rawMarkdownV2?String(n):cp(n),a=await e({...i,text:o,disable_web_page_preview:!0,parse_mode:r}),d=await a.json().catch(()=>({}));if(a.ok&&!1!==d.ok)return d.result;if("editMessageText"===t&&yp(d.description))return;if(s.rawMarkdownV2&&"MarkdownV2"===r){const s=await e({...i,text:up(n),disable_web_page_preview:!0,parse_mode:"Markdown"}),r=await s.json().catch(()=>({}));if(s.ok&&!1!==r.ok)return r.result;if("editMessageText"===t&&yp(r.description))return}const c=await e({...i,text:s.rawMarkdownV2?up(n):String(n),disable_web_page_preview:!0}),l=await c.json().catch(()=>({}));if(c.ok&&!1!==l.ok)return l.result;if("editMessageText"!==t||!yp(l.description))throw new Error(l.description||d.description||`Telegram ${t} failed with HTTP ${c.status}`)}function yp(e){return"string"==typeof e&&e.toLowerCase().includes("message is not modified")}function fp(e,t){if("string"==typeof e&&e.trim())return e.trim();bp(`Chat action token is missing ${t}.`)}function Ip(e){if("allow"===e||"deny"===e||"skip"===e)return e;bp("Chat action token has an invalid decision.")}function bp(e){const t=new Error(e);throw Object.assign(t,{statusCode:400,code:"CHAT_ACTION_TOKEN_INVALID"}),t}function vp(e){return Buffer.from(e,"base64url").toString("utf8")}function wp(e){return String(e||"").split(/\r?\n/,1)[0].replace(/^#+\s*/,"").trim().slice(0,20)||"消息通知"}function Sp(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,"string"==typeof t?t:JSON.stringify(t)]))}function Ap(e){return`dtv1.card//IM_GROUP.${e}`}function kp(e){return`dtv1.card//IM_ROBOT.${e}`}function zp(e,t){return $p(t.biz_conversation_id).trim()||$p(e.spaceId).replace(/^dtv1\.card\/\/(?:IM_GROUP|IM_SINGLE|IM_ROBOT)\./,"")}function Tp(e,t={}){const n=$p(e).trim().toUpperCase();return"2"===n||"IM_GROUP"===n?"IM_GROUP":"1"===n||"IM_SINGLE"===n?t.robotMessage?"IM_ROBOT":"IM_SINGLE":"IM_ROBOT"===n?"IM_ROBOT":void 0}function Ep(e){if(e.startsWith("task_handoff:"))return e;if(!e.startsWith("th_cb_"))return"";try{return Buffer.from(e.slice(6),"base64url").toString("utf8")}catch{return""}}function Cp(e,t,n,i,s){const r=zp(i,s);return{cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},cardData:{cardParamMap:Sp({type:"actions",title:"TaskHandoff",description:e,list:El(t),biz_out_track_id:i.outTrackId||s.biz_out_track_id||"",biz_conversation_id:r,biz_sender_id:s.biz_sender_id||i.userId||"",biz_session_webhook:s.biz_session_webhook||"",biz_conversation_type:s.biz_conversation_type||"",biz_step:n,error_msg:""})}}}function xp(e,t,n){const i=[];return Np(i,n),Np(i,t),Np(i,e),i.find(e=>Ep(e))||""}function Np(e,t){for(const n of["actionIdList","actionIds"]){const i=t[n];Array.isArray(i)&&e.push(...i.map(e=>$p(e)).filter(Boolean))}for(const n of["actionId","action_id","id","actionValue"]){const i=$p(t[n]);i&&e.push(i)}}async function Op(e,t,n,i){i?.("info",{target:"sessionWebhook",hasSessionWebhook:Boolean(t),textPreview:Mp(n)},"dingding webhook send requested");const s=await e(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({msgtype:"markdown",markdown:{title:wp(n),text:n}})}),r=await s.json().catch(()=>{});if(i?.(s.ok?"info":"warn",{target:"sessionWebhook",status:s.status,response:Dp(r)},"dingding webhook send completed"),!s.ok)throw new Error(`DingDing webhook failed with HTTP ${s.status}`)}async function _p(e){const t=El(e.replyMarkup);if(!t.length&&!e.forceCard)return e.sessionWebhook&&await Op(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),e.sessionWebhook?{delivered:!0}:void 0;const n=e.bridge.settings||{},i=$p(n.robotCode),s=$p(n.cardTemplateId)||"13fc6717-12e4-43ed-8533-111a310d4995.schema",r=$p(n.cardCallbackRouteKey)||"task_handoff_message",o=e.senderId||e.runtime.senderIds.get(e.chatId)||$p(n.senderId),a=(d=e.runtime,c=e.chatId,d.conversationTypes?.get(c)||"IM_GROUP");var d,c;if(!i||!s||!o){if(e.sessionWebhook&&!e.forceCard)return await Op(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),{delivered:!0};throw new Error("DingDing card target is incomplete.")}const l=`task_handoff_cp_${Date.now()}_${Math.random().toString(16).slice(2)}`,p=Sp({type:"actions",title:e.title||wp(e.text),description:e.text,list:t,biz_out_track_id:l,biz_step:e.step||"task_handoff_actions",biz_conversation_id:e.chatId,biz_sender_id:o,biz_session_webhook:e.sessionWebhook||e.runtime.chatWebhooks.get(e.chatId)||"",biz_conversation_type:a,error_msg:""}),u=function(e,t,n,i){return"IM_SINGLE"===e?{openSpaceId:(s=t,`dtv1.card//IM_SINGLE.${s}`),imSingleOpenSpaceModel:{},imSingleOpenDeliverModel:{extension:{}}}:"IM_ROBOT"===e?{openSpaceId:kp(n),imRobotOpenSpaceModel:{supportForward:!1},imRobotOpenDeliverModel:{extension:{},robotCode:i,spaceType:"IM_ROBOT"}}:{openSpaceId:Ap(t),imGroupOpenSpaceModel:{supportForward:!1},imGroupOpenDeliverModel:{extension:{},robotCode:i}};var s}(a,e.chatId,o,i);return e.runtime.onLog?.("info",{target:"card",chatId:e.chatId,senderId:o,conversationType:a,openSpaceId:u.openSpaceId,hasSessionWebhook:Boolean(e.sessionWebhook||e.runtime.chatWebhooks.get(e.chatId)),hasReplyMarkup:Boolean(e.replyMarkup),actionCount:t.length,textPreview:Mp(e.text)},"dingding card send requested"),await Rp(e.fetchImpl,e.bridge,e.runtime,"POST","/v1.0/card/instances/createAndDeliver",{userId:o,cardTemplateId:s,outTrackId:l,callbackType:"STREAM",callbackRouteKey:r,cardData:{cardParamMap:p},userIdType:Number(n.cardUserIdType||1),...u}),{delivered:!0,outTrackId:l}}async function Rp(e,t,n,i,s,r){const o=await async function(e,t,n){if(n.accessToken&&n.accessToken.expiresAt>Date.now()+6e4)return n.accessToken.value;const i=$p(t.settings.clientSecret);if(!t.token||!i)throw new Error("DingDing client id/secret is not configured.");const s=await e("https://api.dingtalk.com/v1.0/oauth2/accessToken",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({appKey:t.token,appSecret:i})}),r=await s.json().catch(()=>({}));if(!s.ok||!r.accessToken)throw new Error(`DingDing access token failed with HTTP ${s.status}`);const o=Number(r.expireIn||7200);return n.accessToken={value:r.accessToken,expiresAt:Date.now()+1e3*Math.max(60,o-120)},n.accessToken.value}(e,t,n);n.onLog?.("info",{method:i,path:s,body:Pp(r)},"dingding api request");const a=await e(`https://api.dingtalk.com${s}`,{method:i,headers:{"content-type":"application/json","x-acs-dingtalk-access-token":o},body:JSON.stringify(r)}),d=await a.json().catch(()=>{});if(n.onLog?.(a.ok?"info":"warn",{method:i,path:s,status:a.status,response:Dp(d)},"dingding api response"),!a.ok)throw new Error(`DingDing API failed with HTTP ${a.status}`);const c=Lp(d),l=c.code??c.errcode,p=c.success;if(void 0!==l&&"0"!==String(l)||!1===p)throw new Error($p(c.message||c.errmsg)||`DingDing API returned ${String(l||"failure")}`);const u=function(e){const t=Lp(Lp(e).result).deliverResults;if(!Array.isArray(t))return"";const n=t.find(e=>!1===Lp(e).success);if(!n)return"";const i=Lp(n),s=$p(i.spaceId),r=$p(i.errorMsg||i.message||i.errmsg)||"delivery failed";return s?`DingDing card delivery failed for ${s}: ${r}`:`DingDing card delivery failed: ${r}`}(d);if(u)throw new Error(u);return a}function Pp(e){const t=Lp(e),n=Lp(t.cardData),i=Lp(n.cardParamMap);return{openSpaceId:$p(t.openSpaceId),outTrackId:$p(t.outTrackId),userId:$p(t.userId),userIdType:t.userIdType,callbackType:$p(t.callbackType),callbackRouteKey:$p(t.callbackRouteKey),hasImGroupTarget:Boolean(t.imGroupOpenSpaceModel||t.imGroupOpenDeliverModel),hasImSingleTarget:Boolean(t.imSingleOpenSpaceModel||t.imSingleOpenDeliverModel),hasImRobotTarget:Boolean(t.imRobotOpenSpaceModel||t.imRobotOpenDeliverModel),imGroupOpenDeliverModel:jp(t.imGroupOpenDeliverModel),imSingleOpenDeliverModel:jp(t.imSingleOpenDeliverModel),imRobotOpenDeliverModel:jp(t.imRobotOpenDeliverModel),bizConversationId:$p(i.biz_conversation_id),bizConversationType:$p(i.biz_conversation_type),bizSenderId:$p(i.biz_sender_id),hasBizSessionWebhook:Boolean($p(i.biz_session_webhook))}}function jp(e){const t=Lp(e);if(Object.keys(t).length)return{hasExtension:Boolean(t.extension),hasRobotCode:Boolean($p(t.robotCode)),spaceType:$p(t.spaceType),recipients:Array.isArray(t.recipients)?t.recipients.length:void 0,atUserIds:t.atUserIds&&"object"==typeof t.atUserIds?Object.keys(t.atUserIds).length:void 0}}function Dp(e){const t=Lp(e),n=Lp(t.result);return{code:t.code??t.errcode,message:Mp(t.message||t.errmsg,240),success:t.success,requestId:t.requestId,result:Object.keys(n).length?n:void 0}}function Mp(e,t=160){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function Lp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function qp(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:"string"==typeof e&&e.trim()?Bp(e):{}}function $p(e){return"string"==typeof e?e:""}function Bp(e){try{return Lp(JSON.parse(String(e||"{}")))}catch{return{}}}function Up(e){return JSON.stringify(El(e))}const Fp="task_handoff_action_id";function Hp(e,t){const n=El(t);return{schema:"2.0",config:{summary:{content:Vp(e)}},body:{elements:[{tag:"markdown",content:e},...n.map(e=>({tag:"button",text:{tag:"plain_text",content:e.text},type:Kp(e.text),width:"fill",size:"medium",behaviors:[{type:"callback",value:{[Fp]:e.id}}]}))]}}}function Wp(e){const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e);return function(e){const t=String(e||"");return t.startsWith("th_cb_")?function(e){try{return Buffer.from(e,"base64url").toString("utf8")}catch{return""}}(t.slice(6)):""}(t[Fp]||t.action_id||t.actionId||t.id||e)}function Gp(e){return JSON.stringify(El(e))}function Vp(e){const t=e.replace(/\s+/g," ").trim();return t.length<=50?t:`${t.slice(0,47)}...`}function Kp(e){const t=e.trim().toLowerCase();return["deny","cancel","delete","remove"].some(e=>t.includes(e))?"danger":["allow","approve","launch","open"].some(e=>t.includes(e))?"primary":"default"}function Jp(e){return e instanceof Error?e.message:String(e)}function Yp(e){const t=Number(function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e).message_id);return Number.isInteger(t)&&t>0?t:void 0}function Qp(e){return Array.isArray(e?.actionRows)?e.actionRows:(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e])}function Xp(e,t){const n=Qp(e),i=Qp(t);return n.length===i.length&&n.every((e,t)=>{const n=i[t];return e.length===n.length&&e.every((e,t)=>{const i=n[t];return e.text===i?.text&&e.callbackData===i.callbackData})})}class Zp{entries;updateIntervalMs;send;edit;deleteMessage;messageIdFromResult;retryAfterMs;isMessageTooLong;onLog;constructor(e){this.entries=e.entries||new Map,this.updateIntervalMs=e.updateIntervalMs||1e3,this.send=e.send,this.edit=e.edit,this.deleteMessage=e.delete,this.messageIdFromResult=e.messageIdFromResult||Yp,this.retryAfterMs=e.retryAfterMs,this.isMessageTooLong=e.isMessageTooLong,this.onLog=e.onLog}remember(e,t,n,i,s,r){const o=this.entries.get(e);return o&&(clearTimeout(o.timer),o.timer=void 0,o.pendingText=void 0),this.entries.set(e,{lastText:n,lastUpdateAt:Date.now(),messageId:t,route:i,options:s,lastOptions:s,renderOptions:r}),o}rekey(e,t){if(e===t)return this.entries.has(e);const n=this.entries.get(e);if(!n||this.entries.has(t))return!1;if(clearTimeout(n.timer),n.timer=void 0,this.entries.delete(e),this.entries.set(t,n),n.pendingText){const e=n.rateLimitedUntil?Math.max(0,n.rateLimitedUntil-Date.now()):Math.max(0,this.updateIntervalMs-(Date.now()-n.lastUpdateAt));this.scheduleFlush(t,e)}return!0}scheduleFlush(e,t){const n=this.entries.get(e);n&&!n.timer&&(n.timer=setTimeout(()=>{n.timer=void 0;const t=n.pendingText;n.pendingText=void 0,t&&this.applyUpdate(e,t,n.route,n.options)},t))}markRateLimited(e,t,n,i){const s=this.entries.get(e);s&&(s.rateLimitedUntil=Date.now()+n,s.pendingText=t,s.route=i||s.route,this.scheduleFlush(e,n))}async applyUpdate(e,t,n,i){let s=this.entries.get(e);const r=s,o=n||s?.route,a=i||s?.options;try{if(s&&(s.route=o,s.options=a),s?.pending&&await s.pending,s=this.entries.get(e),r&&s!==r)return!1;if(s?.messageId){if(s.lastText===t&&Xp(s.lastOptions,a))return!0;const n=Date.now()-(s.lastUpdateAt||0);return n<this.updateIntervalMs?(s.pendingText=t,s.route=o||s.route,s.options=a||s.options,this.scheduleFlush(e,this.updateIntervalMs-n),!0):(await this.edit(s.messageId,t,o||s.route,a),s.lastText=t,s.lastOptions=a,s.lastUpdateAt=Date.now(),s.rateLimitedUntil=void 0,!0)}const n={lastText:t,lastUpdateAt:Date.now(),route:o,options:a,lastOptions:a};return n.pending=this.send(t,o,a).then(e=>{const t=this.messageIdFromResult(e);t&&(n.messageId=t)}).finally(()=>{n.pending=void 0}),this.entries.set(e,n),await n.pending,this.entries.get(e)===n&&(n.rateLimitedUntil=void 0,Boolean(n.messageId))}catch(n){const i=this.retryAfterMs?.(n);return i&&this.markRateLimited(e,t,i,o),this.onLog?.(`Telegram progress update skipped: ${Jp(n)}`),!1}}update(e,t,n,i){const s=String(t||"").trim();if(!s)return;const r=this.entries.get(e);if(r&&(r.route=n||r.route,r.options=i||r.options),r?.lastText===s&&Xp(r.lastOptions,i||r.options)&&!r.pending&&!r.pendingText)return;const o=Date.now();if(r?.rateLimitedUntil){if(r.rateLimitedUntil>o)return r.pendingText=s,void this.scheduleFlush(e,r.rateLimitedUntil-o);r.rateLimitedUntil=void 0}if(r?.pending&&!r.messageId)return r.pendingText=s,void this.scheduleFlush(e,this.updateIntervalMs);if(!r||!r.messageId)return void this.applyUpdate(e,s,n,i);const a=Date.now()-(r.lastUpdateAt||0);if(a>=this.updateIntervalMs)return clearTimeout(r.timer),r.timer=void 0,r.pendingText=void 0,void this.applyUpdate(e,s,n||r.route,i||r.options);r.pendingText=s,this.scheduleFlush(e,this.updateIntervalMs-a)}async finish(e,t,n,i,s){const r=this.entries.get(e);if(!r)return!1;try{if(clearTimeout(r.timer),r.timer=void 0,r.pendingText=void 0,r.pending&&await r.pending,this.entries.delete(e),!r.messageId)return!1;const o=i||r.options;return r.lastText===t&&Xp(r.lastOptions,o)||await this.edit(r.messageId,t,n||r.route,o,s||r.renderOptions),!0}catch(t){return this.entries.delete(e),this.isMessageTooLong?.(t)?this.onLog?.("Telegram progress finish too long; sending result as multiple messages"):this.onLog?.(`Telegram progress finish skipped: ${Jp(t)}`),!1}}async delete(e,t){const n=this.entries.get(e);if(!n)return!1;try{return clearTimeout(n.timer),n.timer=void 0,n.pendingText=void 0,n.pending&&await n.pending,this.entries.delete(e),!(!this.deleteMessage||!n.messageId)&&(await this.deleteMessage(n.messageId,t||n.route),!0)}catch(t){return this.entries.delete(e),this.onLog?.(`Telegram progress delete skipped: ${Jp(t)}`),!1}}async flush(e){const t=this.entries.get(e);if(t?.pending&&await t.pending,t?.timer){clearTimeout(t.timer),t.timer=void 0;const n=t.pendingText;t.pendingText=void 0,n&&await this.applyUpdate(e,n,t.route,t.options)}}async wait(e){await function(e){return new Promise(t=>setTimeout(t,e))}(e)}}const eu=20971520;function tu(e){const t=[],n=[...e.photo||[]].filter(e=>e.file_id).sort((e,t)=>Number(t.file_size||t.width||0)-Number(e.file_size||e.width||0))[0];return n?.file_id&&t.push({fileId:n.file_id,fileName:"telegram-photo.jpg",fileSize:n.file_size}),e.document?.file_id&&String(e.document.mime_type||"").startsWith("image/")&&t.push({fileId:e.document.file_id,fileName:e.document.file_name,fileSize:e.document.file_size}),t}async function nu(e,n,i="telegram-image",s){if(s&&s>eu)throw new Error(`image is too large: ${s} bytes`);const r=await e.getFileLink(n),o=String(r),a=await(e.fetchFile||fetch)(o);if(!a.ok)throw new Error(`download failed with HTTP ${a.status}`);const d=Number(a.headers.get("content-length")||0);if(d>eu)throw new Error(`image is too large: ${d} bytes`);const c=t.extname(i)||".jpg";let l=c;try{l=t.extname(new URL(o).pathname)||c}catch{l=c}const p=t.join(y.tmpdir(),"task-handoff-images");await h.mkdir(p,{recursive:!0});const u=l.replace(/[^.\w-]/g,"")||".jpg",m=t.join(p,`telegram-${Date.now()}-${Math.random().toString(16).slice(2)}${u}`),g=Buffer.from(await a.arrayBuffer());if(g.length>eu)throw new Error(`image is too large: ${g.length} bytes`);return await h.writeFile(m,g),m}class iu{store;constructor(e){this.store=new Zp({updateIntervalMs:e.updateIntervalMs,send:(t,n,i)=>e.send(e.requireBridge(n?.bridgeId||""),n?.chatId||"",pp(t),{rawMarkdownV2:!0,replyMarkup:cu(i)}),edit:(t,n,i,s)=>e.edit(e.requireBridge(i?.bridgeId||""),i?.chatId||"",t,pp(n),{rawMarkdownV2:!0,replyMarkup:cu(s)}),delete:(t,n)=>e.deleteMessage(e.requireBridge(n?.bridgeId||""),n?.chatId||"",t),onLog:e.onLog})}get entries(){return this.store.entries}remember(e,t,n,i){return this.store.remember(e,t,n,i)}rekey(e,t){return this.store.rekey(e,t)}delete(e){return this.store.delete(e)}async applyUpdate(e){return this.store.applyUpdate(e.key,e.text,{bridgeId:e.bridge.id,chatId:e.chatId},{actionRows:e.actionRows})}}async function su(e){return(await async function(e,t,n,i){const s=[];for(const r of tu(n))try{const n=await nu({getFileLink:n=>gp(e,t,n),fetchFile:e},r.fileId,r.fileName,r.fileSize);s.push(n)}catch(e){i?.({fileId:r.fileId,fileName:r.fileName,error:e})}return s}(e.fetchImpl,e.bridge,e.message,e.onImageDownloadError)).map((e,s)=>{const r=n.readFileSync(e);return{id:`tg_${i.randomUUID().replace(/-/g,"").slice(0,24)}`,kind:"image",name:t.basename(e)||`telegram-image-${s+1}`,mime:ru(e),size:r.length,source:{type:"inline",encoding:"base64",data:r.toString("base64")}}})}function ru(e){const n=t.extname(e).toLowerCase();return".png"===n?"image/png":".webp"===n?"image/webp":".gif"===n?"image/gif":".bmp"===n?"image/bmp":"image/jpeg"}function ou(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function au(e){return e&&"object"==typeof e?e:{}}function du(e){return"string"==typeof e?e:""}function cu(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return kl(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function lu(e){const t=Array.isArray(e.item_list)?e.item_list:[];for(const e of t){const t=pu(e);if(1!==t.type)continue;const n=uu(pu(t.text_item).text).trim();if(n)return n}return""}function pu(e){return e&&"object"==typeof e?e:{}}function uu(e){return"string"==typeof e?e:""}function mu(e){const{fetchImpl:t,bridge:n,dingdingRuntime:s,larkRuntime:r}=e;return"telegram"===n.channel?function(e,t){return{bridge:t,send:async(n,i,s={})=>{const r=await mp(e,t,n,i,{replyMarkup:s.replyMarkup,replyToMessageId:s.replyToMessageId,rawMarkdownV2:s.rawMarkdownV2,parseMode:s.parseMode});return{provider:"telegram",raw:r,messageId:Number(au(r).message_id)||void 0}}}}(t,n):"dingding"===n.channel?function(e,t,n){return{bridge:t,send:async(i,s,r={})=>{const o=r.sessionWebhook||n?.chatWebhooks.get(i)||$p(t.settings.sessionWebhook);if(r.replyMarkup&&n){const a=await _p({fetchImpl:e,bridge:t,runtime:n,chatId:i,text:s,replyMarkup:r.replyMarkup,sessionWebhook:o,senderId:r.senderId||n.senderIds.get(i)||$p(t.settings.senderId)});if(a?.delivered)return{provider:"dingding",interactionId:a.outTrackId}}if(o)return await Op(e,o,s,n?.onLog),{provider:"dingding"}}}}(t,n,s):"lark"===n.channel?function(e,t){return{bridge:e,send:async(e,n,i={})=>{if(!t)return;const s=await t.channel.send(e,i.replyMarkup?{card:Hp(n,i.replyMarkup)}:{markdown:n});return{provider:"lark",interactionId:s.messageId,raw:s}}}}(n,r):"wechat"===n.channel?function(e,t){return{bridge:t,send:async(n,s,r={})=>{const o=r.contextToken||uu(t.settings.contextToken);if(o)return await async function(e,t,n,s,r){const o=uu(t.settings.baseUrl)||"https://ilinkai.weixin.qq.com",a=await e(`${o}/ilink/bot/sendmessage`,{method:"POST",headers:{"content-type":"application/json",AuthorizationType:"ilink_bot_token",Authorization:`Bearer ${t.token}`,"X-WECHAT-UIN":String(Math.floor(Math.random()*2**31))},body:JSON.stringify({msg:{from_user_id:"",to_user_id:n,client_id:i.randomUUID(),message_type:2,message_state:2,context_token:s,item_list:[{type:1,text_item:{text:r}}]},base_info:{channel_version:"1.0.2"}})}),d=await a.json().catch(()=>({}));if(!a.ok||d.errcode)throw new Error(uu(d.errmsg)||`WeChat send failed with HTTP ${a.status}`)}(e,t,n,o,s),{provider:"wechat"}}}}(t,n):{bridge:n,send:async()=>{}}}class gu{entries=new Map;fetchImpl;generations=new Map;constructor(e){this.fetchImpl=e}clear(){for(const e of new Set([...this.generations.keys(),...[...this.entries.values()].map(e=>e.bridgeId)]))this.clearBridge(e)}clearBridge(e){this.generations.set(e,this.generation(e)+1),this.clearEntries(t=>t.bridgeId===e)}generation(e){return this.generations.get(e)||0}isCurrent(e,t){return this.generation(e)===t}clearEntries(e){for(const[t,n]of this.entries)e(n)&&(n.timer&&clearTimeout(n.timer),n.cancelPending?.(new Error("DingDing progress update was cancelled.")),this.entries.delete(t))}async applyUpdate(e,t){const n=this.generation(e.bridge.id),i=Up(e.replyMarkup);let s=this.entries.get(e.key);if(s?.pending&&await s.pending,!this.isCurrent(e.bridge.id,n))return!1;if(s=this.entries.get(e.key),s?.outTrackId){if(s.lastText===e.text&&s.lastActionsFingerprint===i)return!0;const r=Date.now()-(s.lastUpdateAt||0);return r<1e3?(s.pendingText=e.text,s.pendingReplyMarkup=e.replyMarkup,s.timer||(s.pending=new Promise((i,o)=>{s.cancelPending=o,s.timer=setTimeout(()=>{s.timer=void 0,s.cancelPending=void 0;const r=s.pendingText,a=s.pendingReplyMarkup;if(s.pendingText=void 0,s.pendingReplyMarkup=void 0,!r)return i(void 0);this.updateExistingEntry(e,t,s,r,a,Up(a),n).then(i,o)},1e3-r)}).finally(()=>{s.pending=void 0,s.timer=void 0,s.cancelPending=void 0})),await s.pending,this.isCurrent(e.bridge.id,n)&&this.entries.has(e.key)):(await this.updateExistingEntry(e,t,s,e.text,e.replyMarkup,i,n),this.isCurrent(e.bridge.id,n))}const r={bridgeId:e.bridge.id,lastText:e.text,lastActionsFingerprint:i,lastUpdateAt:Date.now()};return r.pending=_p({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,chatId:e.chatId,text:e.text,replyMarkup:e.replyMarkup,sessionWebhook:t.chatWebhooks.get(e.chatId)||hu(e.bridge.settings.sessionWebhook),senderId:t.senderIds.get(e.chatId)||hu(e.bridge.settings.senderId),title:"TaskHandoff 执行中",step:"progress",forceCard:!0}).then(t=>{this.isCurrent(e.bridge.id,n)&&(t?.outTrackId&&(r.outTrackId=t.outTrackId),t?.delivered&&(r.delivered=!0,r.lastUpdateAt=Date.now()))}).catch(t=>{throw this.isCurrent(e.bridge.id,n)&&this.entries.delete(e.key),t}).finally(()=>{r.pending=void 0}),this.entries.set(e.key,r),await r.pending,this.isCurrent(e.bridge.id,n)&&Boolean(r.delivered)}async updateExistingEntry(e,t,n,i,s,r,o){n.outTrackId&&(await async function(e){await Rp(e.fetchImpl,e.bridge,e.runtime,"PUT","/v1.0/card/instances",{outTrackId:e.outTrackId,cardData:{cardParamMap:Sp({type:"actions",title:e.title,description:e.text,list:El(e.replyMarkup),biz_step:e.step,error_msg:""})},cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},userIdType:Number(e.bridge.settings.cardUserIdType||1)})}({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,outTrackId:n.outTrackId,text:i,replyMarkup:s,title:"TaskHandoff 执行中",step:"progress"}),this.isCurrent(e.bridge.id,o)&&(n.lastText=i,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function hu(e){return"string"==typeof e?e:""}function yu(e){const t=new f.DWClient({clientId:e.clientId,clientSecret:e.clientSecret,ua:"task-handoff-control-plane",keepAlive:!1,autoReconnect:!1});let n,i=!1;return{async connect(){i=!1,await t.getEndpoint(),await t._connect();const e=t.socket;e?.once("close",()=>{i||n?.(new Error("DingDing stream connection closed."))})},disconnect(){i=!0,t.disconnect()},onDisconnect(e){n=e},getConfig:()=>t.getConfig(),registerCallbackListener(e,n){t.registerCallbackListener(e,n)},socketCallBackResponse(e,n){t.socketCallBackResponse(e,n)}}}class fu{runtimes=new Map;connected=new Set;reconnectTimers=new Map;progress;options;createClient;constructor(e){this.options=e,this.createClient=e.createClient||yu,this.progress=new gu(e.fetchImpl)}has(e){return this.runtimes.has(e)}isRunning(e){return this.connected.has(e)}get(e){return this.runtimes.get(e)}ids(){return this.runtimes.keys()}start(e){const t=(n=e.settings?.clientSecret,"string"==typeof n?n:"");var n;if(!e.token||!t)return this.options.onError(e.id,"DingDing client id/secret is not configured."),!1;const i={client:this.createClient({clientId:e.token,clientSecret:t}),chatWebhooks:new Map,senderIds:new Map,conversationTypes:new Map,onLog:(t,n,i)=>{this.options.logger["warn"===t?"warn":"info"]({bridgeId:e.id,...n},i)}};return i.client.onDisconnect?.(t=>{this.runtimes.get(e.id)===i&&this.handleConnectionFailure(e,i,t)}),i.client.registerCallbackListener(f.TOPIC_ROBOT,t=>{this.options.onRobotMessage(e,i,t).catch(t=>{this.options.onError(e.id,t)})}),i.client.registerCallbackListener(f.TOPIC_CARD,t=>{const n=t;this.options.onCardCallback(e,i,n).then(e=>i.client.socketCallBackResponse(n.headers.messageId,e||{})).catch(t=>{this.options.onError(e.id,t),i.client.socketCallBackResponse(n.headers.messageId,{})})}),this.options.clearError(e.id),this.runtimes.set(e.id,i),this.connect(e,i),!0}connect(e,t){this.reconnectTimers.delete(e.id),this.connected.add(e.id),t.client.connect().then(()=>{this.runtimes.get(e.id)===t&&(this.connected.add(e.id),this.options.clearError(e.id))}).catch(n=>{this.runtimes.get(e.id)===t&&this.handleConnectionFailure(e,t,n)})}handleConnectionFailure(e,t,n){if(this.connected.delete(e.id),this.progress.clearBridge(e.id),this.options.onError(e.id,n||"DingDing stream connection failed."),this.reconnectTimers.has(e.id))return;const i=setTimeout(()=>{this.runtimes.get(e.id)===t&&this.connect(e,t)},this.options.reconnectDelayMs??1e3);i.unref?.(),this.reconnectTimers.set(e.id,i)}stop(e){const t=this.reconnectTimers.get(e);t&&clearTimeout(t),this.reconnectTimers.delete(e),this.connected.delete(e);const n=this.runtimes.get(e);if(n){try{n.client.disconnect()}catch{}this.runtimes.delete(e)}this.progress.clearBridge(e)}stopAll(){for(const e of[...this.runtimes.keys()])this.stop(e);this.progress.clear()}applyUpdate(e){const t=this.runtimes.get(e.bridge.id);return t?this.progress.applyUpdate(e,t):Promise.resolve(!1)}applyProgressUpdate(e){return this.applyUpdate(e)}}class Iu{entries=new Map;generations=new Map;updateIntervalMs;constructor(e=1e3){this.updateIntervalMs=e}clear(){for(const e of new Set([...this.generations.keys(),...[...this.entries.values()].map(e=>e.bridgeId)]))this.clearBridge(e)}clearBridge(e){this.generations.set(e,this.generation(e)+1);for(const[t,n]of this.entries)n.bridgeId===e&&(n.timer&&clearTimeout(n.timer),n.cancelPending?.(new Error("Lark progress update was cancelled.")),this.entries.delete(t))}generation(e){return this.generations.get(e)||0}isCurrent(e,t){return this.generation(e)===t}async applyUpdate(e,t){const n=this.generation(e.bridge.id),i=Gp(e.replyMarkup);let s=this.entries.get(e.key);if(s?.pending&&await s.pending,!this.isCurrent(e.bridge.id,n))return!1;if(s=this.entries.get(e.key),s?.messageId){if(s.lastText===e.text&&s.lastActionsFingerprint===i)return!0;const r=Date.now()-s.lastUpdateAt;return r<this.updateIntervalMs?(s.pendingText=e.text,s.pendingReplyMarkup=e.replyMarkup,s.timer||(s.pending=new Promise((i,o)=>{s.cancelPending=o,s.timer=setTimeout(()=>{s.timer=void 0,s.cancelPending=void 0;const r=s.pendingText,a=s.pendingReplyMarkup;if(s.pendingText=void 0,s.pendingReplyMarkup=void 0,!r)return i(void 0);this.updateExistingEntry(e,t,s,r,a,Gp(a),n).then(i,o)},this.updateIntervalMs-r)}).finally(()=>{s.pending=void 0,s.timer=void 0,s.cancelPending=void 0})),await s.pending,this.isCurrent(e.bridge.id,n)&&this.entries.has(e.key)):(await this.updateExistingEntry(e,t,s,e.text,e.replyMarkup,i,n),this.isCurrent(e.bridge.id,n))}const r={bridgeId:e.bridge.id,lastText:e.text,lastActionsFingerprint:i,lastUpdateAt:Date.now()};return r.pending=t.channel.send(e.chatId,{card:Hp(e.text,e.replyMarkup)}).then(t=>{this.isCurrent(e.bridge.id,n)&&(r.messageId=t.messageId,r.delivered=!0,r.lastUpdateAt=Date.now())}).catch(t=>{throw this.isCurrent(e.bridge.id,n)&&this.entries.delete(e.key),t}).finally(()=>{r.pending=void 0}),this.entries.set(e.key,r),await r.pending,this.isCurrent(e.bridge.id,n)&&Boolean(r.delivered)}async updateExistingEntry(e,t,n,i,s,r,o){n.messageId&&(await t.channel.updateCard(n.messageId,Hp(i,s)),this.isCurrent(e.bridge.id,o)&&(n.lastText=i,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function bu(e){const t={appId:e.appId,appSecret:e.appSecret,domain:e.domain,transport:"websocket",source:"task-handoff-control-plane",handshakeTimeoutMs:15e3,policy:{requireMention:!0,dmMode:"open",respondToMentionAll:!1}};return I.createLarkChannel(t)}class vu{runtimes=new Map;connected=new Set;unsubscribe=new Map;reconnectTimers=new Map;options;createChannel;progress;constructor(e){this.options=e,this.createChannel=e.createChannel||bu,this.progress=new Iu(e.progressUpdateIntervalMs)}has(e){return this.runtimes.has(e)}isRunning(e){return this.connected.has(e)}get(e){return this.runtimes.get(e)}ids(){return this.runtimes.keys()}start(e){const t=(n=e.settings?.appSecret,"string"==typeof n?n.trim():"");var n;if(!e.token||!t)return this.options.onError(e.id,"Lark app id/secret is not configured."),!1;const i={channel:this.createChannel({appId:e.token,appSecret:t,domain:wu(e.settings?.domain)})},s=i.channel.on({message:t=>{this.options.onMessage(e,i,t).catch(t=>{this.options.onError(e.id,t)})},cardAction:t=>{this.options.onCardAction(e,i,t).catch(t=>{this.options.onError(e.id,t)})},error:t=>{this.options.onError(e.id,t),this.options.logger.warn({bridgeId:e.id,error:t.message},"lark channel error")},reconnecting:()=>{this.connected.delete(e.id),this.options.onError(e.id,"Lark WebSocket is reconnecting."),this.options.logger.info({bridgeId:e.id},"lark channel reconnecting")},reconnected:()=>{this.runtimes.get(e.id)===i&&(this.connected.add(e.id),this.options.clearError(e.id),this.options.logger.info({bridgeId:e.id},"lark channel reconnected"))}});return this.options.clearError(e.id),this.runtimes.set(e.id,i),this.unsubscribe.set(e.id,s),this.connect(e,i),!0}connect(e,t){this.reconnectTimers.delete(e.id),t.channel.connect().then(()=>{this.runtimes.get(e.id)===t&&(this.connected.add(e.id),this.options.clearError(e.id),this.options.logger.info({bridgeId:e.id},"lark channel connected"))}).catch(n=>{if(this.runtimes.get(e.id)!==t)return;if(this.connected.delete(e.id),this.options.onError(e.id,n),t.channel.rawWsClient||this.reconnectTimers.has(e.id))return;const i=setTimeout(()=>{this.runtimes.get(e.id)===t&&this.connect(e,t)},this.options.reconnectDelayMs??1e3);i.unref?.(),this.reconnectTimers.set(e.id,i)})}stop(e){const t=this.reconnectTimers.get(e);t&&clearTimeout(t),this.reconnectTimers.delete(e),this.unsubscribe.get(e)?.(),this.unsubscribe.delete(e),this.connected.delete(e);const n=this.runtimes.get(e);if(this.runtimes.delete(e),this.progress.clearBridge(e),n){try{n.channel.rawWsClient?.close({force:!0})}catch{}n.channel.disconnect().catch(()=>{})}}stopAll(){for(const e of[...this.runtimes.keys()])this.stop(e);this.progress.clear()}applyUpdate(e){const t=this.runtimes.get(e.bridge.id);return t?this.progress.applyUpdate(e,t):Promise.resolve(!1)}applyProgressUpdate(e){return this.applyUpdate(e)}}function wu(e){return"lark"===String(e||"").trim().toLowerCase()?I.Domain.Lark:I.Domain.Feishu}class Su{ttlMs;load;now;cached;pending;generation=0;constructor(e,t,n={}){this.ttlMs=e,this.load=t,this.now=n.now||Date.now}get(){if(this.cached&&this.cached.expiresAt>this.now())return Promise.resolve(this.cached.value);if(this.pending)return this.pending;const e=this.generation,t=this.load().then(t=>(this.generation===e&&(this.cached={expiresAt:this.now()+this.ttlMs,value:t}),t)).finally(()=>{this.pending===t&&(this.pending=void 0)});return this.pending=t,t}invalidate(){this.generation+=1,this.cached=void 0,this.pending=void 0}}class Au{aggregates=new Map;endTokens=new Map;options;delayMs;constructor(e){this.options=e,this.delayMs=e.delayMs??1e3}async handleIncoming(e,t,n,i,s=[],r={},o={}){const a=i.trim(),d=a.split(/\s+/,1)[0]?.toLowerCase()||"",c=ku(e.id,t,n),l=this.aggregates.get(c);return o.autoBegin&&!l?(this.start(c,e,t,n,r),this.enqueue(c,e,t,n,i,s,r,!0),void await this.sendCollectionStarted(e,t,c,r.sourceMessageId,"Image received. Continue sending messages, then send /end when done.")):"/begin"===d?(this.start(c,e,t,n,r),void await this.sendCollectionStarted(e,t,c,r.sourceMessageId,"Started collecting messages. Send /end when done.")):void("/end"!==d?l?.explicit?this.enqueue(c,e,t,n,i,s,r,!0):a.startsWith("/")?await this.options.dispatch(e,t,n,i,s,r):this.enqueue(c,e,t,n,i,s,r,!1):await this.flush(c,"manual"))}async handleEndCallback(e,t,n,i,s){const r=this.endTokens.get(i)||"";if(r!==ku(e.id,t,s))return void await this.options.answerCallback(e,n,"This collection is not active here");const o=await this.flush(r,"callback");await this.options.answerCallback(e,n,o?"Collected message sent":"No messages collected")}stop(){for(const e of this.aggregates.values())e.timer&&clearTimeout(e.timer);this.aggregates.clear(),this.endTokens.clear()}stopBridge(e){for(const[t,n]of this.aggregates)n.bridgeId===e&&(n.timer&&clearTimeout(n.timer),this.aggregates.delete(t));for(const[t,n]of this.endTokens)n.startsWith(`${e}:`)&&this.endTokens.delete(t)}start(e,t,n,i,s){const r=this.aggregates.get(e);r?.timer&&clearTimeout(r.timer),this.aggregates.set(e,{bridgeId:t.id,chatId:n,userId:i,texts:[],attachments:[],context:s,explicit:!0})}enqueue(e,t,n,i,s,r,o,a){const d=this.aggregates.get(e);d?.timer&&clearTimeout(d.timer);const c=d||{bridgeId:t.id,chatId:n,userId:i,texts:[],attachments:[],context:o,explicit:a};var l,p;c.bridgeId=t.id,c.chatId=n,c.userId=i,c.context=(l=c.context,p=o,{sourceMessageId:l?.sourceMessageId??p.sourceMessageId,replyToMessageId:l?.replyToMessageId??p.replyToMessageId,quoteText:l?.quoteText||p.quoteText}),c.explicit=c.explicit||a,s.trim()&&c.texts.push(s),c.attachments.push(...r),c.timer=c.explicit?void 0:setTimeout(()=>{this.flush(e,"timer").catch(e=>this.options.onError?.(c.bridgeId,e))},this.delayMs),this.aggregates.set(e,c)}async flush(e,t){const n=this.aggregates.get(e);if(!n)return!1;n.timer&&clearTimeout(n.timer),this.aggregates.delete(e);const i=this.options.requireBridge(n.bridgeId),s=n.texts.join("\n\n").trim();return s||n.attachments.length?(await this.options.dispatch(i,n.chatId,n.userId,s,n.attachments,n.context||{}),!0):("timer"!==t&&await this.options.send(i,n.chatId,"No messages collected.",{replyToMessageId:n.context?.sourceMessageId}),!1)}sendCollectionStarted(e,t,n,i,s){return this.options.send(e,t,s,{replyToMessageId:i,replyMarkup:kl([[{text:"/end",callbackData:this.endCallbackData(n)}]])})}endCallbackData(e){const t=i.createHash("sha256").update(e).digest("base64url").slice(0,16);return this.endTokens.set(t,e),`task_handoff:cp_msg_end:${t}`}}function ku(e,t,n){return[e,t,n||""].join(":")}class zu{cancelTokens=new Map;queueActionTokens=new Map;options;constructor(e){this.options=e}cancelCallbackData(e,t){this.pruneExpired();const n=Eu([e,t]);return this.cancelTokens.set(n,this.expiring({instanceId:e,sessionId:t})),`task_handoff:cp_ai_cancel:${n}`}queueSteerCallbackData(e,t,n){return`task_handoff:cp_ai_steer:${this.queueActionToken({type:"steer",instanceId:e,sessionId:t,queueId:n})}`}queueDeleteMenuCallbackData(e,t){return`task_handoff:cp_ai_qdel_menu:${this.queueActionToken({type:"delete-menu",instanceId:e,sessionId:t})}`}async tryHandle(e,t){this.pruneExpired();const n=Tu(e,"task_handoff:cp_ai_cancel:");if(void 0!==n){const e=this.cancelTokens.get(n)?.value;return e?(await this.cancel(t,e.instanceId,e.sessionId),!0):this.expired(t)}const i=Tu(e,"task_handoff:cp_ai_steer:");if(void 0!==i){const e=this.queueActionTokens.get(i)?.value;return e&&"steer"===e.type?(await this.steer(t,e),!0):this.expired(t)}const s=Tu(e,"task_handoff:cp_ai_qdel_menu:");if(void 0!==s){const e=this.queueActionTokens.get(s)?.value;return e&&"delete-menu"===e.type?(await this.deleteMenu(t,e),!0):this.expired(t)}const r=Tu(e,"task_handoff:cp_ai_qdel:");if(void 0!==r){const e=this.queueActionTokens.get(r)?.value;return e&&"delete-item"===e.type?(await this.deleteItem(t,e),!0):this.expired(t)}return!1}async cancel(e,t,n){await this.requireAllowed(e,t,n)&&await this.run(e,{instanceId:t,sessionId:n,successText:"Interrupt sent",failurePrefix:"Interrupt failed",logMessage:"chat ai session cancel sent",operation:()=>this.options.interrupt(t,n)})}async steer(e,t){await this.requireAllowed(e,t.instanceId,t.sessionId)&&await this.run(e,{...t,successText:"Steered queued message",failurePrefix:"Steer failed",logMessage:"chat ai session queued message steered",operation:()=>this.options.steer(t.instanceId,t.sessionId,t.queueId)})}async deleteMenu(e,t){if(await this.requireAllowed(e,t.instanceId,t.sessionId))try{const n=xu(await this.options.queue(t.instanceId,t.sessionId)),i=(Array.isArray(n.items)?n.items:[]).map(xu).filter(e=>"queued"===Nu(e.status)&&Nu(e.id));if(!i.length)return void await this.answer(e,"Queue is empty");const s=i.slice(0,5).map((e,n)=>[{text:Cu(Nu(e.message),n),callbackData:this.queueDeleteItemCallbackData(t.instanceId,t.sessionId,Nu(e.id))}]);await this.send(e,"Delete queued message",{replyMarkup:kl(s)}),await this.answer(e,"Select a queued message"),this.options.info(this.logData(e,t,{itemCount:i.length}),"chat ai session queue delete menu sent")}catch(t){await this.fail(e,t,"Queue menu failed")}}async deleteItem(e,t){if(await this.requireAllowed(e,t.instanceId,t.sessionId))try{await this.options.remove(t.instanceId,t.sessionId,t.queueId),await this.answer(e,"Queued message deleted"),(e.deleteMessage||Number.isInteger(e.messageId))&&await this.deleteMessage(e).catch(n=>{this.options.warn(this.logData(e,t,{messageId:e.messageId,error:Ou(n)}),"chat ai session queue delete menu message delete failed")}),this.options.info(this.logData(e,t),"chat ai session queued message deleted")}catch(t){await this.fail(e,t,"Delete failed")}}async run(e,t){try{await t.operation(),await this.answer(e,t.successText),this.options.info(this.logData(e,t),t.logMessage)}catch(n){await this.fail(e,n,t.failurePrefix)}}async requireAllowed(e,t,n){return!!(e.actionAllowed?e.actionAllowed(t,n):this.options.actionAllowed(e.bridge,e.chatId,t,n,Number.isInteger(e.messageId)?e.messageId:void 0))||(await this.answer(e,"This chat is not bound to that AI session"),!1)}async fail(e,t,n){const i=Ou(t);this.options.setBridgeError(e.bridge.id,i),await this.answer(e,`${n}: ${function(e){const t=e.replace(/\s+/g," ").trim();return t.length<=120?t:`${t.slice(0,Math.max(0,119))}…`}(i)}`)}async expired(e){return await this.answer(e,"This AI session action expired"),!0}answer(e,t){return e.answer?e.answer(t):this.options.answer(e.bridge,e.callbackQueryId,t)}send(e,t,n){return e.send?e.send(t,n):this.options.send(e.bridge,e.chatId,t,n)}deleteMessage(e){return e.deleteMessage?e.deleteMessage():Number.isInteger(e.messageId)?this.options.deleteMessage(e.bridge,e.chatId,e.messageId):Promise.resolve(void 0)}queueDeleteItemCallbackData(e,t,n){return`task_handoff:cp_ai_qdel:${this.queueActionToken({type:"delete-item",instanceId:e,sessionId:t,queueId:n})}`}queueActionToken(e){this.pruneExpired();const t=Eu([e.type,e.instanceId,e.sessionId,"queueId"in e?e.queueId:""]);return this.queueActionTokens.set(t,this.expiring(e)),t}clear(){this.cancelTokens.clear(),this.queueActionTokens.clear()}expiring(e){return{value:e,expiresAt:(this.options.now||Date.now)()+(this.options.tokenTtlMs??864e5)}}pruneExpired(){const e=(this.options.now||Date.now)();for(const[t,n]of this.cancelTokens)n.expiresAt<=e&&this.cancelTokens.delete(t);for(const[t,n]of this.queueActionTokens)n.expiresAt<=e&&this.queueActionTokens.delete(t)}logData(e,t,n={}){return{bridgeId:e.bridge.id,chatId:e.chatId,instanceId:t.instanceId,sessionId:t.sessionId,...t.queueId?{queueId:t.queueId}:{},userId:e.userId,...n}}}function Tu(e,t){if(!e.startsWith(t))return;const n=e.slice(t.length);return n&&!n.includes(":")?n:void 0}function Eu(e){return i.createHash("sha256").update(e.join("\0")).digest("base64url").slice(0,16)}function Cu(e,t){const n=`${t+1}. `,i=Nu(e).replace(/\s+/g," ").trim()||"Queued message",s=Math.max(8,48-n.length),r=Array.from(i);return`${n}${r.length>s?`${r.slice(0,Math.max(1,s-3)).join("")}...`:i}`}function xu(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Nu(e){return"string"==typeof e?e.trim():""}function Ou(e){return e instanceof Error?e.message:String(e)}class _u{announced=new Set;options;constructor(e){this.options=e}async poll(){const e=await this.options.listRoutes().catch(()=>[]);for(const t of e){if(this.announced.has(t.id))continue;const e=Ru(t,this.options.callbackData),n=t.aiSessionId?this.options.listBindings().filter(e=>e.activeInstanceId===t.instanceId&&e.activeAiSessionId===t.aiSessionId):[];(await this.sendToBindings(n,e)||await this.sendToDefaults(e))&&this.announced.add(t.id)}}async sendToBindings(e,t){let n=!1;for(const i of e){if(!i.bridgeId)continue;const e=this.options.requireBridge(i.bridgeId);if(!e.enabled)continue;const s=await this.send(e,i.chatSessionId,t);n||=s}return n}async sendToDefaults(e){let t=!1;for(const n of this.options.listBridges()){if(!n.enabled||!n.defaultChatId)continue;let i=!1;await this.options.send(n,n.defaultChatId,e).catch(e=>(this.options.setBridgeError(n.id,Pu(e)),i=!0,!1))?t=!0:i||this.options.setBridgeError(n.id,"Chat bridge message was not delivered.")}return t}async send(e,t,n){return this.options.send(e,t,n).then(Boolean).catch(t=>(this.options.setBridgeError(e.id,Pu(t)),!1))}}function Ru(e,t){const n=`${e.project?.name||e.projectId} / ${e.instance?.name||e.instanceId}`,i="approval"===e.kind?`/approve ${e.id}\n/deny ${e.id}\n/skip ${e.id}`:`/reply ${e.id} <message>`,s=`[${n}]\n${e.result}\n\n${i}`;return"approval"!==e.kind?{text:s}:{text:s,replyMarkup:kl([[{text:"Allow",callbackData:t(e.id,"allow")},{text:"Skip",callbackData:t(e.id,"skip")},{text:"Deny",callbackData:t(e.id,"deny")}]])}}function Pu(e){return e instanceof Error?e.message:String(e)}function ju(){return e=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(e||"").trim().toLowerCase());var e}class Du{service;fetchImpl;logger;diagnosticLogsEnabled;bridgeTimers=new Map;bridgePollingGenerations=new Map;bridgePolls=new Map;dingdingBridges;larkBridges;bridgeErrors=new Map;telegramOffsets=new Map;seenTelegramUpdates=new Set;wechatCursors=new Map;pendingRouteNotifier;deliveredAiSessionFingerprints=new Map;telegramAiSessionCallbacks;telegramMessageAggregator;telegramProgressMessageTargets=new Map;aiSessionInstanceNamesCache;aiSessionPendingRoutesCache;telegramProgress;stopAiSessionListener;constructor(e,t=fetch,n={}){this.service=e,this.fetchImpl=t,this.logger=n.logger,this.diagnosticLogsEnabled=n.diagnosticLogsEnabled||ju,this.aiSessionInstanceNamesCache=new Su(3e4,async()=>{const e=await(this.service.listAiSessionInstanceNames?.()||this.service.boardAsync()).catch(()=>[]);return new Map(e.map(e=>[e.id,e.name||e.id]))}),this.aiSessionPendingRoutesCache=new Su(1e3,()=>this.service.listPendingRoutes().catch(()=>[])),this.telegramMessageAggregator=new Au({requireBridge:e=>this.service.requireChatBridge(e),send:(e,t,n,i={})=>this.sendTelegramMessage(e,t,n,i),answerCallback:(e,t,n)=>this.answerTelegramCallback(e,t,n),dispatch:(e,t,n,i,s,r)=>this.dispatchTelegramGatewayMessage(e,t,n,i,s,r),onError:(e,t)=>this.bridgeErrors.set(e,Wu(t))}),this.telegramAiSessionCallbacks=new zu({interrupt:(e,t)=>this.service.interruptAiSession(e,t),queue:(e,t)=>this.service.aiSessionQueue(e,t),steer:(e,t,n)=>this.service.steerAiSessionQueuedMessage(e,t,n),remove:(e,t,n)=>this.service.removeAiSessionQueuedMessage(e,t,n),actionAllowed:(e,t,n,i,s)=>this.telegramAiSessionActionAllowed(e,t,n,i,s),answer:(e,t,n)=>this.answerTelegramCallback(e,t,n),send:(e,t,n,i={})=>this.sendTelegramMessage(e,t,n,i),deleteMessage:(e,t,n)=>this.deleteTelegramMessage(e,t,n),setBridgeError:(e,t)=>this.bridgeErrors.set(e,t),info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.pendingRouteNotifier=new _u({listRoutes:()=>this.service.listPendingRoutes(),listBindings:()=>this.service.listChatSessions(),listBridges:()=>this.service.listChatBridges(),requireBridge:e=>this.service.requireChatBridge(e),callbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),send:(e,t,n)=>this.sendViaBridge(e,t,n),setBridgeError:(e,t)=>this.bridgeErrors.set(e,t)}),this.telegramProgress=new iu({updateIntervalMs:n.telegramProgressUpdateIntervalMs,requireBridge:e=>this.service.requireChatBridge(e),send:(e,t,n,i={})=>this.sendTelegramMessage(e,t,n,i),edit:(e,t,n,i,s={})=>this.editTelegramMessage(e,t,n,i,s),deleteMessage:(e,t,n)=>this.deleteTelegramMessage(e,t,n),onLog:e=>this.logWarn({message:e},"telegram progress store warning")}),this.dingdingBridges=new fu({fetchImpl:this.fetchImpl,createClient:n.createDingdingClient,logger:{info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)},onRobotMessage:(e,t,n)=>this.handleDingdingRobotMessage(e,t,n),onCardCallback:(e,t,n)=>this.handleDingdingCardCallback(e,t,n),onError:(e,t)=>this.bridgeErrors.set(e,Wu(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.larkBridges=new vu({createChannel:n.createLarkChannel,progressUpdateIntervalMs:n.larkProgressUpdateIntervalMs,logger:{info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)},onMessage:(e,t,n)=>this.handleLarkMessage(e,t,n),onCardAction:(e,t,n)=>this.handleLarkCardAction(e,t,n),onError:(e,t)=>this.bridgeErrors.set(e,Wu(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.stopAiSessionListener=n.aiSessions?.onSnapshot(e=>{this.deliverAiSessionSnapshot(e.instanceId,e.aiSessions).catch(t=>{this.logWarn({instanceId:e.instanceId,snapshotRevision:e.revision,error:Wu(t)},"chat ai session snapshot delivery failed")})})}logInfo(e,t){this.diagnosticLogsEnabled()&&this.logger?.info?.({component:"control-plane-chat-gateway",...e},t)}logWarn(e,t){this.diagnosticLogsEnabled()&&this.logger?.warn?.({component:"control-plane-chat-gateway",...e},t)}updateChatBridge(e,t){this.service.updateChatBridge?.(e,t)}startEnabled(){this.logAiSessionDelivery({stage:"runtime-start-enabled",bridgeCount:this.service.listChatBridges().length,enabledBridgeCount:this.service.listChatBridges().filter(e=>e.enabled).length});for(const e of this.service.listChatBridges())e.enabled&&this.startBridge(e.id)}startBridge(e){if(this.bridgeTimers.has(e)||this.dingdingBridges.has(e)||this.larkBridges.has(e))return this.logAiSessionDelivery({stage:"bridge-start-skipped-running",bridgeId:e}),this.status();const t=this.service.requireChatBridge(e);return this.logAiSessionDelivery({stage:"bridge-start",bridgeId:t.id,channel:t.channel,enabled:t.enabled,hasToken:Boolean(t.token)}),"wechat"===t.channel?this.startPollingBridge(t,(e,t)=>this.pollWechat(e,t)):"dingding"===t.channel?this.startDingdingBridge(t):"lark"===t.channel?this.startLarkBridge(t):"telegram"!==t.channel?(this.bridgeErrors.set(e,`${t.channel} bridge is not supported in the control plane.`),this.status()):t.token?this.startPollingBridge(t,(e,t)=>this.pollTelegram(e,t)):(this.bridgeErrors.set(e,"Telegram token is not configured."),this.status())}stopBridge(e){this.advanceBridgePollingGeneration(e);const t=`:${e}:`;for(const e of this.deliveredAiSessionFingerprints.keys())e.includes(t)&&this.deliveredAiSessionFingerprints.delete(e);const n=this.bridgeTimers.get(e);return n&&(clearInterval(n),this.bridgeTimers.delete(e)),this.dingdingBridges.stop(e),this.larkBridges.stop(e),this.telegramMessageAggregator.stopBridge(e),this.status()}stopAll(){const e=new Set([...this.service.listChatBridges().map(e=>e.id),...this.bridgePollingGenerations.keys(),...this.bridgeTimers.keys(),...this.bridgePolls.keys(),...this.dingdingBridges.ids(),...this.larkBridges.ids()]);for(const t of e)this.stopBridge(t);this.dingdingBridges.stopAll(),this.larkBridges.stopAll(),this.telegramMessageAggregator.stop(),this.telegramAiSessionCallbacks.clear(),this.stopAiSessionListener?.(),this.stopAiSessionListener=void 0}async pollBridgeNow(e){const t=this.service.requireChatBridge(e),n=this.bridgePollingGeneration(e);return"telegram"===t.channel?(await this.runBridgePoll(t,n,(e,t)=>this.pollTelegram(e,t)),this.status()):"wechat"===t.channel?(await this.runBridgePoll(t,n,(e,t)=>this.pollWechat(e,t)),this.status()):("dingding"===t.channel||"lark"===t.channel||this.bridgeErrors.set(e,`${t.channel} bridge is not supported in the control plane.`),this.status())}async pollAiSessionsNow(){return await this.pollAiSessionUpdates(),this.status()}status(){const e=this.service.listChatBridges().map(e=>({id:e.id,channel:e.channel,name:e.name,running:this.bridgeTimers.has(e.id)||this.dingdingBridges.isRunning(e.id)||this.larkBridges.isRunning(e.id),tokenSet:Boolean(e.tokenSet),defaultChatId:e.defaultChatId,lastUpdateId:this.telegramOffsets.get(e.id),error:this.bridgeErrors.get(e.id)}));return{running:e.some(e=>e.running),bridges:e}}startPollingBridge(e,t){if(!e.token)return this.bridgeErrors.set(e.id,`${e.channel} token is not configured.`),this.status();this.bridgeErrors.delete(e.id);const n=this.advanceBridgePollingGeneration(e.id),i=()=>this.bridgePollingGeneration(e.id)===n,s=s=>{i()&&this.runBridgePoll(s,n,t).catch(t=>{i()&&this.bridgeErrors.set(e.id,t instanceof Error?t.message:String(t))})},r=setInterval(()=>{if(!i())return;const t=this.service.requireChatBridge(e.id);t.enabled?s(t):this.stopBridge(e.id)},e.pollIntervalMs);if(this.bridgeTimers.set(e.id,r),this.logAiSessionDelivery({stage:"bridge-poll-started",bridgeId:e.id,channel:e.channel,intervalMs:e.pollIntervalMs}),e.enabled){const t=this.service.requireChatBridge(e.id);s(t)}return this.status()}runBridgePoll(e,t,n){const i=this.bridgePolls.get(e.id);if(i?.generation===t)return i.promise;const s=(async()=>{const i=()=>this.bridgePollingGeneration(e.id)===t;i()&&await n(e,i)})();this.bridgePolls.set(e.id,{generation:t,promise:s});const r=()=>{this.bridgePolls.get(e.id)?.promise===s&&this.bridgePolls.delete(e.id)};return s.then(r,r),s}bridgePollingGeneration(e){return this.bridgePollingGenerations.get(e)||0}advanceBridgePollingGeneration(e){const t=this.bridgePollingGeneration(e)+1;return this.bridgePollingGenerations.set(e,t),t}startDingdingBridge(e){return this.dingdingBridges.start(e),this.status()}startLarkBridge(e){return this.larkBridges.start(e),this.status()}async handleLarkMessage(e,t,n){const i=this.larkAllowed(e,n.senderId),s=String(n.content||"").trim();if(!i||!s)return void this.logWarn({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,allowed:i,hasText:Boolean(s)},"lark message ignored");let r;e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:n.chatId}),this.logInfo({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,chatType:n.chatType,messageId:n.messageId,textPreview:Vu(s)},"lark chat gateway message received");try{r=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"lark",bridgeId:e.id,chatSessionId:n.chatId,userId:n.senderId},message:{text:s,attachments:[]}})}catch(e){return void await t.channel.send(n.chatId,{markdown:`Failed to handle message: ${Wu(e)}`})}const o=Mu(r);if(!o)return;const a=qu(r);if(await this.sendLarkRoutedAiSessionProgress(r,e,n.chatId,o,a))return;const d=mu({fetchImpl:this.fetchImpl,bridge:e,larkRuntime:t}),c=await d.send(n.chatId,o,{replyMarkup:a});c&&this.logInfo({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,provider:c.provider,interactionId:c.interactionId,routed:!0===Yu(r).routed,replyPreview:Vu(o)},"lark chat gateway reply sent")}async sendLarkRoutedAiSessionProgress(e,t,n,i,s){if(!0!==e.routed)return!1;const r=Zu(e),{instanceId:o,sessionId:a,turnId:d}=r;if(!o||!a||!d)return this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,routed:e.routed},"lark ai session progress message not started"),!1;const c=rm(o,a,d,t.id,n);return!!await this.larkBridges.applyProgressUpdate({bridge:t,key:c,chatId:n,text:i,replyMarkup:s})&&(this.deliveredAiSessionFingerprints.delete(c),this.logInfo({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,key:c,textPreview:Vu(i)},"lark ai session progress message started"),!0)}async handleLarkCardAction(e,t,n){const i=n.operator.openId||n.operator.userId;if(!this.larkAllowed(e,i))return void this.logWarn({bridgeId:e.id,chatId:n.chatId,messageId:n.messageId,userId:i},"lark card action ignored");const s=Wp(n.action.value),r=(e,i)=>t.channel.updateCard(n.messageId,Hp(e||"Updated",i));if(!s)return void await r("Unsupported action");if(await this.telegramAiSessionCallbacks.tryHandle(s,{bridge:e,chatId:n.chatId,callbackQueryId:n.messageId,userId:i,messageId:n.messageId,actionAllowed:(t,i)=>this.chatAiSessionBindingActive(e,n.chatId,t,i),answer:e=>r(e),send:(e,i)=>t.channel.send(n.chatId,{card:Hp(e,i?.replyMarkup)})}))return;let o;try{o=await this.parseChatGatewayCallbackAction(s)}catch(e){if(Gu(e,"CHAT_PENDING_ACTION_STALE"))return void await r(Wu(e));throw e}if(!o)return void await r("Unsupported action");const a=await this.service.handleChatGatewayAction({source:{channel:"lark",bridgeId:e.id,chatSessionId:n.chatId,userId:i},action:o});if("pending-decision"===o.type&&Lu(a))return void await r(`${o.decision} sent`);const d=Mu(a)||Hu(a.message)||"Updated";await r(d,qu(a))}async handleDingdingRobotMessage(e,t,n){const i=function(e){const t=Bp(e),n=$p(t.conversationId),i=$p(Lp(t.text).content).trim();if(!n||!i)return;const s=$p(t.senderStaffId||t.senderId);return{chatId:n,userId:s||void 0,senderId:s||void 0,sessionWebhook:$p(t.sessionWebhook)||void 0,conversationType:Tp(t.conversationType,{robotMessage:!0}),text:i,raw:t}}(n.data);if(t.client.socketCallBackResponse(n.headers.messageId,{}),!i||!this.dingdingAllowed(e,i.senderId))return void this.logWarn({bridgeId:e.id,hasEvent:Boolean(i),senderId:i?.senderId,allowed:i?this.dingdingAllowed(e,i.senderId):void 0},"dingding robot message ignored");const{chatId:s,text:r,senderId:o,sessionWebhook:a}=i;a&&t.chatWebhooks.set(s,a),i.conversationType&&t.conversationTypes.set(s,i.conversationType);const d=a||t.chatWebhooks.get(s)||Hu(e.settings.sessionWebhook);let c;o&&t.senderIds.set(s,o),e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:s}),this.logInfo({bridgeId:e.id,chatId:s,senderId:o,conversationType:i.conversationType,hasSessionWebhook:Boolean(a),hasCachedSessionWebhook:Boolean(t.chatWebhooks.get(s)),hasResolvedSessionWebhook:Boolean(d),textPreview:Vu(r)},"dingding chat gateway message received");try{c=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"dingding",bridgeId:e.id,chatSessionId:s,userId:o||void 0},message:{text:r,attachments:[]}})}catch(e){if(d)return void await Op(this.fetchImpl,d,`Failed to handle message: ${Wu(e)}`,t.onLog);throw e}const l=Mu(c);if(l){const n=qu(c);if(await this.sendDingdingRoutedAiSessionProgress(c,e,t,s,l,{replyMarkup:n,sessionWebhook:d,senderId:o,sourcePrompt:r}))return;const i=mu({fetchImpl:this.fetchImpl,bridge:e,dingdingRuntime:t}),a=await i.send(s,l,{replyMarkup:n,sessionWebhook:d,senderId:o});if(a)return void this.logInfo({bridgeId:e.id,chatId:s,senderId:o,provider:a.provider,interactionId:a.interactionId,routed:!0===Yu(c).routed,hasReplyMarkup:Boolean(n),replyPreview:Vu(l)},"dingding chat gateway reply sent");this.logWarn({bridgeId:e.id,chatId:s,senderId:o,hasReplyMarkup:Boolean(n),hasSessionWebhook:Boolean(d),hasRobotCode:Boolean(Hu(e.settings.robotCode)),replyPreview:Vu(l)},"dingding chat gateway reply skipped")}}async sendDingdingRoutedAiSessionProgress(e,t,n,i,s,r={}){if(!0!==e.routed)return!1;const o=Zu(e),{instanceId:a,sessionId:d,turnId:c}=o;if(!a||!d||!c)return this.logWarn({bridgeId:t.id,chatId:i,instanceId:a,sessionId:d,turnId:c,turnIdSources:o.sources,routed:e.routed},"dingding ai session progress card not started"),!1;const l=rm(a,d,c,t.id,i);return!!await this.dingdingBridges.applyProgressUpdate({bridge:t,key:l,chatId:i,text:s,replyMarkup:r.replyMarkup})&&(this.deliveredAiSessionFingerprints.delete(l),this.logInfo({bridgeId:t.id,chatId:i,instanceId:a,sessionId:d,turnId:c,key:l,hasSessionWebhook:Boolean(r.sessionWebhook),hasSenderId:Boolean(r.senderId),sourcePrompt:Vu(r.sourcePrompt,80),textPreview:Vu(s)},"dingding ai session progress card started"),!0)}async handleDingdingCardCallback(e,t,n){const i=function(e){const t=Bp(e),n=qp(t.cardActionData||t.content),i=qp(n.cardPrivateData||t.cardPrivateData||t.content),s=qp(i.params||n.params||t.params),r=$p(t.userId),o=$p(s.biz_sender_id);return{userId:r||void 0,chatId:zp(t,s),senderId:r||void 0,deliverySenderId:o||void 0,sessionWebhook:$p(s.biz_session_webhook)||void 0,conversationType:Tp(s.biz_conversation_type||t.conversationType||t.conversation_type),callbackData:Ep(xp(t,n,i)),body:t,params:s}}(n.data);if(!this.dingdingAllowed(e,i.userId))return Cp("not authorized",void 0,"unauthorized",i.body,i.params);const s=i.chatId||Hu(e.defaultChatId),r=i.deliverySenderId||i.senderId,o=i.sessionWebhook;let a;s&&o&&t.chatWebhooks.set(s,o),s&&i.conversationType&&t.conversationTypes.set(s,i.conversationType),s&&r&&t.senderIds.set(s,r);try{a=await this.parseChatGatewayCallbackAction(i.callbackData)}catch(e){if(Gu(e,"CHAT_PENDING_ACTION_STALE"))return Cp(Wu(e),void 0,"approval_stale",i.body,i.params);throw e}if(!a)return this.logWarn({bridgeId:e.id,chatId:s,userId:i.userId,senderId:r,...Ku(i)},"dingding card callback action unsupported"),Cp("Unsupported action",void 0,"unsupported",i.body,i.params);this.logInfo({bridgeId:e.id,chatId:s,userId:i.userId,senderId:r,actionType:a.type,...Ku(i)},"dingding card callback action parsed");const d=await this.service.handleChatGatewayAction({source:{channel:"dingding",bridgeId:e.id,chatSessionId:s,userId:i.userId||void 0},action:a});return"pending-decision"===a.type&&Lu(d)?Cp(`${a.decision} sent`,void 0,"approval_done",i.body,i.params):Cp(Mu(d)||Hu(d.message)||"updated",qu(d),"updated",i.body,i.params)}async pollWechat(e,t=()=>!0){if(!e.token)return;const n=e.settings||{},i=this.wechatCursors.get(e.id)||Hu(n.updatesBuf),s=await async function(e){const t=uu((e.bridge.settings||{}).baseUrl)||"https://ilinkai.weixin.qq.com",n=await e.fetchImpl(`${t}/ilink/bot/getupdates`,{method:"POST",headers:{"content-type":"application/json",AuthorizationType:"ilink_bot_token",Authorization:`Bearer ${e.bridge.token}`,"X-WECHAT-UIN":String(Math.floor(Math.random()*2**31))},body:JSON.stringify({get_updates_buf:e.cursor,base_info:{channel_version:"1.0.2"}})}),i=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`HTTP ${n.status}`);const s=Number(i.errcode??i.ret??0);if(0!==s)throw new Error(uu(i.errmsg||i.msg)||`chat bridge API returned ${s}`);const r=[];for(const e of Array.isArray(i.msgs)?i.msgs:[]){const t=pu(e);if(1!==t.message_type)continue;const n=uu(t.from_user_id),i=lu(t);n&&i&&r.push({chatId:n,text:i,contextToken:uu(t.context_token)})}return{cursor:uu(i.get_updates_buf),messages:r}}({fetchImpl:this.fetchImpl,bridge:e,cursor:i});if(t()){s.cursor&&(this.wechatCursors.set(e.id,s.cursor),this.updateChatBridge(e.id,{settings:{updatesBuf:s.cursor}}));for(const i of s.messages){if(!t())return;const{chatId:s,contextToken:r,text:o}=i;if(e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:s,settings:{contextToken:r}}),e.defaultChatId&&e.defaultChatId!==s)continue;const a=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"wechat",bridgeId:e.id,chatSessionId:s},message:{text:o,attachments:[]}});if(!t())return;const d=Mu(a);if(d){const t=mu({fetchImpl:this.fetchImpl,bridge:e});await t.send(s,d,{contextToken:r||Hu(n.contextToken)})}}}}pollPendingRoutes(){return this.pendingRouteNotifier.poll()}async sendToChatBinding(e,t){if(!e.bridgeId)return!1;const n=this.service.requireChatBridge(e.bridgeId);if(!n.enabled)return!1;const i=await this.sendViaBridge(n,e.chatSessionId,t).catch(e=>{this.bridgeErrors.set(n.id,e instanceof Error?e.message:String(e))});return Boolean(i)}async sendViaBridge(e,t,n){const i="string"==typeof n?n:n.text,s="string"==typeof n?void 0:n.replyMarkup;return mu({fetchImpl:this.fetchImpl,bridge:e,dingdingRuntime:this.dingdingBridges.get(e.id),larkRuntime:this.larkBridges.get(e.id)}).send(t,i,{replyMarkup:s})}async pollTelegram(e,t=()=>!0){if(!e.token)return;const n=Number(e.settings?.telegramLastUpdateId),i=this.telegramOffsets.get(e.id)||(Number.isInteger(n)?n:void 0),s=await async function(e){const t=new URLSearchParams({timeout:"0",...e.offset?{offset:String(e.offset+1)}:{}}),n=await e.fetchImpl(`https://api.telegram.org/bot${e.bridge.token}/getUpdates?${t.toString()}`),i=await n.json().catch(()=>({}));if(!n.ok||!1===i.ok){if(409===n.status||/terminated by other getUpdates request/i.test(String(i.description||"")))return{updates:[],conflict:i.description||"Telegram getUpdates conflict: another bot instance is polling this token."};throw new Error(i.description||`Telegram getUpdates failed with HTTP ${n.status}`)}const s=[];for(const t of i.result||[]){const n=Number(t.update_id),i=Number.isInteger(n)?n:void 0,r=au(t.callback_query);if(Object.keys(r).length>0){s.push({updateId:i,callbackQuery:r});continue}const o=au(t.message||t.edited_message);if(0===Object.keys(o).length)continue;const a=au(o.chat),d=au(o.from),c=void 0!==a.id?String(a.id):e.bridge.defaultChatId,l=void 0!==d.id?String(d.id):void 0;if(!c)continue;const p=du(o.text??o.caption),u=tu(o);(p||0!==u.length)&&s.push({updateId:i,chatId:c,userId:l,text:p,rawText:p,message:o,messageId:ou(o),replyToMessageId:ou(au(o.reply_to_message)),quoteText:du(au(o.quote).text),autoBegin:1===u.length&&!p.trim(),hasSingleImageWithoutText:1===u.length&&!p.trim()})}return{updates:s}}({fetchImpl:this.fetchImpl,bridge:e,offset:i});if(t())if(s.conflict)this.bridgeErrors.set(e.id,s.conflict);else for(const n of s.updates){if(!t())return;if(void 0!==n.updateId){const t=`${e.id}:${n.updateId}`;if(this.seenTelegramUpdates.has(t)||n.updateId<=(this.telegramOffsets.get(e.id)||0))continue;this.seenTelegramUpdates.add(t),this.telegramOffsets.set(e.id,n.updateId),this.updateChatBridge(e.id,{settings:{...e.settings,telegramLastUpdateId:n.updateId}})}if("callbackQuery"in n){const t=n.callbackQuery;await this.handleTelegramCallback(e,t).catch(async n=>{const i=Yu(t.message),s=Yu(i.chat),r=void 0!==s.id?String(s.id):e.defaultChatId;this.bridgeErrors.set(e.id,Wu(n)),r&&await this.sendTelegramMessage(e,r,`Action failed: ${Wu(n)}`).catch(t=>{this.bridgeErrors.set(e.id,Wu(t))})});continue}if(!this.telegramAllowed(e,n.userId))continue;const i=await su({fetchImpl:this.fetchImpl,bridge:e,message:n.message,onImageDownloadError:({fileId:t,fileName:n,error:i})=>{this.logWarn({bridgeId:e.id,fileId:t,fileName:n,error:Wu(i)},"telegram image download skipped")}});if(!t())return;const s=n.rawText.trim();(s||i.length)&&(this.logInfo({bridgeId:e.id,chatId:n.chatId,messageId:n.messageId,replyToMessageId:n.replyToMessageId,hasQuote:Boolean(n.quoteText),textPreview:Vu(s)},"telegram chat gateway message received"),await this.telegramMessageAggregator.handleIncoming(e,n.chatId,n.userId,s,i,{sourceMessageId:n.messageId,replyToMessageId:n.replyToMessageId,quoteText:n.quoteText},{autoBegin:n.autoBegin}))}}async dispatchTelegramGatewayMessage(e,t,n,i,s=[],r={}){try{const o=void 0!==r.replyToMessageId?this.telegramReplyAiSessionTarget(e.id,t,r.replyToMessageId):void 0,a=function(e,t){const n=String(t||"").trim(),i=e.trim();return n?[`引用:${n}`,i].filter(Boolean).join("\n"):i}(i,r.quoteText),d=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"telegram",bridgeId:e.id,chatSessionId:t,userId:n},message:{text:a,attachments:s},...o?{target:{instanceId:o.instanceId,aiSessionId:o.sessionId}}:{}}),c=Mu(d),l=qu(d);if(c){const n=await this.sendTelegramMessage(e,t,c,{replyMarkup:l,replyToMessageId:r.sourceMessageId});this.logInfo({bridgeId:e.id,chatId:t,sourceMessageId:r.sourceMessageId,replyToMessageId:r.replyToMessageId,replyTargetInstanceId:o?.instanceId,replyTargetSessionId:o?.sessionId,sentMessageId:Number(Yu(n).message_id)||void 0,routed:!0===Yu(d).routed,replyPreview:Vu(c)},"telegram chat gateway reply sent"),await this.rememberTelegramProgressMessage(d,e,t,n,c)}}catch(n){this.bridgeErrors.set(e.id,Wu(n)),await this.sendTelegramMessage(e,t,`Failed to handle message: ${Wu(n)}`,{replyToMessageId:r.sourceMessageId}).catch(t=>{this.bridgeErrors.set(e.id,Wu(t))})}}async handleTelegramCallback(e,t){const n=Hu(t.data),i=Yu(t.from),s=Yu(t.message),r=Yu(s.chat),o=void 0!==r.id?String(r.id):e.defaultChatId,a=void 0!==i.id?String(i.id):void 0;if(!o||!this.telegramAllowed(e,a))return;if(await this.telegramAiSessionCallbacks.tryHandle(n,{bridge:e,chatId:o,callbackQueryId:Hu(t.id),userId:a,messageId:Bu(s)}))return;const d=n.match(/^task_handoff:cp_msg_end:([^:]+)$/);if(d)return void await this.telegramMessageAggregator.handleEndCallback(e,o,Hu(t.id),d[1],a);let c;try{c=await this.parseChatGatewayCallbackAction(n)}catch(n){if(Gu(n,"CHAT_PENDING_ACTION_STALE")){await this.answerTelegramCallback(e,Hu(t.id),Wu(n));const i=Bu(s);return void(void 0!==i&&await this.deleteTelegramStandaloneApprovalMessage(e,o,i))}throw n}if(!c)return void await this.answerTelegramCallback(e,Hu(t.id),"Unsupported action");const l=await this.service.handleChatGatewayAction({source:{channel:"telegram",bridgeId:e.id,chatSessionId:o,userId:a},action:c});if("pending-decision"===c.type&&Lu(l)){await this.answerTelegramCallback(e,Hu(t.id),"");const n=Bu(s);return void(void 0!==n&&await this.deleteTelegramStandaloneApprovalMessage(e,o,n))}await this.answerTelegramCallback(e,Hu(t.id),Hu(l.message)||"updated");const p=Mu(l),u=qu(l),m=s.message_id;p&&"number"==typeof m?await this.editTelegramMessage(e,o,m,p,{replyMarkup:u}):p&&await this.sendTelegramMessage(e,o,p,{replyMarkup:u})}async deleteTelegramStandaloneApprovalMessage(e,t,n){[...this.telegramProgress.entries.values()].find(i=>i.messageId===n&&i.route?.bridgeId===e.id&&i.route?.chatId===t)||await this.deleteTelegramMessage(e,t,n).catch(i=>{this.logWarn({bridgeId:e.id,chatId:t,messageId:n,error:Wu(i)},"telegram callback message delete failed")})}chatAiSessionBindingActive(e,t,n,i){return this.service.listChatSessions().some(s=>s.bridgeId===e.id&&s.chatSessionId===t&&s.activeInstanceId===n&&s.activeAiSessionId===i)}telegramAiSessionActionAllowed(e,t,n,i,s){if(this.chatAiSessionBindingActive(e,t,n,i))return!0;if(!Number.isInteger(s))return!1;const r=this.telegramReplyAiSessionTarget(e.id,t,s);return Boolean(r&&r.instanceId===n&&r.sessionId===i)}async parseChatGatewayCallbackAction(e){const t=function(e){const t=e.match(/^task_handoff:cp_p:v1:([ads]):([A-Za-z0-9_-]{16})$/);if(!t)return;const n=Object.entries(yl).find(([,e])=>e===t[1])?.[0];return"allow"===n||"deny"===n||"skip"===n?{routeFingerprint:t[2],decision:n}:void 0}(e);if(t){const e=(await this.service.listPendingRoutes()).filter(e=>"approval"===e.kind&&"pending"===e.status&&fl(e.id)===t.routeFingerprint);if(1!==e.length){const e=new Error("This approval is no longer pending.");throw Object.assign(e,{statusCode:409,code:"CHAT_PENDING_ACTION_STALE"}),e}return{type:"pending-decision",routeId:e[0].id,decision:t.decision}}return function(e,t){const n=e.match(/^task_handoff:cp_session:(\d+)$/);if(n)return{type:"ai-session",index:Number(n[1])};const i=e.match(/^task_handoff:cp_i:([^:]+)$/)||e.match(/^task_handoff:cp_instance_apps:([^:]+)$/);if(i)return i[0].startsWith("task_handoff:cp_i:")?{type:"instance-app-menu",instanceId:fp(t(i[1],"instance-app-menu").instanceId,"instanceId")}:{type:"instance-app-menu",instanceId:vp(i[1])};const s=e.match(/^task_handoff:cp_a:([^:]+)$/)||e.match(/^task_handoff:cp_launch_app:([^:]+):([^:]+)$/);if(s){if(s[0].startsWith("task_handoff:cp_a:")){const e=t(s[1],"launch-app");return{type:"launch-app",instanceId:fp(e.instanceId,"instanceId"),appId:fp(e.appId,"appId")}}return{type:"launch-app",instanceId:vp(s[1]),appId:vp(s[2])}}const r=e.match(/^task_handoff:cp_p:([^:]+)$/);if(r){const e=t(r[1],"pending-decision");return{type:"pending-decision",routeId:fp(e.routeId,"routeId"),decision:Ip(e.decision)}}const o=e.match(/^task_handoff:approval:([^:]+:ai:[^:]+):(allow|deny|skip)$/);return o?{type:"pending-decision",routeId:o[1],decision:o[2]}:void 0}(e,(e,t)=>this.service.resolveChatActionToken(e,t))}dingdingAllowed(e,t){const n=String(t||"").trim();return!!n&&(0===e.allowedUserIds.length?(e.allowedUserIds=[n],this.updateChatBridge(e.id,{allowedUserIds:e.allowedUserIds}),this.logInfo({bridgeId:e.id,userId:n},"dingding user bound"),!0):e.allowedUserIds.includes(n))}larkAllowed(e,t){const n=String(t||"").trim();return!!n&&(0===e.allowedUserIds.length?(e.allowedUserIds=[n],this.updateChatBridge(e.id,{allowedUserIds:e.allowedUserIds}),this.logInfo({bridgeId:e.id,userId:n},"lark user bound"),!0):e.allowedUserIds.includes(n))}telegramAllowed(e,t){const n=String(t||"").trim();return!!n&&(0===e.allowedUserIds.length?(e.allowedUserIds=[n],this.updateChatBridge(e.id,{allowedUserIds:e.allowedUserIds}),this.logInfo({bridgeId:e.id,userId:n},"telegram user bound"),!0):e.allowedUserIds.includes(n))}async answerTelegramCallback(e,t,n){return async function(e,t,n,i){t.token&&n&&await e(`https://api.telegram.org/bot${t.token}/answerCallbackQuery`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({callback_query_id:n,text:i.slice(0,200)})})}(this.fetchImpl,e,t,n)}async editTelegramMessage(e,t,n,i,s={}){return async function(e,t,n,i,s,r={}){if(t.token)return hp(n=>e(`https://api.telegram.org/bot${t.token}/editMessageText`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)}),"editMessageText",s,{chat_id:n,message_id:i,...r.replyMarkup?{reply_markup:r.replyMarkup}:{}},r)}(this.fetchImpl,e,t,n,i,s)}async sendTelegramMessage(e,t,n,i={}){return mp(this.fetchImpl,e,t,n,i)}async deleteTelegramMessage(e,t,n){return async function(e,t,n,i){if(!t.token||!Number.isInteger(i))return;const s=await e(`https://api.telegram.org/bot${t.token}/deleteMessage`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({chat_id:n,message_id:i})}),r=await s.json().catch(()=>({}));if(!s.ok||!1===r.ok)throw new Error(r.description||`Telegram deleteMessage failed with HTTP ${s.status}`)}(this.fetchImpl,e,t,n)}async rememberTelegramProgressMessage(e,t,n,i,s){if(!0!==e.routed)return;const r=Zu(e),{instanceId:o,sessionId:a,turnId:d}=r,c=Number(Yu(i).message_id);if(!(o&&a&&d&&Number.isInteger(c)))return void this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,messageId:Number.isInteger(c)?c:void 0,routed:e.routed},"telegram ai session progress message not remembered");const l=rm(o,a,d,t.id,n),p=this.telegramProgress.remember(l,c,s,{bridgeId:t.id,chatId:n});this.telegramProgressMessageTargets.set(Uu(t.id,n,c),{instanceId:o,sessionId:a,turnId:d,messageId:c}),this.deliveredAiSessionFingerprints.delete(l),this.logInfo({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,key:l,messageId:c,progressKeys:this.telegramProgressKeysFor(o,a,t.id,n),textPreview:Vu(s)},"telegram ai session progress message remembered"),"queue"===function(e){return e.aiSession&&"action"in e.aiSession?e.aiSession.action:void 0}(e)&&p?.messageId&&p.messageId!==c&&(this.telegramProgressMessageTargets.delete(Uu(t.id,n,p.messageId)),await this.deleteTelegramMessage(t,n,p.messageId).catch(e=>{this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,replacedMessageId:p.messageId,replacementMessageId:c,error:Wu(e)},"telegram queued progress message replacement cleanup failed")}))}telegramReplyAiSessionTarget(e,t,n){const i=this.telegramProgressMessageTargets.get(Uu(e,t,n));if(i)return i;for(const[i,s]of this.telegramProgress.entries)if(s.messageId===n&&s.route?.bridgeId===e&&s.route?.chatId===t){const s=Fu(i,e,t);if(s){const i={...s,messageId:n};return this.telegramProgressMessageTargets.set(Uu(e,t,n),i),i}}}async pollAiSessionUpdates(){this.logAiSessionDelivery({stage:"poll-tick"});const e=await this.service.listAiSessions({refresh:!0}).catch(()=>{});if(!e)return void this.logAiSessionDelivery({stage:"poll-no-snapshot"});const t=new Map(e.instances.map(e=>[e.instanceId,e.aiSessions]));this.logAiSessionDelivery({stage:"poll-snapshot",instanceCount:t.size,instances:[...t.entries()].map(([e,t])=>({instanceId:e,sessionCount:t.sessions?.length||0,runningCount:t.runningCount,waitingCount:t.waitingCount,updatedAt:t.updatedAt}))});const n=await this.aiSessionInstanceNames();for(const[e,i]of t)await this.deliverAiSessionSnapshot(e,i,n)}async deliverAiSessionSnapshot(e,t,n){const i=Array.isArray(t.sessions)?t.sessions:[];if(this.pruneAiSessionDeliveryState(e,new Set(i.map(e=>e.id))),0===i.length)return;const s=n||await this.aiSessionInstanceNames(),r=await this.aiSessionPendingApprovalRoutes(e);await this.deliverOwnedTelegramProgress(e,i,s,r),await this.deliverActiveBindingTelegramProgress(e,i,s,r)}pruneAiSessionDeliveryState(e,t){for(const[n,i]of this.telegramProgress.entries){const s=i.route?.bridgeId&&i.route.chatId?this.telegramProgressMessageTargets.get(Uu(i.route.bridgeId,i.route.chatId,i.messageId||0))||Fu(n,i.route.bridgeId,i.route.chatId):void 0;s&&s.instanceId===e&&!t.has(s.sessionId)&&(i.timer&&clearTimeout(i.timer),this.telegramProgress.entries.delete(n),this.deliveredAiSessionFingerprints.delete(n),i.route?.bridgeId&&i.route.chatId&&i.messageId&&this.telegramProgressMessageTargets.delete(Uu(i.route.bridgeId,i.route.chatId,i.messageId)))}}async deliverActiveBindingTelegramProgress(e,t,n,i){for(const s of this.service.listChatSessions()){if(!s.bridgeId||s.activeInstanceId!==e||!s.activeAiSessionId)continue;const r=t.find(e=>e.id===s.activeAiSessionId);if(!r)continue;const o=lm(n.get(e)||e,r),a=cm(r,o);if(!a){this.logAiSessionDelivery({stage:"skip-empty-text",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:Ju(um(r))});continue}const d=om(r);if(!d){this.logAiSessionDelivery({stage:"skip-empty-turn-id",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:Ju(um(r))});continue}if(this.listTelegramOwnedProgressEntries(e).some(e=>e.route.bridgeId===s.bridgeId&&e.route.chatId===s.chatSessionId&&e.owner.sessionId===r.id&&e.owner.turnId===d))continue;const c=rm(e,r.id,d,s.bridgeId||"",s.chatSessionId),l=am(r,o);if(!l||this.deliveredAiSessionFingerprints.get(c)===l){this.logAiSessionDelivery({stage:"skip-duplicate-fingerprint",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,turnId:d,key:c,hasFingerprint:Boolean(l),fingerprintMatched:this.deliveredAiSessionFingerprints.get(c)===l,latestTurn:Ju(um(r)),textPreview:Vu(a)});continue}const p=nm({cancelCallbackData:this.telegramAiSessionCallbacks.cancelCallbackData(e,r.id),queueSteerCallbackData:t=>this.telegramAiSessionCallbacks.queueSteerCallbackData(e,r.id,t),queueDeleteMenuCallbackData:()=>this.telegramAiSessionCallbacks.queueDeleteMenuCallbackData(e,r.id),permissionCallbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),pendingApproval:i.get(r.id)||im(e,r),session:r});if(this.logAiSessionDelivery({stage:"attempt",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,turnId:d,key:c,relatedProgressKeys:this.telegramProgressKeysFor(e,r.id,s.bridgeId||"",s.chatSessionId),hasProgressEntry:this.telegramProgress.entries.has(c),status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:Ju(um(r)),textPreview:Vu(a)}),await this.updateChatAiSessionProgress(s,a,c,p).catch(t=>(this.bridgeErrors.set(s.bridgeId||"",t instanceof Error?t.message:String(t)),this.logWarn({bridgeId:s.bridgeId,chatId:s.chatSessionId,instanceId:e,sessionId:r.id,turnId:d,key:c,error:Wu(t)},"chat ai session progress update failed"),!1)))this.logAiSessionDelivery({stage:"delivered",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,turnId:d,key:c,textPreview:Vu(a)}),this.deliveredAiSessionFingerprints.set(c,l);else{if("telegram"===this.service.requireChatBridge(s.bridgeId).channel){const t=this.telegramProgress.entries.get(c),n=this.service.requireChatBridge(s.bridgeId);this.logAiSessionDelivery({stage:t?"telegram-update-not-delivered":"telegram-no-progress-entry",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,turnId:d,key:c,relatedProgressKeys:this.telegramProgressKeysFor(e,r.id,s.bridgeId||"",s.chatSessionId),bridgeEnabled:n.enabled,bridgeChannel:n.channel,progressMessageId:t?.messageId,progressLastText:Vu(t?.lastText),progressHasPending:Boolean(t?.pending),latestTurn:Ju(um(r)),textPreview:Vu(a)});continue}await this.sendToChatBinding(s,{text:a}).catch(e=>(this.bridgeErrors.set(s.bridgeId||"",e instanceof Error?e.message:String(e)),!1))&&(this.logAiSessionDelivery({stage:"fallback-sent",instanceId:e,sessionId:r.id,bridgeId:s.bridgeId,chatId:s.chatSessionId,turnId:d,key:c,textPreview:Vu(a)}),this.deliveredAiSessionFingerprints.set(c,l))}}}async deliverOwnedTelegramProgress(e,t,n,i){for(const s of this.listTelegramOwnedProgressEntries(e)){const r=this.service.requireChatBridge(s.route.bridgeId);if("telegram"!==r.channel||!r.enabled)continue;const o=this.matchTelegramOwnedProgressSession(s,t);if(!o)continue;const a={bridgeId:s.route.bridgeId,chatSessionId:s.route.chatId},d=lm(n.get(e)||e,o),c=cm(o,d),l=om(o);if(!c||!l){this.logAiSessionDelivery({stage:"remembered-skip-turn-or-text",key:s.key,parsedTurnId:s.owner.turnId,currentTurnId:l,hasText:Boolean(c),instanceId:e,sessionId:o.id,bridgeId:s.route.bridgeId,chatId:s.route.chatId});continue}if(s.owner.turnId&&l!==s.owner.turnId){this.logAiSessionDelivery({stage:"remembered-skip-different-active-turn",key:s.key,ownerTurnId:s.owner.turnId,currentTurnId:l,instanceId:e,sessionId:o.id,bridgeId:s.route.bridgeId,chatId:s.route.chatId});continue}const p=l===s.owner.turnId?s.key:rm(e,o.id,l,s.route.bridgeId,s.route.chatId);if(p!==s.key&&this.telegramProgress.entries.has(p))continue;if(p!==s.key&&!this.rekeyTelegramOwnedProgress(s,p,{instanceId:e,sessionId:o.id,turnId:l}))continue;const u=am(o,d);if(!u||this.deliveredAiSessionFingerprints.get(p)===u){this.logAiSessionDelivery({stage:"remembered-skip-fingerprint",key:s.key,hasFingerprint:Boolean(u),fingerprintMatched:this.deliveredAiSessionFingerprints.get(p)===u,instanceId:e,sessionId:o.id,bridgeId:s.route.bridgeId,chatId:s.route.chatId});continue}const m=nm({cancelCallbackData:this.telegramAiSessionCallbacks.cancelCallbackData(e,o.id),queueSteerCallbackData:t=>this.telegramAiSessionCallbacks.queueSteerCallbackData(e,o.id,t),queueDeleteMenuCallbackData:()=>this.telegramAiSessionCallbacks.queueDeleteMenuCallbackData(e,o.id),permissionCallbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),pendingApproval:i.get(o.id)||im(e,o),session:o}),g=await this.updateChatAiSessionProgress(a,c,p,m).catch(e=>(this.bridgeErrors.set(a.bridgeId||"",e instanceof Error?e.message:String(e)),!1));this.logAiSessionDelivery({stage:g?"remembered-delivered":"remembered-not-delivered",key:p,instanceId:e,sessionId:o.id,bridgeId:s.route.bridgeId,chatId:s.route.chatId,textPreview:Vu(c)}),g&&(this.telegramProgressMessageTargets.set(Uu(s.route.bridgeId,s.route.chatId,s.messageId),{instanceId:e,sessionId:o.id,turnId:l,messageId:s.messageId}),this.deliveredAiSessionFingerprints.set(p,u))}}rekeyTelegramOwnedProgress(e,t,n){return!!this.telegramProgress.rekey(e.key,t)&&(this.deliveredAiSessionFingerprints.delete(e.key),this.telegramProgressMessageTargets.set(Uu(e.route.bridgeId,e.route.chatId,e.messageId),{...n,messageId:e.messageId}),!0)}logAiSessionDelivery(e){this.logInfo(e,"telegram ai session delivery flow")}telegramProgressKeysFor(e,t,n,i){const s=`${e}:${t}:`,r=`:${n}:${i}`;return[...this.telegramProgress.entries.keys()].filter(e=>e.startsWith(s)&&e.endsWith(r))}listTelegramOwnedProgressEntries(e){const t=[];for(const[n,i]of this.telegramProgress.entries){if(!i.route?.bridgeId||!i.route.chatId||!Number.isInteger(i.messageId))continue;const s=this.telegramProgressMessageTargets.get(Uu(i.route.bridgeId,i.route.chatId,i.messageId))||Fu(n,i.route.bridgeId,i.route.chatId);s&&s.instanceId===e&&t.push({key:n,route:{bridgeId:i.route.bridgeId,chatId:i.route.chatId},messageId:i.messageId,owner:{...s,messageId:i.messageId}})}return t}matchTelegramOwnedProgressSession(e,t){const n=t.find(t=>t.id===e.owner.sessionId);if(n)return n;if(e.owner.turnId){const n=t.find(t=>t.activeTurnId===e.owner.turnId||um(t)?.id===e.owner.turnId||um(t)?.providerTurnId===e.owner.turnId);if(n)return n}}async updateChatAiSessionProgress(e,t,n,i){if(!e.bridgeId)return this.logAiSessionDelivery({stage:"chat-update-skip-missing-bridge",chatId:e.chatSessionId,key:n}),!1;const s=this.service.requireChatBridge(e.bridgeId);if(!s.enabled)return this.logAiSessionDelivery({stage:"chat-update-skip-bridge-state",bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,bridgeEnabled:s.enabled,bridgeChannel:s.channel}),!1;if("dingding"===s.channel){if(!this.dingdingBridges.get(s.id))return!1;const r=await this.dingdingBridges.applyProgressUpdate({bridge:s,key:n,chatId:e.chatSessionId,text:t,replyMarkup:$u({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:Vu(t)},"dingding ai session progress updated"),r}if("lark"===s.channel){const r=await this.larkBridges.applyProgressUpdate({bridge:s,key:n,chatId:e.chatSessionId,text:t,replyMarkup:$u({actionRows:i})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:Vu(t)},"lark ai session progress updated"),r}if("telegram"!==s.channel)return!1;const r=this.telegramProgress.entries.get(n);if(!await this.telegramProgress.applyUpdate({bridge:s,key:n,chatId:e.chatSessionId,text:t,actionRows:i})){const t=this.telegramProgress.entries.get(n);return this.logAiSessionDelivery({stage:"telegram-update-returned-false",bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,progressMessageId:r?.messageId||t?.messageId,progressLastText:Vu(r?.lastText||t?.lastText),progressHasPending:Boolean(r?.pending||t?.pending)}),!1}return this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,messageId:r?.messageId||this.telegramProgress.entries.get(n)?.messageId,textPreview:Vu(t)},r?"telegram ai session progress edited":"telegram ai session progress sent"),!0}async aiSessionInstanceNames(){return this.aiSessionInstanceNamesCache.get()}async aiSessionPendingApprovalRoutes(e){const t=await this.aiSessionPendingRoutesCache.get();return new Map(t.filter(t=>t.instanceId===e&&t.aiSessionId&&"approval"===t.kind).map(e=>[e.aiSessionId||"",e]))}}function Mu(e){return"object"==typeof e&&e&&"reply"in e?String(e.reply||""):""}function Lu(e){return"object"==typeof e&&null!==e&&!0===e.accepted}function qu(e){const t="object"==typeof e&&e&&"replyMarkup"in e?e.replyMarkup:void 0;if(t&&"object"==typeof t&&!Array.isArray(t))return t}function $u(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return kl(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function Bu(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function Uu(e,t,n){return[e,t,String(n)].join(":")}function Fu(e,t,n){const i=`:${t}:${n}`;if(!e.endsWith(i))return;const s=e.slice(0,-i.length).split(":"),r=s[0]||"",o=s[1]||"",a=s.slice(2).join(":")||void 0;return r&&o?{instanceId:r,sessionId:o,turnId:a}:void 0}function Hu(e){return"string"==typeof e?e:""}function Wu(e){return e instanceof Error?e.message:String(e)}function Gu(e,t){return Boolean(e&&"object"==typeof e&&"code"in e&&e.code===t)}function Vu(e,t=160){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function Ku(e){const t=Qu(e.body.cardActionData||e.body.content),n=Qu(t.cardPrivateData||e.body.cardPrivateData||e.body.content);return{outTrackId:Hu(e.body.outTrackId),spaceId:Hu(e.body.spaceId),conversationType:e.conversationType,hasCallbackData:Boolean(e.callbackData),callbackDataPreview:Vu(e.callbackData,120),actionIds:[...Xu(n.actionIdList),...Xu(t.actionIdList),Hu(n.actionId),Hu(t.actionId),Hu(e.body.actionId)].filter(Boolean).slice(0,5),cardActionDataKeys:Object.keys(t).sort(),privateDataKeys:Object.keys(n).sort(),paramKeys:Object.keys(e.params).sort(),hasSessionWebhook:Boolean(e.sessionWebhook)}}function Ju(e){if(e)return{id:e.id,providerTurnId:e.providerTurnId,source:e.source,status:e.status,phase:e.phase,revision:e.revision,userPrompt:Vu(e.userPrompt,80),hasResponse:Boolean(e.lastMessage?.trim()||e.summary?.trim()),responsePreview:Vu(e.lastMessage||e.summary,80),updatedAt:e.updatedAt,observedAt:e.observedAt}}function Yu(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Qu(e){if(e&&"object"==typeof e&&!Array.isArray(e))return e;if("string"==typeof e&&e.trim())try{return Yu(JSON.parse(e))}catch{return{}}return{}}function Xu(e){return Array.isArray(e)?e.map(e=>Hu(e)).filter(Boolean):[]}function Zu(e){const t=e.aiSession&&"session"in e.aiSession?e.aiSession:void 0,n=t?.session||(e.aiSession&&"id"in e.aiSession?e.aiSession:void 0);return{instanceId:e.instanceId||e.instance?.id||"",sessionId:e.aiSessionId||n?.id||e.binding?.activeAiSessionId||"",turnId:e.turnId||e.providerTurnId||t?.turnId||t?.providerTurnId||(n?om(n):""),sources:{resultTurnId:e.turnId,resultProviderTurnId:e.providerTurnId,actionTurnId:t?.turnId,actionProviderTurnId:t?.providerTurnId,sessionActiveTurnId:n?.activeTurnId,latestTurnId:n?um(n)?.id:void 0}}}const em=5,tm=48;function nm(e){const{cancelCallbackData:t,queueSteerCallbackData:n,queueDeleteMenuCallbackData:i,permissionCallbackData:s,pendingApproval:r,session:o}=e,a="approval"===r?.kind?[[{text:"Allow",callbackData:s(r.id,"allow")},{text:"Skip",callbackData:s(r.id,"skip")},{text:"Deny",callbackData:s(r.id,"deny")}]]:[];if("running"!==o.status)return a;const d=(o.queue?.items||[]).filter(e=>"queued"===e.status).slice(0,em);return[...d.map((e,t)=>[{text:sm(e.message,t),callbackData:n(e.id)}]),d.length?[{text:"Delete Queue",callbackData:i()},{text:"Cancel",callbackData:t}]:[{text:"Cancel",callbackData:t}]]}function im(e,t){if("approval"===t.phase)return{id:`${e}:ai:${t.id}`,kind:"approval"}}function sm(e,t){const n=`${t+1}. `,i=e.replace(/\s+/g," ").trim()||"Queued message",s=Math.max(8,tm-n.length),r=Array.from(i);return`${n}${r.length>s?`${r.slice(0,Math.max(1,s-3)).join("")}...`:i}`}function rm(e,t,...n){return[e,t,...n].join(":")}function om(e){const t=um(e);return t?.id?t.id:Hu(e.activeTurnId)}function am(e,t=""){const n=um(e);return[t,n?.id||"",n?.status||e.status||"",n?.phase||e.phase||"",n?.lastMessage||"",n?.summary||"",n?.userPrompt||"",e.error||"",e.currentTool?.id||"",e.currentTool?.name||"",e.currentTool?.inputPreview||"",String(e.toolCallsSinceLastMessage??0),dm(e)].join("\0")}function dm(e){return(e.queue?.items||[]).map(e=>[e.id,e.status,e.message].join(":")).join("|")}function cm(e,t){const n=function(e,t){let n="";t?"waiting"===t.status&&"approval"===t.phase&&t.summary?.trim()?n=t.summary.trim():t.lastMessage?.trim()?n=t.lastMessage.trim():t.summary?.trim()&&(n=t.summary.trim()):"waiting"===e.status&&"approval"===e.phase&&e.summary?.trim()?n=e.summary.trim():e.lastMessage?.trim()?n=e.lastMessage.trim():e.summary?.trim()?n=e.summary.trim():e.error?.trim()&&(n="failed"===e.status?`${e.agent} session failed:\n${e.error.trim()}`:e.error.trim());const i=function(e){if(e.currentTool?.name)return`Thinking... · ${e.currentTool.name}${e.currentTool.inputPreview?` · ${e.currentTool.inputPreview}`:""}`;const t=e.toolCallsSinceLastMessage??0;return t>0?`Thinking... · ${t} ${1===t?"tool":"tools"} completed`:""}(e);return[n,i&&!pm(n,e)?i:""].filter(Boolean).join("\n\n")}(e,um(e));return n?`${t}\n${n}`:""}function lm(e,t){const n=["idle"===t.status?"completed":t.status,t.phase&&"unknown"!==t.phase?t.phase:void 0].filter(Boolean).join("/");return`${e} · ${t.agent||"ai"} ${n||"unknown"}`}function pm(e,t){if("waiting"!==t.status||"approval"!==t.phase)return!1;const n=t.currentTool?.inputPreview?.trim();return Boolean(n&&e.includes(n))}function um(e){return(e.turns||[]).filter(e=>e.id||e.userPrompt?.trim()||e.lastMessage?.trim()||e.summary?.trim()).at(-1)}class mm{clients=new Set;listeners=new Set;seq=0;connect(e,t={}){e.topics=new Set(["*"]),e.instanceIds=t.instanceIds?.length?new Set(t.instanceIds):void 0,this.clients.add(e),e.on("close",()=>{this.clients.delete(e)}),e.on("message",t=>{const n=function(e){try{const t=JSON.parse(String(e||"{}"));if(!t||"object"!=typeof t)return;const n=t;return{type:n.type,topics:Array.isArray(n.topics)?n.topics.map(String).filter(Boolean):void 0,instanceIds:Array.isArray(n.instanceIds)?n.instanceIds.map(String).map(e=>e.trim()).filter(Boolean):void 0}}catch{return}}(t);"subscribe"===n?.type&&(e.topics=new Set(n.topics?.length?n.topics:["*"]),e.instanceIds=n.instanceIds?.length?new Set(n.instanceIds):void 0)})}publish(e,t,n={}){const i=this.createEvent(e,t,n),s=i.topic,r=JSON.stringify(i);for(const e of this.listeners)try{e(i)}catch{this.listeners.delete(e)}for(const t of this.clients)if(t.readyState===t.OPEN&&gm(t.topics,s,e)&&hm(t.instanceIds,i.scope))try{t.send(r)}catch{this.clients.delete(t)}return i}on(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}send(e,t,n,i={}){const s=this.createEvent(t,n,i);return e.send(JSON.stringify(s)),s}createEvent(e,t,n={}){return{v:1,id:`evt_${Date.now().toString(36)}_${Math.random().toString(16).slice(2)}`,seq:++this.seq,type:e,topic:n.topic||Xr(e),createdAt:(new Date).toISOString(),payload:t,scope:n.scope}}}function gm(e,t,n){return!e||e.has("*")||e.has(t)||e.has(n)}function hm(e,t){return!e||!t?.instanceId||e.has(t.instanceId)}const ym={"image/bmp":".bmp","image/gif":".gif","image/jpeg":".jpg","image/png":".png","image/webp":".webp"},fm=a.z.object({instanceId:a.z.string().trim().min(1).max(120),sessionId:a.z.string().trim().min(1).max(120),kind:a.z.enum(["image","file"]),name:a.z.string().trim().min(1).max(240),mime:a.z.string().trim().min(1).max(120),data:a.z.string().min(1).max(31457280)}).strict();function Im(){return t.join(y.tmpdir(),"task-handoff-ai-session-attachments")}class bm{items=new Map;ttlMs;constructor(e=864e5){this.ttlMs=e,this.pruneOrphanFiles()}upload(e){this.pruneExpired();const s=fm.parse(e),r=function(e,t){const n=/^data:([^;,]+);base64,(.+)$/i.exec(e.trim()),i=n?.[1]||t,s=n?.[2]||e;return{mime:i,buffer:Buffer.from(s,"base64")}}(s.data,s.mime),o=r.mime.toLowerCase(),a=ym[o]||"";if("image"===s.kind&&!a)throw new Error(`Unsupported image type: ${o}`);const d="image"===s.kind?r.buffer.length>E:r.buffer.length>=C;if(!r.buffer.length||d)throw new Error("image"===s.kind?"Image must be between 1 byte and 20971520 bytes.":"File must be smaller than 512000 bytes.");const c=`att_${i.randomUUID().replace(/-/g,"").slice(0,24)}`,l=new Date,p=new Date(l.getTime()+this.ttlMs),u=Im();n.mkdirSync(u,{recursive:!0});const m=function(e){return t.basename(e).replace(/[^\w.\- ()\u4e00-\u9fff]/g,"_").slice(0,160)||"attachment"}(s.name),g=t.join(u,`${c}-${m.endsWith(a)?m:`${m}${a}`}`);n.writeFileSync(g,r.buffer);const h={id:c,instanceId:s.instanceId,sessionId:s.sessionId,kind:s.kind,name:m,mime:o,size:r.buffer.length,source:{type:"inline",encoding:"base64",data:r.buffer.toString("base64")},path:g,createdAt:l.toISOString(),expiresAt:p.toISOString()};return this.items.set(c,h),this.publicAttachment(h)}resolveRefs(e,t,n){this.pruneExpired();const i=a.z.array(oe).max(6).default([]).parse(e),s=i.map(e=>"runtime-path"===e.source.type?se.parse(e):this.requireAttachment(e,t,n));if(s.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>x)throw new Error("Inline attachments must be 41943040 bytes or less in total.");for(const e of i)"upload-ref"===e.source.type&&this.consumeAttachment(e.id);return s}dispose(){for(const e of[...this.items.keys()])this.consumeAttachment(e)}requireAttachment(e,t,n){const i=this.items.get(e.id);if(!i)throw new Error(`AI session attachment not found or expired: ${e.id}`);if(e.kind&&e.kind!==i.kind)throw new Error(`AI session attachment kind mismatch: ${e.id}`);if(i.instanceId!==t||i.sessionId!==n)throw new Error(`AI session attachment scope mismatch: ${e.id}`);return se.parse({id:i.id,kind:i.kind,name:i.name,mime:i.mime,size:i.size,source:i.source})}consumeAttachment(e){const t=this.items.get(e);if(t){this.items.delete(e);try{n.unlinkSync(t.path)}catch{}}}publicAttachment(e){return{id:e.id,kind:e.kind,name:e.name,mime:e.mime,size:e.size,expiresAt:e.expiresAt}}pruneExpired(){const e=Date.now();for(const[t,i]of this.items)if(!(Date.parse(i.expiresAt)>e)){this.items.delete(t);try{n.unlinkSync(i.path)}catch{}}this.pruneOrphanFiles()}pruneOrphanFiles(){const e=Im();let i;try{i=n.readdirSync(e)}catch{return}const s=Date.now()-Math.max(this.ttlMs,864e5);for(const r of i){const i=t.join(e,r);try{n.statSync(i).isFile()&&n.statSync(i).mtimeMs<=s&&n.unlinkSync(i)}catch{}}}}const vm={controlPlaneAuthBoundary:"public"},wm={controlPlaneAuthBoundary:"public-ui"},Sm={controlPlaneAuthBoundary:"proxy-binding"},Am={controlPlaneAuthBoundary:"node-tunnel"};class km{attempt=0;timer;get pending(){return Boolean(this.timer)}get attempts(){return this.attempt}schedule(e,t={}){if(this.timer)return;const n=function(e,t=Math.random){const n=Math.min(3e4,1e3*2**Math.max(0,e));return Math.min(3e4,Math.round(n*(.75+.5*t())))}(this.attempt,t.random);this.attempt+=1;const i=t.setTimeoutFn||setTimeout;return this.timer=i(()=>{this.timer=void 0,e()},n),{attempt:this.attempt,delay:n}}reset(e=clearTimeout){this.timer&&e(this.timer),this.timer=void 0,this.attempt=0}cancel(e=clearTimeout){this.timer&&e(this.timer),this.timer=void 0}}function zm(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function Tm(e){return e.unref?.(),e}class Em{connectTimeoutMs;handshakeTimeoutMs;heartbeatIntervalMs;heartbeatTimeoutMs;stableThresholdMs;now;setTimeoutFn;clearTimeoutFn;ping;onTimeout;onStable;onPhase;connectTimer;handshakeTimer;heartbeatTimer;stableTimer;awaitingPongSince;stable=!1;stopped=!1;currentPhase="connecting";lastActivityAt;lastPongAt;constructor(e){this.connectTimeoutMs=zm(e.connectTimeoutMs,1e4),this.handshakeTimeoutMs=zm(e.handshakeTimeoutMs,1e4),this.heartbeatIntervalMs=zm(e.heartbeatIntervalMs,25e3),this.heartbeatTimeoutMs=zm(e.heartbeatTimeoutMs,1e4),this.stableThresholdMs=zm(e.stableThresholdMs,6e4),this.now=e.now||Date.now,this.setTimeoutFn=e.setTimeoutFn||setTimeout,this.clearTimeoutFn=e.clearTimeoutFn||clearTimeout,this.ping=e.ping,this.onTimeout=e.onTimeout,this.onStable=e.onStable,this.onPhase=e.onPhase}get phase(){return this.currentPhase}start(){this.stopped=!1,this.setPhase("connecting"),this.clearTimer("connectTimer"),this.connectTimer=Tm(this.setTimeoutFn(()=>this.timeout("connect"),this.connectTimeoutMs))}opened(){this.stopped||(this.clearTimer("connectTimer"),this.setPhase("handshaking"),this.handshakeTimer=Tm(this.setTimeoutFn(()=>this.timeout("handshake"),this.handshakeTimeoutMs)),this.scheduleHeartbeat(this.heartbeatIntervalMs))}healthy(){this.stopped||(this.clearTimer("handshakeTimer"),this.activity(),this.setPhase("healthy"),this.stable||this.stableTimer||(this.stableTimer=Tm(this.setTimeoutFn(()=>{this.stableTimer=void 0,this.stopped||"healthy"!==this.currentPhase||(this.stable=!0,this.onStable?.())},this.stableThresholdMs))))}activity(){this.stopped||(this.lastActivityAt=this.now())}pong(){if(this.stopped)return;const e=this.now();this.awaitingPongSince=void 0,this.lastPongAt=e,this.lastActivityAt=e,this.scheduleHeartbeat(this.heartbeatIntervalMs)}close(){this.stopped||(this.stopped=!0,this.clearTimers(),this.awaitingPongSince=void 0,this.setPhase("closed"))}diagnostics(){return{phase:this.currentPhase,stable:this.stable,...void 0===this.lastActivityAt?{}:{lastActivityAt:new Date(this.lastActivityAt).toISOString()},...void 0===this.lastPongAt?{}:{lastPongAt:new Date(this.lastPongAt).toISOString()}}}scheduleHeartbeat(e){this.stopped||(this.clearTimer("heartbeatTimer"),this.heartbeatTimer=Tm(this.setTimeoutFn(()=>{if(this.heartbeatTimer=void 0,!this.stopped){if(void 0!==this.awaitingPongSince){const e=Math.max(0,this.now()-this.awaitingPongSince);return e>=this.heartbeatTimeoutMs?void this.timeout("heartbeat"):void this.scheduleHeartbeat(this.heartbeatTimeoutMs-e)}this.awaitingPongSince=this.now();try{this.ping()}catch{return void this.timeout("heartbeat")}this.scheduleHeartbeat(this.heartbeatTimeoutMs)}},e)))}timeout(e){this.stopped||(this.clearTimers(),this.setPhase("failed"),this.onTimeout(e))}setPhase(e){this.currentPhase!==e&&(this.currentPhase=e,this.onPhase?.(e))}clearTimers(){this.clearTimer("connectTimer"),this.clearTimer("handshakeTimer"),this.clearTimer("heartbeatTimer"),this.clearTimer("stableTimer")}clearTimer(e){const t=this[e];t&&this.clearTimeoutFn(t),this[e]=void 0}}class Cm{transport;constructor(e){this.transport=e}attachMain(e,t){this.transport.attach(e,t),t.send(JSON.stringify({type:"control-plane.hello",protocolVersion:"2026-08-01",nodeId:e,serverTime:(new Date).toISOString(),capabilities:{reverseTunnel:"request-response",auxiliaryChannels:!0,httpResponseStreaming:!0,lifecycleCommands:!0,instanceApiProxy:!0}})),t.on("message",n=>this.handleMainMessage(e,t,n))}attachAuxiliary(e,t,n){return this.transport.attachAuxiliary(e,t,n)}handleMainMessage(e,t,n){if(!this.transport.isCurrentSocket(e,t))return;let i;try{i=JSON.parse(String(n))}catch{return void t.send(JSON.stringify({type:"control-plane.error",code:"INVALID_JSON"}))}const s=i&&"object"==typeof i?i:{},r=this.transport.handleSocketMessage(e,t,s);if(void 0!==r&&!r){if("node-agent.ping"!==s.type)return"node-agent.identify"===s.type?(this.transport.markHealthy(e,t),void t.send(JSON.stringify({type:"control-plane.identified",nodeId:e,serverTime:(new Date).toISOString()}))):void t.send(JSON.stringify({type:"control-plane.error",code:"UNSUPPORTED_MESSAGE"}));t.send(JSON.stringify({type:"control-plane.pong",nodeId:e,serverTime:(new Date).toISOString()}))}}}const xm={[N]:rt,[O]:ot,[_]:at,[R]:dt,[P]:ct,[ht]:Et,[yt]:Ct,[ft]:xt},Nm=new Set(Object.keys(xm));class Om{options;validatedScopes=new Map;validatingScopes=new Map;eventQueues=new Map;scopeEpochs=new Map;constructor(e={}){this.options=e}handle(e,t){const n="string"==typeof t.type?t.type:"";if("node-agent.streams.hello"===n){const n="string"==typeof t.instanceId?t.instanceId:"",i=Bo(to,t.payload);return n&&i.success&&this.enqueue(e,n,()=>this.options.onStreamsHello?.(n,i.data)),!0}if(!n.startsWith("node-agent.event."))return!1;const i=_m(t.event),s="string"==typeof i?.type?i.type:"";if(!s)return!0;const r="payload"in i?i.payload:{},o=_m(i.scope)||{},a="string"==typeof t.instanceId?t.instanceId:void 0,d=function(...e){return e.find(e=>"string"==typeof e)}(o.instanceId,i.instanceId,a);if("instance.metrics.snapshot"===s){const t=Bo(br,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(s,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(s===Lr){const t=Bo(qr,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(s,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(s===dr||s===cr){const t=Bo(s===dr?pr:ur,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(s,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(Nm.has(s)){const t=function(e,t){const n=xm[e];if(!n)return;const i=Bo(n,t);if(!i.success)return;const s=i.data;return{instanceId:"meta"in s?s.meta.instanceId:s.instanceId,payload:s}}(s,r);return!t||([o.instanceId,i.instanceId,a].filter(e=>"string"==typeof e&&Boolean(e)).some(e=>e!==t.instanceId)||this.enqueue(e,t.instanceId,()=>{const n={...o,nodeId:e,instanceId:t.instanceId},r={v:1,id:"string"==typeof i.id?i.id:`forwarded_${Date.now().toString(36)}`,seq:"number"==typeof i.seq?i.seq:0,type:s,topic:"string"==typeof i.topic?i.topic:s.startsWith("app-session.")?"app.sessions":"ai.sessions",createdAt:"string"==typeof i.createdAt?i.createdAt:(new Date).toISOString(),payload:t.payload,scope:n};this.options.onSessionEvent&&!this.options.onSessionEvent(r)||this.options.events?.publish(s,t.payload,{topic:r.topic,scope:n})}),!0)}const c=()=>{this.options.events?.publish(s,r,{topic:"string"==typeof i.topic?i.topic:void 0,scope:{...o,nodeId:e,...d?{instanceId:d}:{}}})};return d?this.enqueue(e,d,c):c(),!0}invalidate(e={}){const t=new Set;for(const[n,i]of this.validatedScopes)e.nodeId&&i.nodeId!==e.nodeId||e.instanceId&&i.instanceId!==e.instanceId||t.add(n);for(const n of new Set([...this.validatingScopes.keys(),...this.eventQueues.keys()])){const[i,s]=Pm(n);e.nodeId&&i!==e.nodeId||e.instanceId&&s!==e.instanceId||t.add(n)}for(const e of t)this.scopeEpochs.delete(e),this.validatedScopes.delete(e),this.validatingScopes.delete(e),this.eventQueues.delete(e)}diagnostics(){return{validatedScopes:this.validatedScopes.size,validatingScopes:this.validatingScopes.size,queuedScopes:this.eventQueues.size,scopeEpochs:this.scopeEpochs.size}}enqueue(e,t,n){const i=Rm(e,t),s=this.scopeEpoch(i),r=(this.eventQueues.get(i)||Promise.resolve()).catch(()=>{}).then(async()=>{this.scopeEpochs.get(i)===s&&await this.isScopeValid(e,t,s)&&this.scopeEpochs.get(i)===s&&await n()});this.eventQueues.set(i,r);const o=()=>{this.eventQueues.get(i)===r&&this.eventQueues.delete(i),this.scopeEpochs.get(i)!==s||this.eventQueues.has(i)||this.validatingScopes.has(i)||this.scopeEpochs.delete(i)};r.then(o,o)}async isScopeValid(e,t,n){const i=Rm(e,t);if((this.validatedScopes.get(i)?.expiresAt||0)>Date.now())return!0;const s=this.validatingScopes.get(i);if(s)return s;const r=Promise.resolve(this.options.validateInstanceScope?.(e,t)).then(Boolean).catch(()=>!1).then(s=>(s&&this.scopeEpochs.get(i)===n&&this.validatedScopes.set(i,{nodeId:e,instanceId:t,expiresAt:Date.now()+(this.options.scopeTtlMs??3e4)}),s));return this.validatingScopes.set(i,r),r.finally(()=>{this.validatingScopes.get(i)===r&&this.validatingScopes.delete(i)})}scopeEpoch(e){const t=this.scopeEpochs.get(e);if(t)return t;const n={};return this.scopeEpochs.set(e,n),n}}function _m(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function Rm(e,t){return JSON.stringify([e,t])}function Pm(e){const t=JSON.parse(e);return Array.isArray(t)&&2===t.length?[String(t[0]),String(t[1])]:["",""]}const jm=a.z.object({nodeId:a.z.string().trim().min(1).max(120)}).strict();function Dm(){return`req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}const Mm=new Map;function Lm(e,t){if("paired-hmac"!==e.auth.mode||!e.auth.keyId||!e.auth.secret){const e=new Error("Reverse tunnel requires paired-HMAC node auth.");throw Object.assign(e,{statusCode:401,code:"NODE_AGENT_TUNNEL_REQUIRES_PAIRED_HMAC"}),e}const n=function(e){const t=new Map;for(const[n,i]of Object.entries(e)){const e=Array.isArray(i)?i.join(","):"string"==typeof i?i:void 0===i?"":String(i);t.set(n.toLowerCase(),e)}return{nodeId:t.get("x-taskhandoff-node-id")||"",keyId:t.get("x-taskhandoff-key-id")||"",timestamp:t.get("x-taskhandoff-timestamp")||"",nonce:t.get("x-taskhandoff-nonce")||"",bodySha256:t.get("x-taskhandoff-body-sha256")||"",signature:t.get("x-taskhandoff-signature")||""}}(t.headers);if(n.nodeId!==e.id)throw Object.assign(new Error("Invalid reverse tunnel node id."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NODE_MISMATCH"});if(n.keyId!==e.auth.keyId)throw Object.assign(new Error("Invalid reverse tunnel key id."),{statusCode:401,code:"NODE_AGENT_TUNNEL_KEY_INVALID"});const s=Date.parse(n.timestamp);if(!Number.isFinite(s)||Math.abs(Date.now()-s)>nd)throw Object.assign(new Error("Reverse tunnel timestamp is outside the allowed window."),{statusCode:401,code:"NODE_AGENT_TUNNEL_TIMESTAMP_INVALID"});const r=Date.now()-nd;for(const[e,t]of Mm)t<=r&&Mm.delete(e);const o=`${e.id}:${n.keyId}:${n.nonce}`;if(!n.nonce||Mm.has(o))throw Object.assign(new Error("Reverse tunnel nonce is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NONCE_INVALID"});const a=rd("");if(n.bodySha256!==a)throw Object.assign(new Error("Reverse tunnel body hash is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_BODY_HASH_INVALID"});const d=t.url||`${id}?nodeId=${encodeURIComponent(e.id)}`,c=od(e.auth.secret,{keyId:n.keyId,method:"GET",pathWithQuery:d,timestamp:n.timestamp,nonce:n.nonce,bodySha256:a});if(!function(e,t){const n=Buffer.from(e,"hex"),s=Buffer.from(t,"hex");return n.length===s.length&&i.timingSafeEqual(n,s)}(n.signature,c))throw Object.assign(new Error("Reverse tunnel signature is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_SIGNATURE_INVALID"});Mm.set(o,Date.now()+nd)}function qm(e){return e?e instanceof Headers?Object.fromEntries(e.entries()):Array.isArray(e)?Object.fromEntries(e.map(([e,t])=>[e,t])):Object.fromEntries(Object.entries(e).map(([e,t])=>[e,String(t)])):{}}class $m{sockets=new Map;eventRouter;httpStreamHeaderTimeoutMs;requestTimeoutMs;auxiliaryAttachTimeoutMs;connectionRuntime;connectionOptions;constructor(e,t={}){this.eventRouter=new Om({events:e,onStreamsHello:t.onStreamsHello,onSessionEvent:t.onSessionEvent,validateInstanceScope:t.validateInstanceScope}),this.httpStreamHeaderTimeoutMs=t.httpStreamHeaderTimeoutMs??3e4,this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.auxiliaryAttachTimeoutMs=t.auxiliaryAttachTimeoutMs??3e4,this.connectionRuntime=t.connectionRuntime,this.connectionOptions=t}attach(e,t){const n=this.sockets.get(e);if(n?.socket===t)return;n&&this.invalidateInstanceScope({nodeId:e});const i=new Map,s={socket:t,runtimeGeneration:this.connectionRuntime?.begin(e,"reverse-wss","handshaking"),pending:i,streams:new Map,httpStreams:new Map,pendingChannels:new Map},r=new Em({...this.connectionOptions,ping:()=>t.ping?.(),onTimeout:n=>{this.sockets.get(e)===s&&(void 0!==s.runtimeGeneration&&this.connectionRuntime?.update(e,s.runtimeGeneration,{phase:"suspect",error:`Reverse tunnel ${n} timeout.`}),t.terminate?t.terminate():t.close?.(1011,`Reverse tunnel ${n} timeout.`))},onStable:()=>{void 0!==s.runtimeGeneration&&this.connectionRuntime?.stable(e,s.runtimeGeneration)}});s.supervisor=r,this.sockets.set(e,s),r.start(),r.opened(),t.on?.("pong",()=>{this.sockets.get(e)===s&&(r.pong(),void 0!==s.runtimeGeneration&&this.connectionRuntime?.pong(e,s.runtimeGeneration))}),t.on?.("close",()=>this.detach(e,t)),t.on?.("error",()=>this.detach(e,t)),n&&n.socket!==t&&this.finalizeConnection(n,new Error(`Reverse tunnel for node ${e} was replaced.`),"Reverse tunnel was replaced.",!0)}detach(e,t){const n=this.sockets.get(e);!n||t&&n.socket!==t||(this.sockets.delete(e),n.supervisor?.close(),void 0!==n.runtimeGeneration&&this.connectionRuntime?.disconnected(e,n.runtimeGeneration,{error:"Reverse tunnel disconnected."}),this.invalidateInstanceScope({nodeId:e}),this.finalizeConnection(n,new Error(`Reverse tunnel for node ${e} disconnected.`),"Reverse tunnel disconnected.",!0))}disconnect(e,t="Node connection disabled locally."){const n=this.sockets.get(e);return!!n&&(this.detach(e,n.socket),n.socket.close?.(1e3,t),!0)}connected(e){return this.sockets.has(e)}markHealthy(e,t){const n=this.sockets.get(e);return!(!n||n.socket!==t||void 0===n.runtimeGeneration)&&(n.supervisor?.healthy(),this.connectionRuntime?.connected(e,n.runtimeGeneration)??!0)}finalizeConnection(e,t,n,i){e.supervisor?.close();for(const n of[...e.pending.keys()])this.cancelPendingRequest(e,n,t,!1);for(const[t,i]of e.streams)e.streams.delete(t),i.downstream.close(1011,n);for(const i of[...e.httpStreams.keys()])this.cancelHttpStream(e,i,t,n,!1);for(const t of e.pendingChannels.values())clearTimeout(t.timer);if(e.pendingChannels.clear(),i&&e.socket.close&&3!==e.socket.readyState)try{e.socket.close(1e3,n)}catch{}}isCurrentSocket(e,t){return this.sockets.get(e)?.socket===t}handleSocketMessage(e,t,n){if(this.isCurrentSocket(e,t))return this.handleMessage(e,n)}handleMessage(e,t){if(this.eventRouter.handle(e,t))return!0;if(this.handleWebSocketMessage(e,t))return!0;if("node-agent.response"!==t.type)return!1;const n="string"==typeof t.requestId?t.requestId:"",i=this.sockets.get(e),s=i?.pending.get(n);if(!s||!i)return!0;i.pending.delete(n),clearTimeout(s.timer),s.signal&&s.onAbort&&s.signal.removeEventListener("abort",s.onAbort);const r=Number(t.status)||502,o=t.headers&&"object"==typeof t.headers?t.headers:{},a="string"==typeof t.body?t.body:"";if(t.error&&"object"==typeof t.error){const e=t.error,n=new Error("string"==typeof e.message?e.message:`Reverse tunnel request failed with HTTP ${r}`);return Object.assign(n,{statusCode:r,code:"string"==typeof e.code?e.code:"NODE_AGENT_REVERSE_REQUEST_FAILED"}),s.reject(n),!0}return s.resolve(new Response(a,{status:r,headers:o})),!0}invalidateInstanceScope(e={}){this.eventRouter.invalidate(e)}instanceScopeDiagnostics(){return this.eventRouter.diagnostics()}async request(e,t,n={}){const i=this.sockets.get(e.id);if(!i){const t=new Error(`Reverse tunnel for node ${e.id} is not connected.`);throw Object.assign(t,{statusCode:503,code:"NODE_AGENT_REVERSE_TUNNEL_OFFLINE"}),t}const s=Dm(),r=Ti(n.body),o={type:"control-plane.request",requestId:s,route:t,init:{method:n.method||"GET",headers:qm(n.headers),body:r}};return new Promise((r,a)=>{let d;if(d={resolve:r,reject:a,timer:setTimeout(()=>{const n=new Error(`Reverse tunnel request to ${e.id}${t} timed out.`);Object.assign(n,{statusCode:504,code:"NODE_AGENT_REVERSE_REQUEST_TIMEOUT"}),this.cancelPendingRequest(i,s,n)},this.requestTimeoutMs),signal:n.signal||void 0},n.signal&&(d.onAbort=()=>{this.cancelPendingRequest(i,s,Object.assign(new Error("Reverse tunnel request was aborted."),{name:"AbortError",code:"ABORT_ERR"}))},n.signal.addEventListener("abort",d.onAbort,{once:!0})),i.pending.set(s,d),n.signal?.aborted)d.onAbort?.();else try{i.socket.send(JSON.stringify(o))}catch(e){this.cancelPendingRequest(i,s,e instanceof Error?e:new Error(String(e)),!1)}})}cancelPendingRequest(e,t,n,i=!0){const s=e.pending.get(t);if(!s)return!1;if(e.pending.delete(t),clearTimeout(s.timer),s.signal&&s.onAbort&&s.signal.removeEventListener("abort",s.onAbort),s.reject(n),i)try{e.socket.send(JSON.stringify({type:"control-plane.request.cancel",requestId:t}))}catch{}return!0}async requestStream(e,t,n={}){const i=this.sockets.get(e.id);if(!i)throw Object.assign(new Error(`Reverse tunnel for node ${e.id} is not connected.`),{statusCode:503,code:"NODE_AGENT_REVERSE_TUNNEL_OFFLINE"});const s=Dm(),r=Ti(n.body);return new Promise((o,a)=>{const d={resolve:o,reject:a,timer:setTimeout(()=>{this.cancelHttpStream(i,s,Object.assign(new Error(`Reverse tunnel stream to ${e.id}${t} timed out.`),{statusCode:504,code:"NODE_AGENT_REVERSE_STREAM_TIMEOUT"}),"Reverse HTTP stream header timeout.")},this.httpStreamHeaderTimeoutMs),settled:!1,finalized:!1,signal:n.signal||void 0};if(i.httpStreams.set(s,d),this.registerPendingChannel(i,{id:s,attach:t=>this.attachHttpStreamChannel(e.id,s,t),cancel:(e,t)=>{this.cancelHttpStream(i,s,e,t)}},"Reverse HTTP channel attach timed out."),n.signal&&(d.onAbort=()=>this.cancelHttpStream(i,s,Object.assign(new Error("Reverse HTTP stream consumer disconnected."),{name:"AbortError",code:"ABORT_ERR"}),"HTTP consumer disconnected."),n.signal.addEventListener("abort",d.onAbort,{once:!0}),n.signal.aborted))d.onAbort();else try{i.socket.send(JSON.stringify({type:"control-plane.http.open",streamId:s,route:t,init:{method:n.method||"GET",headers:qm(n.headers),body:r}}))}catch(e){this.cancelHttpStream(i,s,e instanceof Error?e:new Error(String(e)),"Reverse tunnel send failed.",!1)}})}cancelHttpStream(e,t,n,i,s=!0){const r=e.httpStreams.get(t);if(!r||r.finalized)return!1;if(r.finalized=!0,e.httpStreams.delete(t),this.removePendingChannel(e,t),clearTimeout(r.timer),r.signal&&r.onAbort&&r.signal.removeEventListener("abort",r.onAbort),r.settled?r.body?.destroy(n):(r.settled=!0,r.reject(n)),1===r.socket?.readyState&&r.socket.close(1e3,i),s)try{e.socket.send(JSON.stringify({type:"control-plane.http.cancel",streamId:t,reason:i}))}catch{}return!0}completeHttpStream(e,t){const n=e.httpStreams.get(t);return!(!n||n.finalized||(n.finalized=!0,e.httpStreams.delete(t),this.removePendingChannel(e,t),clearTimeout(n.timer),n.signal&&n.onAbort&&n.signal.removeEventListener("abort",n.onAbort),n.body?.end(),0))}attachAuxiliary(e,t,n){const i=this.sockets.get(e),s=i?.pendingChannels.get(t);return i&&s?(this.removePendingChannel(i,t),s.attach(n)):(n.close(1008,"Unknown reverse tunnel channel."),!1)}registerPendingChannel(e,t,n){this.removePendingChannel(e,t.id),t.timer=setTimeout(()=>{e.pendingChannels.get(t.id)===t&&(e.pendingChannels.delete(t.id),t.cancel(Object.assign(new Error(n),{code:"NODE_AGENT_REVERSE_CHANNEL_ATTACH_TIMEOUT"}),n))},this.auxiliaryAttachTimeoutMs),t.timer.unref?.(),e.pendingChannels.set(t.id,t)}removePendingChannel(e,t){const n=e.pendingChannels.get(t);return n?.timer&&clearTimeout(n.timer),e.pendingChannels.delete(t),n}attachHttpStream(e,t,n){return this.attachAuxiliary(e,t,n)}attachHttpStreamChannel(e,t,n){const i=this.sockets.get(e),s=i?.httpStreams.get(t);if(!i||!s)return n.close(1008,"Unknown reverse HTTP stream."),!1;s.socket=n;const r=e=>{this.cancelHttpStream(i,t,e,"Reverse HTTP stream failed.")};return n.on("message",(e,o)=>{if(s.finalized||i.httpStreams.get(t)!==s)return;if(o)return s.body?void(s.body.write(Buffer.isBuffer(e)?e:Buffer.from(e))||(n.pause?.(),s.body.once("drain",()=>n.resume?.()))):r(new Error("Reverse HTTP stream received data before response headers."));let a;try{a=JSON.parse(String(e))}catch{return void r(new Error("Reverse HTTP stream sent invalid JSON control data."))}if("node-agent.http.head"===a.type){if(s.settled)return;clearTimeout(s.timer);const e=Number(a.status)||502,n=a.headers&&"object"==typeof a.headers?a.headers:{},r=new m.PassThrough({highWaterMark:65536});return s.body=r,s.settled=!0,r.once("close",()=>{this.cancelHttpStream(i,t,new Error("Reverse HTTP stream consumer closed."),"HTTP consumer closed.")}),void s.resolve(new Response(m.Readable.toWeb(r),{status:e,headers:n}))}"node-agent.http.end"!==a.type?"node-agent.http.error"===a.type&&r(new Error("string"==typeof a.message?a.message:"Reverse HTTP stream failed.")):s.settled?this.completeHttpStream(i,t):r(new Error("Reverse HTTP stream ended before response headers."))}),n.on("close",()=>{r(new Error("Reverse HTTP stream disconnected."))}),n.on("error",()=>r(new Error("Reverse HTTP stream failed."))),!0}proxyWebSocket(e,t,n,i,s={}){const r=e.id,o=this.sockets.get(r);if(!o)return void t.close(1011,"Reverse tunnel is not connected.");const a=Dm(),d=e=>{try{o.socket.send(JSON.stringify(e))}catch{this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,"Reverse tunnel send failed.")}},c={downstream:t,pendingFrames:[]};o.streams.set(a,c),this.registerPendingChannel(o,{id:a,attach:e=>this.attachWebSocketStreamChannel(r,a,e),cancel:(e,n)=>{this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,n)}},"Reverse websocket channel attach timed out."),d({type:"control-plane.websocket.open",streamId:a,route:n,protocols:Array.isArray(i)?i:i?[i]:[],headers:s}),t.on("message",(e,n)=>{const i=o.streams.get(a);if(i&&!i.upstream)return i.pendingFrames.length>=256?(this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,"Reverse websocket stream pending frame limit exceeded."),void d({type:"control-plane.websocket.close",streamId:a,code:1011,reason:"Reverse websocket stream pending frame limit exceeded."})):void i.pendingFrames.push({data:e,isBinary:Boolean(n)})}),t.on("close",(e,t)=>{const n=o.streams.get(a);if(n){this.removePendingChannel(o,a),o.streams.delete(a);const i=Qa(e),s=Ya(t);n.upstream&&Xa(n.upstream,i,s),d({type:"control-plane.websocket.close",streamId:a,...void 0===i?{}:{code:i},...s?{reason:s}:{}})}}),t.on("error",()=>{const e=o.streams.get(a);e&&(this.removePendingChannel(o,a),o.streams.delete(a),e.upstream?.close(1011,"Downstream websocket failed."),d({type:"control-plane.websocket.close",streamId:a,code:1011,reason:"Downstream websocket failed."}))})}attachWebSocketStream(e,t,n){return this.attachAuxiliary(e,t,n)}attachWebSocketStreamChannel(e,t,n){const i=this.sockets.get(e),s=i?.streams.get(t);if(!i||!s)return n.close(1008,"Unknown reverse websocket stream."),!1;s.upstream=n;for(const e of s.pendingFrames.splice(0))n.send(e.data,{binary:e.isBinary});return ed(s.downstream,n,{pendingFrameLimit:256,onClientClose:()=>{this.removePendingChannel(i,t),i.streams.delete(t)},onClientError:()=>{this.removePendingChannel(i,t),i.streams.delete(t)},onUpstreamClose:()=>{this.removePendingChannel(i,t),i.streams.delete(t)},onUpstreamError:()=>{this.removePendingChannel(i,t),i.streams.delete(t)}}),!0}handleWebSocketMessage(e,t){const n="string"==typeof t.type?t.type:"";if(!n.startsWith("node-agent.websocket."))return!1;const i=this.sockets.get(e),s="string"==typeof t.streamId?t.streamId:"",r=i?.streams.get(s);return!r||("node-agent.websocket.close"===n?(i&&this.removePendingChannel(i,s),i?.streams.delete(s),Xa(r.downstream,t.code,t.reason),!0):"node-agent.websocket.error"!==n||(i&&this.removePendingChannel(i,s),i?.streams.delete(s),r.downstream.close(1011,"string"==typeof t.message?t.message:"Reverse websocket proxy failed."),!0))}}class Bm{sockets=new Map;socketUrls=new Map;retries=new Map;supervisors=new Map;runtimeGenerations=new Map;service;tunnel;safetyIntervalMs;logger;connectionRuntime;createSocket;connectionOptions;reconnectAttempts=0;safetyReconciliations=0;timer;running=!1;constructor(e,t,n={}){var i;this.service=e,this.tunnel=t,this.safetyIntervalMs=(i=n.safetyIntervalMs,Math.min(6e4,Math.max(3e4,i??45e3))),this.logger=n.logger,this.connectionRuntime=n.connectionRuntime,this.connectionOptions=n,this.createSocket=n.createSocket||((e,t)=>new l.WebSocket(e,t))}start(){this.running||(this.running=!0,this.sync(),this.timer=setInterval(()=>{this.safetyReconciliations+=1,this.sync()},this.safetyIntervalMs))}stop(){this.running=!1,this.timer&&(clearInterval(this.timer),this.timer=void 0);for(const e of this.sockets.values())e.close();for(const e of this.supervisors.values())e.close();this.sockets.clear(),this.socketUrls.clear(),this.supervisors.clear(),this.runtimeGenerations.clear();for(const e of this.retries.values())e.timer.cancel();this.retries.clear()}syncNow(){this.sync()}diagnostics(){return{reconnectAttempts:this.reconnectAttempts,safetyReconciliations:this.safetyReconciliations,activeConnections:this.sockets.size,pendingRetries:[...this.retries.values()].filter(e=>e.timer.pending).length,safetyIntervalMs:this.safetyIntervalMs,connections:[...this.supervisors.entries()].map(([e,t])=>({nodeId:e,...t.diagnostics()}))}}sync(){const e=new Set;for(const t of this.service.listNodes()){const n=this.nodeEventsUrl(t);if(!n)continue;e.add(t.id);const i=this.retries.get(t.id);if(i?.timer.pending&&i.url!==n&&(i.timer.cancel(),this.retries.delete(t.id)),this.socketUrls.get(t.id)!==n&&this.sockets.has(t.id)){const e=this.sockets.get(t.id),n=this.runtimeGenerations.get(t.id);this.supervisors.get(t.id)?.close(),this.sockets.delete(t.id),this.socketUrls.delete(t.id),this.supervisors.delete(t.id),this.runtimeGenerations.delete(t.id),void 0!==n&&this.connectionRuntime?.disconnected(t.id,n,{error:"Direct event endpoint changed."}),e?.close()}this.sockets.has(t.id)||this.retries.get(t.id)?.timer.pending||this.connect(t,n)}for(const[t,n]of this.sockets)if(!e.has(t)){const e=this.runtimeGenerations.get(t);this.supervisors.get(t)?.close(),this.sockets.delete(t),this.socketUrls.delete(t),this.supervisors.delete(t),this.runtimeGenerations.delete(t),void 0!==e&&this.connectionRuntime?.disconnected(t,e,{error:"Direct event connection is no longer configured."}),n.close();const i=this.retries.get(t);i?.timer.cancel(),this.retries.delete(t)}for(const[t,n]of this.retries)e.has(t)||(n.timer.cancel(),this.retries.delete(t),this.socketUrls.delete(t))}connect(e,t){const n=ad(t),i=n?void 0:new URL(t),s=sd(e,{method:"GET",pathWithQuery:i?`${i.pathname}${i.search}`:"/api/node-agent/events"}),r=n?cd(n,"/events",void 0,s):this.createSocket(t,{headers:s}),o=this.connectionRuntime?.begin(e.id,"direct-http","connecting");void 0!==o&&this.runtimeGenerations.set(e.id,o);const a=this.retries.get(e.id)?.timer||new km;this.retries.set(e.id,{timer:a,url:t});const d=new Em({...this.connectionOptions,ping:()=>r.ping(),onTimeout:t=>{this.sockets.get(e.id)===r&&(void 0!==o&&this.connectionRuntime?.update(e.id,o,{phase:"suspect",error:`Direct event WebSocket ${t} timeout.`}),r.terminate())},onStable:()=>{a.reset(),void 0!==o&&this.connectionRuntime?.stable(e.id,o)}});this.sockets.set(e.id,r),this.socketUrls.set(e.id,t),this.supervisors.set(e.id,d),d.start(),r.on("open",()=>{this.sockets.get(e.id)===r&&(d.opened(),void 0!==o&&this.connectionRuntime?.update(e.id,o,{phase:"handshaking"}))}),r.on("message",t=>{if(this.sockets.get(e.id)!==r)return;let n;try{n=JSON.parse(String(t))}catch{return}if(n&&"object"==typeof n&&!Array.isArray(n)){d.activity(),"healthy"!==d.phase&&(d.healthy(),void 0!==o&&this.connectionRuntime?.connected(e.id,o));const t=n,i="string"==typeof t.type&&t.type.startsWith("node-agent.")?t:{type:"node-agent.event.forwarded",event:t};this.tunnel.handleMessage(e.id,i)}}),r.on("pong",()=>{this.sockets.get(e.id)===r&&(d.pong(),void 0!==o&&this.connectionRuntime?.pong(e.id,o))}),r.on("close",(t,n)=>{this.sockets.get(e.id)===r&&(d.close(),this.sockets.delete(e.id),this.socketUrls.delete(e.id),this.supervisors.delete(e.id),this.runtimeGenerations.delete(e.id),this.scheduleReconnect(e.id,{generation:o,closeCode:"number"==typeof t?t:void 0,error:Buffer.isBuffer(n)?n.toString("utf8"):String(n||"Direct event WebSocket disconnected.")}))}),r.on("error",()=>{this.sockets.get(e.id)===r&&r.terminate()})}scheduleReconnect(e,t={}){const n=this.service.listNodes().find(t=>t.id===e),i=n&&this.nodeEventsUrl(n);if(!this.running||!n||!i)return void(void 0!==t.generation&&this.connectionRuntime?.disconnected(e,t.generation,t));const s=this.retries.get(e)??{timer:new km};if(s.timer.pending)return;s.url=i;const r=s.timer.schedule(()=>{this.running&&!this.sockets.has(e)&&this.connect(n,i)});r&&(this.reconnectAttempts+=1,void 0!==t.generation&&this.connectionRuntime?.disconnected(e,t.generation,{...t,nextRetryAt:new Date(Date.now()+r.delay).toISOString()}),this.logger?.info?.({nodeId:e,url:i,attempt:r.attempt,delay:r.delay,reconnectAttempts:this.reconnectAttempts},"session-stream.node-connection.reconnect-scheduled")),this.retries.set(e,s)}nodeEventsUrl(e){if(!1===e.connectionEnabled)return;const t=e.controlEndpoint||e.endpoint;if(t&&"reverse-wss"!==e.connectionMode){if(ad(t))return t;try{const e=new URL("/api/node-agent/events",t.replace(/\/$/,""));return e.protocol="https:"===e.protocol?"wss:":"ws:",e.toString()}catch{return}}}}function Um(e=function(){return process.env.TASK_HANDOFF_CONTROL_PLANE_DATA_DIR||t.join(y.homedir(),".config","task-handoff","control-plane")}()){const n=t.resolve(e);return{dataDir:n,settingsPath:t.join(n,"control-plane-settings.json"),projectsDir:t.join(n,"projects"),modelsDir:t.join(n,"models"),imagesDir:t.join(n,"images"),marketDir:t.join(n,"market"),marketCachePath:t.join(n,"market","catalog-cache.json"),marketStatePath:t.join(n,"market","catalog-state.json"),marketMigrationBackupPath:t.join(n,"market","legacy-image-migration-backup.json"),nodesDir:t.join(n,"nodes"),pendingPairingRevokesDir:t.join(n,"pending-pairing-revokes"),chatSessionsDir:t.join(n,"chat-sessions"),chatBridgesDir:t.join(n,"chat-bridges"),triggersDir:t.join(n,"triggers"),proxyAuthorityPath:t.join(n,"control-plane-proxy","authority.json"),identitySigningPath:t.join(n,"control-plane-identity-signing.json"),cloudConnectivityPath:t.join(n,"cloud-connectivity.json"),authUsersDir:t.join(n,"auth-users"),authSessionsDir:t.join(n,"auth-sessions"),aiSessionUnreadDir:t.join(n,"ai-session-unread"),logsDir:t.join(n,"logs")}}class Fm extends Error{code;lockPath;owner;constructor(e,t,n={}){const i=t?.pid?` pid ${t.pid}`:"";super(`${n.label||"Process"} is already running${i}. Lock: ${e}`),this.name="ProcessSingletonError",this.code=n.code||"PROCESS_ALREADY_RUNNING",this.lockPath=e,this.owner=t}}function Hm(e){return t.join(e,"owner.json")}function Wm(e){return t.join(e,"initializing.json")}function Gm(e){return t.join(e,"recovering.json")}function Vm(e){return Number.isInteger(e)&&Number(e)>0}function Km(e,t=process.platform){if(Vm(e)){if("linux"===t)try{const t=n.readFileSync(`/proc/${e}/stat`,"utf8"),i=t.lastIndexOf(")");if(i<0)return;const s=t.slice(i+2).trim().split(/\s+/)[19];return s?`linux:${s}`:void 0}catch{return}if(["darwin","freebsd","openbsd","aix","sunos"].includes(t)){const n=b.spawnSync("ps",["-o","lstart=","-p",String(e)],{encoding:"utf8",timeout:1e3}),i=0===n.status?n.stdout.trim().replace(/\s+/g," "):"";return i?`${t}:${i}`:void 0}if("win32"===t){const t=`(Get-Process -Id ${e} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`,n=b.spawnSync("powershell.exe",["-NoProfile","-NonInteractive","-Command",t],{encoding:"utf8",timeout:2e3}),i=0===n.status?n.stdout.trim():"";return/^\d+$/.test(i)?`win32:${i}`:void 0}}}const Jm=function(e){try{const t=JSON.parse(n.readFileSync(Hm(e),"utf8"));if(Vm(t.pid)&&"string"==typeof t.startTime){const e=t;return{pid:e.pid,hostname:"string"==typeof e.hostname&&e.hostname?e.hostname:y.hostname(),component:e.component||"server-update",command:"string"==typeof e.command?e.command:"",acquiredAt:"string"==typeof e.createdAt&&Number.isFinite(Date.parse(e.createdAt))?e.createdAt:new Date(0).toISOString(),token:"string"==typeof e.token&&e.token?e.token:`legacy:${e.pid}:${e.startTime}`,startIdentity:e.startTime.startsWith("linux:")?e.startTime:`linux:${e.startTime}`}}if(!(Vm(t.pid)&&"string"==typeof t.hostname&&t.hostname&&"string"==typeof t.command&&"string"==typeof t.acquiredAt&&Number.isFinite(Date.parse(t.acquiredAt))&&"string"==typeof t.token&&t.token))return;return t}catch{return}};function Ym(e){if(!Vm(e))return!1;try{return process.kill(Number(e),0),!0}catch(e){return"EPERM"===e.code}}function Qm(e){if(!e||!Ym(e.pid))return!1;if(!e.startIdentity)return!0;const t=Km(e.pid);return void 0===t||t===e.startIdentity}function Xm(e,i){const s=t.join(e,`.owner-${i.token}.tmp`);n.writeFileSync(s,`${JSON.stringify(i,null,2)}\n`,{encoding:"utf8",mode:384,flag:"wx"});const r=eg(e);if(r?.token!==i.token)throw ng(s),new Error(`Process lock initialization was superseded: ${e}`);n.renameSync(s,Hm(e)),ng(Wm(e))}function Zm(e,s,r){const o=Jm(e);if(o?.token!==s.token)return!1;const a={...s};for(const[e,t]of Object.entries(r))void 0===t?delete a[e]:Object.assign(a,{[e]:t});const d=t.join(e,`.owner-update-${s.token}-${i.randomUUID()}.tmp`);try{if(n.writeFileSync(d,`${JSON.stringify(a,null,2)}\n`,{encoding:"utf8",mode:384,flag:"wx"}),Jm(e)?.token!==s.token)return!1;n.renameSync(d,Hm(e));for(const e of Object.keys(s))delete s[e];return Object.assign(s,a),!0}catch(e){if("ENOENT"===e.code)return!1;throw e}finally{ng(d)}}function eg(e){try{return JSON.parse(n.readFileSync(Wm(e),"utf8"))}catch{return}}function tg(e){const t=eg(e);return Vm(t?.pid)&&Qm({pid:t.pid,startIdentity:t.startIdentity})}function ng(e){try{n.unlinkSync(e)}catch(e){if("ENOENT"!==e.code)throw e}}function ig(){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,20)}function sg(e){try{const t=eg(e),i=Date.parse(t?.startedAt||"");return Number.isFinite(i)?Math.max(0,Date.now()-i):Math.max(0,Date.now()-n.statSync(e).mtimeMs)}catch{return 0}}function rg(e,s){try{return n.writeFileSync(Gm(e),`${JSON.stringify({token:s,pid:process.pid,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(r){if("EEXIST"===r.code)return!!function(e){const s=Gm(e),r=og(s),o=Date.parse(r?.startedAt||"");if(Ym(r?.pid)||Number.isFinite(o)&&Date.now()-o<2e3)return!1;const a=t.join(e,`.recovering-${i.randomUUID()}.stale`);try{n.renameSync(s,a)}catch(e){if(["ENOENT","EEXIST"].includes(e.code||""))return!1;throw e}const d=og(a);if(d?.token===r?.token)return ng(a),!0;try{n.linkSync(a,s)}catch(e){if("EEXIST"!==e.code)throw e}finally{ng(a)}return!1}(e)&&rg(e,s);if("ENOENT"===r.code)return!1;throw r}}function og(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return}}function ag(e,t){return og(Gm(e))?.token===t}function dg(){const e=process.env.TASK_HANDOFF_CONTROL_PLANE_LOCK_PATH?.trim();return e?t.resolve(e):t.join(y.tmpdir(),`task-handoff-control-plane-${process.getuid?.()??"user"}.lock`)}function cg(e,s={}){return function(e,s={}){n.mkdirSync(t.dirname(e),{recursive:!0});const r=Km(process.pid),o={pid:process.pid,hostname:y.hostname(),command:process.argv.join(" "),acquiredAt:(new Date).toISOString(),token:i.randomUUID(),...void 0!==s.component?{component:s.component}:{},...r?{startIdentity:r}:{},...void 0!==s.dataDir?{dataDir:s.dataDir}:{},...void 0!==s.host?{host:s.host}:{},...void 0!==s.port?{port:s.port}:{},...void 0!==s.instanceId?{instanceId:s.instanceId}:{}};for(let t=0;t<5;t+=1)try{return n.mkdirSync(e),n.writeFileSync(Wm(e),`${JSON.stringify({token:o.token,pid:o.pid,startIdentity:o.startIdentity,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),Xm(e,o),{lockPath:e,owner:o,updateDetails:t=>Zm(e,o,t),release(){const t=Jm(e);t?.token===o.token&&n.rmSync(e,{recursive:!0,force:!0})}}}catch(r){if("EEXIST"!==r.code)throw r;const o=Jm(e);if(Qm(o))throw new Fm(e,o,s.error);if(!o&&(tg(e)||sg(e)<(s.incompleteLockStaleMs??2e3))){if(t+1<5){ig();continue}throw new Fm(e,void 0,s.error)}const a=i.randomUUID();if(!rg(e,a)){if(t+1<5){ig();continue}throw new Fm(e,Jm(e),s.error)}const d=Jm(e);if(Qm(d))throw ng(Gm(e)),new Fm(e,d,s.error);if(o?.token&&d?.token!==o.token){ng(Gm(e));continue}if(!ag(e,a))continue;n.rmSync(e,{recursive:!0,force:!0})}const a=Jm(e);throw new Fm(e,a,s.error)}(e,{...s,component:"control-plane",error:{label:"Control plane",code:"CONTROL_PLANE_ALREADY_RUNNING"}})}function lg(e,t,n){if(function(e,t,n){return"system"===e.type||("chat-bridge"===e.type?function(e,t){return"ai-session"===t.type?["read","send-message","approve","interrupt"].includes(e):"instance"===t.type?["read","start","stop","restart"].includes(e):"read"===e}(t,n):"cloud-account"===e.type?function(e,t){return!["control-plane-settings","secret","chat-bridge"].includes(t.type)&&("node"===t.type?"read"===e:pg(e,t))}(t,n):"admin"===e.role||("viewer"===e.role?"read"===t:"operator"===e.role&&pg(t,n)))}(e,t,n))return;const i=new Error(`Actor is not allowed to ${t} ${n.type}${n.id?` ${n.id}`:""}.`);throw Object.assign(i,{statusCode:403,code:"CONTROL_PLANE_FORBIDDEN"}),i}function pg(e,t){return"read"===e||("instance"===t.type?["create","update","delete","start","stop","restart","proxy"].includes(e):"ai-session"===t.type?["send-message","approve","interrupt"].includes(e):("trigger"===t.type||"runtime"===t.type)&&["create","update","delete"].includes(e))}const ug=a.z.string().trim().min(1),mg=a.z.object({id:ug}).strict(),gg=a.z.object({id:ug,keyId:ug}).strict(),hg=a.z.object({id:ug,connectionId:ug}).strict(),yg=a.z.object({id:ug,runtimeId:ug}).strict(),fg=a.z.object({id:ug,folderId:ug}).strict(),Ig=a.z.object({id:ug,sessionId:ug}).strict(),bg=a.z.object({id:ug,sessionId:ug,turnId:ug}).strict(),vg=a.z.object({id:ug,sessionId:ug,queueId:ug}).strict(),wg=a.z.object({configHash:ug}).strict(),Sg=a.z.object({id:ug,configHash:ug}).strict(),Ag=a.z.object({id:ug,sessionId:ug,configHash:ug}).strict(),kg=a.z.object({path:a.z.string().optional(),depth:a.z.coerce.number().int().min(0).max(32).optional()}).strict();async function zg(e,t,n){const i=new AbortController,s=()=>i.abort(),r=()=>{t.raw.writableEnded||s()};e.raw.once("aborted",s),t.raw.once("close",r);try{return await n(i.signal)}finally{e.raw.off("aborted",s),t.raw.off("close",r)}}const Tg=a.z.object({ids:a.z.array(a.z.string().trim().min(1).max(120)).default([])}).strict(),Eg=a.z.object({nodeId:a.z.string().trim().min(1).max(120),modelId:a.z.string().trim().min(1).max(120).optional()}).strict(),Cg=a.z.object({source:a.z.object({channel:Fr,bridgeId:a.z.string().trim().min(1).max(120).optional(),chatSessionId:a.z.string().trim().min(1).max(240),userId:a.z.string().trim().max(240).optional()}).strict(),action:a.z.discriminatedUnion("type",[a.z.object({type:a.z.literal("ai-session"),index:a.z.number().int().nonnegative()}).strict(),a.z.object({type:a.z.literal("instance-app-menu"),instanceId:a.z.string().trim().min(1).max(120)}).strict(),a.z.object({type:a.z.literal("launch-app"),instanceId:a.z.string().trim().min(1).max(120),appId:a.z.string().trim().min(1).max(120)}).strict(),a.z.object({type:a.z.literal("pending-decision"),routeId:a.z.string().trim().min(1).max(120),decision:a.z.enum(["allow","deny","skip"])}).strict()])}).strict();function xg(e){const t=Cg.parse(e);if(!t.action)throw new Error("Chat gateway action is required.");return{source:t.source,action:t.action}}const Ng=a.z.object({path:a.z.string().trim().max(1e3).optional(),depth:a.z.coerce.number().int().min(0).max(2).optional()}).strict(),Og=a.z.object({id:a.z.string().trim().min(1),appId:a.z.string().trim().min(1)}).strict(),_g=a.z.object({id:a.z.string().trim().min(1),jobId:a.z.string().trim().min(1)}).strict(),Rg=a.z.object({projection:a.z.literal("directory").optional(),instanceId:a.z.string().trim().min(1).max(120).optional()}).strict();const Pg=a.z.object({id:a.z.string().trim().min(1).max(120)}).strict(),jg=a.z.object({nodeId:a.z.string().trim().min(1).max(120),templateId:a.z.string().trim().min(1).max(120)}).strict(),Dg=a.z.object({force:a.z.enum(["true","false"]).optional()}).strict(),Mg=a.z.object({projection:a.z.literal("directory").optional()}).strict();const Lg=a.z.object({cwdFolderId:a.z.string().trim().min(1).max(120)}).strict(),qg=a.z.object({appId:a.z.string().trim().min(1).max(120).default("terminal-tty"),cwdFolderId:a.z.string().trim().min(1).max(120).optional(),options:a.z.record(a.z.string(),a.z.unknown()).default({})}).strict().default({appId:"terminal-tty",options:{}}),$g=a.z.object({title:a.z.string().trim().min(1).max(120)}).strict(),Bg=a.z.object({token:a.z.string().trim().min(1).max(512)}).strict(),Ug=a.z.object({}).strict();function Fg(e){const{app:t,service:n,events:i,appSessionAggregator:s,aiSessionAggregator:r,aiSessionUnread:o,chatGateway:d,aiSessionAttachments:c,nodeAgentTunnel:l,nodeEventSubscriber:p,errorPayload:u}=e;!function({app:e,service:t,events:n}){e.get("/api/projects",async()=>({data:t.listProjects()})),e.post("/api/projects",async(e,i)=>{const s=t.createProject(e.body);return n.publish("project.created",{projectId:s.id}),i.code(201).send({data:s})}),e.get("/api/projects/:id",async e=>({data:t.requireProject(mg.parse(e.params).id)})),e.patch("/api/projects/:id",async e=>{const i=t.updateProject(mg.parse(e.params).id,e.body);return n.publish("project.updated",{projectId:i.id}),{data:i}}),e.delete("/api/projects/:id",async e=>{const i=mg.parse(e.params).id,s=t.deleteProject(i);return n.publish("project.deleted",{projectId:i,deleted:s}),{data:{deleted:s}}}),e.get("/api/models",async(e,n)=>zg(e,n,async e=>({data:await t.listFederatedModels(e)}))),e.post("/api/models",async(e,i)=>{const s=await t.createModel(e.body);return n.publish("model.created",{modelId:s.id}),i.code(201).send({data:s})}),e.post("/api/models/discover",async e=>({data:await t.discoverModels(e.body)})),e.post("/api/models/test",async e=>({data:await t.testModel(e.body)})),e.post("/api/models/reorder",async e=>{const i=Tg.parse(e.body),s=await t.reorderModels(i.ids);return n.publish("model.reordered",{ids:i.ids}),{data:s}}),e.get("/api/models/:id",async e=>({data:t.requireModel(mg.parse(e.params).id)})),e.patch("/api/models/:id",async e=>{const i=await t.updateModel(mg.parse(e.params).id,e.body);return n.publish("model.updated",{modelId:i.id}),{data:i}}),e.delete("/api/models/:id",async e=>{const i=mg.parse(e.params).id,s=await t.deleteModel(i);return n.publish("model.deleted",{modelId:i,deleted:s}),{data:{deleted:s}}}),e.post("/api/nodes/:nodeId/models",async(e,i)=>{const{nodeId:s}=Eg.parse(e.params),r=await t.createNodeModel(s,e.body);return n.publish("model.created",{modelId:r.id,nodeId:s}),i.code(201).send({data:r})}),e.post("/api/nodes/:nodeId/models/discover",async e=>{const{nodeId:n}=Eg.parse(e.params);return{data:await t.discoverNodeModels(n,e.body)}}),e.post("/api/nodes/:nodeId/models/test",async e=>{const{nodeId:n}=Eg.parse(e.params);return{data:await t.testNodeModel(n,e.body)}}),e.patch("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:i,modelId:s}=Eg.parse(e.params),r=await t.updateNodeModel(i,s,e.body);return n.publish("model.updated",{modelId:s,nodeId:i}),{data:r}}),e.delete("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:i,modelId:s}=Eg.parse(e.params),r=await t.deleteNodeModel(i,s);return n.publish("model.deleted",{modelId:s,nodeId:i,deleted:r.deleted}),{data:r}}),e.get("/api/market/catalog",async()=>({data:t.getMarketCatalog()})),e.post("/api/market/refresh",async()=>{const e=await t.refreshMarketCatalog();return n.publish("market.catalog.updated",{revision:e.catalog.revision,source:e.catalog.source}),{data:e}}),e.get("/api/image-options",async()=>({data:t.listImageOptions()})),e.get("/api/images",async()=>({data:t.listImages()})),e.post("/api/images",async(e,i)=>{const s=t.createImage(e.body);return n.publish("image.created",{imageId:s.id}),i.code(201).send({data:s})}),e.get("/api/images/:id",async e=>({data:t.requireImage(mg.parse(e.params).id)})),e.patch("/api/images/:id",async e=>{const i=t.updateImage(mg.parse(e.params).id,e.body);return n.publish("image.updated",{imageId:i.id}),{data:i}}),e.delete("/api/images/:id",async e=>{const i=mg.parse(e.params).id,s=await t.deleteImage(i);return n.publish("image.deleted",{imageId:i,deleted:s}),{data:{deleted:s}}})}({app:t,service:n,events:i}),function({app:e,service:t,events:n,nodeAgentTunnel:i,nodeEventSubscriber:s,errorPayload:r}){const o=e=>{if(!e||"object"!=typeof e||Array.isArray(e)||!("target"in e))return;const t=e.target;if(!t||"object"!=typeof t||Array.isArray(t)||"controlled-instance"!==t.component)return;const n=new Error("Independent controlled-instance updates were retired; update the Node rollout instead.");throw Object.assign(n,{statusCode:404,code:"LEGACY_INSTANCE_UPDATE_RETIRED"}),n};e.get("/api/nodes",async e=>({data:"directory"===Mg.parse(e.query).projection?t.listNodes().map(e=>function(e){const t=e.proxyState?.lastError;return Dd.parse({id:e.id,name:e.name,status:e.status,health:e.health,connectionMode:e.connectionMode,connectionPhase:e.connectionPhase,lastSeenAt:e.lastSeenAt,observedAt:e.updatedAt,capabilities:Object.keys(e.capabilities).sort(),error:t?{code:t.code,message:"Node connection failed. Use the desktop Control Plane for diagnostics."}:void 0})}(t.projectNodeConnection(e))):t.listPublicNodes()})),e.post("/api/nodes/local/sync",async()=>{const e=await t.syncLocalNodeConnection();return s.syncNow(),n.publish("node.local-synced",{nodeId:e.id}),{data:t.requirePublicNode(e.id)}}),e.post("/api/nodes",async(e,i)=>{const r=await t.createNode(e.body);return s.syncNow(),n.publish("node.created",{nodeId:r.id}),i.code(201).send({data:t.requirePublicNode(r.id)})}),e.post("/api/nodes/:id/check",async e=>{const i=await t.checkNode(mg.parse(e.params).id);return n.publish("node.checked",{nodeId:i.id},{topic:"node.state",scope:{nodeId:i.id}}),{data:i}}),e.get("/api/nodes/:id/updates/jobs",async e=>({data:await t.listNodeUpdateJobs(mg.parse(e.params).id)})),e.get("/api/nodes/:id/settings/external-listener",async e=>({data:await t.getLocalNodeExternalListener(mg.parse(e.params).id)})),e.patch("/api/nodes/:id/settings/external-listener",async e=>{const i=mg.parse(e.params).id,s=await t.updateLocalNodeExternalListener(i,e.body);return n.publish("node.external-listener.updated",{nodeId:i,bindScope:s.bindScope,port:s.port}),{data:s}}),e.post("/api/nodes/:id/updates/check",async e=>{o(e.body);const i=mg.parse(e.params).id,s=await t.checkNodeUpdate(i,ks.parse(e.body));return n.publish("node.update.checked",{nodeId:i,availableVersion:s.availableVersion,impact:s.impact}),{data:s}}),e.post("/api/nodes/:id/updates/apply",async(e,i)=>{o(e.body);const s=mg.parse(e.params).id,r=await t.applyNodeUpdate(s,Es.parse(e.body));return n.publish("node.update.queued",{nodeId:s,updateJobId:r.id,desiredVersion:r.toVersion,impact:r.impact}),i.code(202).send({data:r})}),e.post("/api/nodes/:id/pairing/invites",async(e,i)=>{const s=mg.parse(e.params),r=await t.createNodePairingInvite(s.id,e.body);return n.publish("node.pairing-invite.created",{nodeId:s.id}),i.code(201).send({data:r})}),e.post("/api/nodes/:id/control-plane-connections",async e=>{const i=mg.parse(e.params),s=await t.connectNodeToControlPlane(i.id,e.body);return n.publish("node.remote-connect.requested",{nodeId:i.id}),{data:s}}),e.get("/api/nodes/:id/control-plane-pairings",async e=>{const n=mg.parse(e.params);return{data:await t.listNodeControlPlanePairings(n.id)}}),e.delete("/api/nodes/:id/control-plane-pairings/:keyId",async e=>{const i=gg.parse(e.params),s=await t.deleteNodeControlPlanePairing(i.id,i.keyId);return n.publish("node.control-plane-pairing.deleted",{nodeId:i.id,keyId:i.keyId}),{data:s}}),e.get("/api/nodes/:id/control-plane-connections",async e=>{const n=mg.parse(e.params);return{data:await t.listNodeControlPlaneConnections(n.id)}}),e.delete("/api/nodes/:id/control-plane-connections/:connectionId",async e=>{const i=hg.parse(e.params),s=await t.deleteNodeControlPlaneConnection(i.id,i.connectionId);return n.publish("node.control-plane-connection.deleted",{nodeId:i.id,connectionId:i.connectionId}),{data:s}}),e.post("/api/node-join/invites",async(e,i)=>{const s=t.createNodeJoinInvite(e.body);return n.publish("node-join.invite.created",{inviteId:s.id}),i.code(201).send({data:s})}),e.post("/api/node-join/complete",{config:vm},async(e,i)=>{const r=t.completeNodeJoin(e.body);return s.syncNow(),n.publish("node.joined",{nodeId:r.id}),i.code(201).send({data:t.requirePublicNode(r.id)})}),e.get("/api/nodes/:id/runtimes",async e=>({data:await t.listNodeRuntimes(mg.parse(e.params).id)})),e.post("/api/nodes/:id/runtimes",async(e,i)=>{const s=mg.parse(e.params),r=await t.createNodeRuntime(s.id,e.body);return n.publish("node.runtime.created",{nodeId:s.id,runtimeId:r.id}),i.code(201).send({data:r})}),e.patch("/api/nodes/:id/runtimes/:runtimeId",async e=>{const i=yg.parse(e.params),s=await t.updateNodeRuntime(i.id,i.runtimeId,e.body);return n.publish("node.runtime.updated",{nodeId:i.id,runtimeId:s.id}),{data:s}}),e.delete("/api/nodes/:id/runtimes/:runtimeId",async e=>{const i=yg.parse(e.params),s=await t.deleteNodeRuntime(i.id,i.runtimeId);return n.publish("node.runtime.deleted",{nodeId:i.id,runtimeId:i.runtimeId}),{data:s}}),e.post("/api/nodes/:id/runtimes/:runtimeId/check",async e=>{const i=yg.parse(e.params),s=await t.checkNodeRuntime(i.id,i.runtimeId);return n.publish("node.runtime.checked",{nodeId:i.id,runtimeId:s.id}),{data:s}}),e.get("/api/nodes/:id/docker/images",async e=>({data:await t.listNodeDockerImages(mg.parse(e.params).id)})),e.get("/api/nodes/:id/image-options",async e=>({data:await t.listNodeImageAvailability(mg.parse(e.params).id)})),e.get("/api/nodes/:id/local-folders",async(e,n)=>zg(e,n,async n=>({data:await t.listNodeLocalFolders(mg.parse(e.params).id,n)}))),e.get("/api/nodes/:id/folders/tree",async e=>{const n=mg.parse(e.params),i=kg.parse(e.query);return{data:await t.listNodeFolderTree(n.id,{path:i.path,depth:i.depth})}}),e.post("/api/nodes/:id/local-folders",async(e,i)=>{const s=mg.parse(e.params),r=await t.createNodeLocalFolder(s.id,e.body);return n.publish("node.local-folder.created",{nodeId:s.id,folderId:r.id}),i.code(201).send({data:r})}),e.delete("/api/nodes/:id/local-folders/:folderId",async e=>{const i=fg.parse(e.params),s=await t.deleteNodeLocalFolder(i.id,i.folderId);return n.publish("node.local-folder.deleted",{nodeId:i.id,folderId:i.folderId}),{data:s}}),e.get("/api/nodes/:id",async e=>({data:t.requirePublicNode(mg.parse(e.params).id)})),e.patch("/api/nodes/:id",async e=>{const r=t.updateNode(mg.parse(e.params).id,e.body);return r.connectionEnabled||i.disconnect(r.id),s.syncNow(),n.publish("node.updated",{nodeId:r.id}),{data:t.requirePublicNode(r.id)}}),e.delete("/api/nodes/:id",async e=>{const i=mg.parse(e.params).id,r=Dg.parse(e.query),o=await t.deleteNodeWithProxyLifecycle(i,"true"===r.force);return s.syncNow(),n.publish("node.deleted",{nodeId:i,deleted:o.deleted,revoke:o.revoke}),{data:o}}),e.get("/api/node-runtimes",async(e,n)=>zg(e,n,async e=>{const n=await t.listNodeRuntimesWithDiagnostics(e);return{data:n.items,meta:{nodeErrors:n.nodeErrors}}})),function(e){const{app:t,service:n,nodeAgentTunnel:i,errorPayload:s}=e,r=new Cm(i),o=e=>{if(!1===e.connectionEnabled){const e=new Error("Node agent connection is disabled locally.");throw Object.assign(e,{statusCode:409,code:"NODE_AGENT_CONNECTION_DISABLED"}),e}};t.get(id,{websocket:!0,config:Am},(e,t)=>{try{const i=jm.parse(t.query),s=n.requireNode(i.nodeId);Lm(s,t),o(s),r.attachMain(s.id,e)}catch(t){const n=s(t);e.send(JSON.stringify({type:"control-plane.error",code:n.code,message:n.message})),e.close(1008,n.message)}}),t.get(`${id}/streams/:streamId`,{websocket:!0,config:Am},(e,t)=>{try{const i=jm.parse(t.query),s=n.requireNode(i.nodeId);Lm(s,t),o(s);const a=t.params.streamId;r.attachAuxiliary(s.id,a,e)}catch(t){const n=s(t);e.close(1008,n.message)}}),t.get(`${id}/channels/:channelId`,{websocket:!0,config:Am},(e,t)=>{try{const i=jm.parse(t.query),s=n.requireNode(i.nodeId);Lm(s,t),o(s);const a=t.params.channelId;r.attachAuxiliary(s.id,a,e)}catch(t){const n=s(t);e.close(1008,n.message)}}),t.get(`${id}/http-streams/:streamId`,{websocket:!0,config:Am},(e,t)=>{try{const i=jm.parse(t.query),s=n.requireNode(i.nodeId);Lm(s,t),o(s);const a=t.params.streamId;r.attachAuxiliary(s.id,a,e)}catch(t){const n=s(t);e.close(1008,n.message)}})}({app:e,service:t,nodeAgentTunnel:i,errorPayload:r})}({app:t,service:n,events:i,nodeAgentTunnel:l,nodeEventSubscriber:p,errorPayload:u}),function({app:e,service:t,events:n}){e.get("/api/controlled-instances",async()=>({data:await t.listControlledInstances()})),e.post("/api/controlled-instances",async(e,i)=>{const s=await t.createControlledInstance(e.body);return n.publish("instance.created",{instanceId:s.id}),i.code(201).send({data:s})}),e.get("/api/controlled-instances/:id",async e=>({data:await t.requireControlledInstance(mg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/metrics",async e=>({data:await t.instanceResourceMetrics(mg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/apps/management",async e=>({data:await t.instanceAppManagement(mg.parse(e.params).id)})),e.post("/api/controlled-instances/:id/apps/:appId/install",async e=>{const n=Og.parse(e.params),i=gs.parse(e.body||{});return{data:await t.requestInstanceAppOperation(n.id,n.appId,"install",i)}}),e.post("/api/controlled-instances/:id/apps/:appId/uninstall",async e=>{const n=Og.parse(e.params),i=gs.parse(e.body||{});return{data:await t.requestInstanceAppOperation(n.id,n.appId,"uninstall",i)}}),e.get("/api/controlled-instances/:id/apps/jobs/:jobId",async e=>{const n=_g.parse(e.params);return{data:await t.instanceAppManagementJob(n.id,n.jobId)}}),e.patch("/api/controlled-instances/:id",async e=>{const i=await t.updateControlledInstance(mg.parse(e.params).id,e.body);return n.publish("instance.updated",{instanceId:i.id}),{data:i}}),e.delete("/api/controlled-instances/:id",async e=>{const i=mg.parse(e.params).id,s=await t.deleteControlledInstance(i,Hi.parse(e.body));return s.completed&&n.publish("instance.deleted",{instanceId:i,result:s}),{data:s}}),e.post("/api/controlled-instances/:id/start",async e=>{const i=await t.startControlledInstance(mg.parse(e.params).id);return n.publish("instance.started",{instanceId:i.id}),{data:i}}),e.post("/api/controlled-instances/:id/stop",async e=>{const i=await t.stopControlledInstance(mg.parse(e.params).id);return n.publish("instance.stopped",{instanceId:i.id}),{data:i}}),e.post("/api/controlled-instances/:id/restart",async e=>{const i=await t.restartControlledInstance(mg.parse(e.params).id);return n.publish("instance.restarted",{instanceId:i.id}),{data:i}}),e.post("/api/controlled-instances/:id/image-provisioning/retry",async e=>{const i=await t.retryControlledInstanceImageProvisioning(mg.parse(e.params).id);return n.publish("instance.image-provisioning-retried",{instanceId:i.id}),{data:i}}),e.get("/api/controlled-instances/:id/config-sync",async e=>({data:await t.instanceConfigSyncState(mg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/config-sync/folders",async e=>({data:await t.listInstanceConfigSyncFolders(mg.parse(e.params).id,Ng.parse(e.query))})),e.post("/api/controlled-instances/:id/config-sync",async e=>{const i=mg.parse(e.params).id,s=await t.syncInstanceConfigs(i,e.body);return n.publish("instance.config-synced",{instanceId:i}),{data:s}}),e.get("/api/instance-board",async(e,n)=>zg(e,n,async n=>{const i=Rg.parse(e.query),s=await t.boardWithDiagnostics(n);return{data:(i.instanceId?s.items.filter(e=>e.id===i.instanceId):s.items).map(e=>"directory"===i.projection?function(e){const t=e.runtimeVersion?.error,n=e.imageProvisioning?.error,i=e.workspace.error,s=t?{code:t.code,message:"Instance runtime convergence failed. Use the desktop Control Plane for diagnostics."}:n?{code:"IMAGE_PROVISIONING_FAILED",message:"Instance image provisioning failed. Use the desktop Control Plane for diagnostics."}:i?{code:"WORKSPACE_FAILED",message:"Instance workspace preparation failed. Use the desktop Control Plane for diagnostics."}:void 0,r=e.node?.capabilities.agent,o=r&&"object"==typeof r&&!Array.isArray(r)?r:void 0,a="string"==typeof o?.protocolVersion?o.protocolVersion:void 0,d=!a||a===ui,c=[e.protocolCompatible?void 0:`Instance protocol ${e.protocolVersion||"unknown"} differs from this Control Plane.`,d?void 0:`Node protocol ${a} differs from this Control Plane.`].filter(e=>Boolean(e)),l="running"===e.status||"online"===e.connectionStatus||"reachable"===e.access.status,p=!["failed","stopped","stopping","unhealthy"].includes(e.status)&&"online"!==e.connectionStatus&&["provisioning","starting","registering","registered"].includes(e.status),u=[l||["provisioning","starting","registering","registered","stopping"].includes(e.status)?void 0:"start",["failed","stopped","stopping","unhealthy"].includes(e.status)||!l&&!p?void 0:"stop",l?"restart":void 0,"failed"===e.status&&"failed"===e.imageProvisioning?.phase?"retry-image":void 0].filter(e=>Boolean(e));return Ld.parse({id:e.id,name:e.name,nodeId:e.nodeId,status:e.status,health:e.health,connectionStatus:e.connectionStatus,ready:e.ready,capabilities:{aiSessionTimeline:e.capabilities.features.aiSessionTimeline},config:{defaultCodexPermissionMode:e.config.defaultCodexPermissionMode},lastHeartbeatAt:e.lastHeartbeatAt,heartbeatAgeMs:e.heartbeatAgeMs,observedAt:e.updatedAt,runtime:{id:e.runtimeId,name:e.runtime?.name,type:e.runtime?.type},workspace:{status:e.workspace.status,path:e.workspace.path},protocol:{version:e.protocolVersion,compatible:e.protocolCompatible&&d,warning:c.length?c.join(" "):void 0},aiSessions:e.aiSessions,availableActions:u,availableApps:(e.appInventory?.items||[]).filter(e=>"available"===e.availability).map(e=>({id:e.id,name:e.name,kind:e.kind,supportsCwdSelection:e.capabilities.supportsCwdSelection})),availableAgents:(e.appInventory?.items||[]).filter(e=>"available"===e.availability&&("codex"===e.id||"claude"===e.id)).map(e=>({id:e.id,name:e.name,kind:e.kind,supportsCwdSelection:e.capabilities.supportsCwdSelection})),error:s})}(e):e),meta:{nodeErrors:s.nodeErrors}}}))}({app:t,service:n,events:i}),function(e,t,n){e.get("/api/nodes/:id/environment-templates",async e=>({data:await t.listEnvironmentTemplates(Pg.parse(e.params).id)})),e.get("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const n=jg.parse(e.params);return{data:await t.getEnvironmentTemplate(n.nodeId,n.templateId)}}),e.post("/api/controlled-instances/:id/environment-templates",async(e,i)=>{const s=Pg.parse(e.params).id,r=await t.createEnvironmentTemplate(s,e.body);return n.publish("environment-template.updated",{templateId:r.id,nodeId:r.nodeId,status:r.status}),i.code(201).send({data:r})}),e.delete("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const i=jg.parse(e.params),s=await t.deleteEnvironmentTemplate(i.nodeId,i.templateId);return n.publish("environment-template.deleted",s),{data:s}})}(t,n,i),function({app:e,service:t,events:n,appSessionAggregator:i,aiSessionAggregator:s,aiSessionUnread:r,aiSessionAttachments:o}){e.get("/api/app-sessions",async e=>{const t=a.z.object({refresh:a.z.string().optional(),instanceId:a.z.string().trim().min(1).optional(),streamId:a.z.string().trim().min(1).optional(),sinceRevision:a.z.string().optional()}).parse(e.query||{});if(void 0!==t.sinceRevision){const e=Number(t.sinceRevision);if(!Number.isInteger(e)||e<0){const e=new Error("sinceRevision must be a non-negative integer.");throw Object.assign(e,{statusCode:400,code:"APP_SESSION_DELTA_INVALID"}),e}if(!t.streamId){const e=new Error("streamId is required with sinceRevision.");throw Object.assign(e,{statusCode:400,code:"APP_SESSION_DELTA_INVALID"}),e}return{data:await i.delta({instanceId:t.instanceId,streamId:t.streamId,sinceRevision:e})}}const n=await i.list({refresh:"true"===t.refresh||"1"===t.refresh});return{data:t.instanceId?{...n,instances:n.instances.filter(e=>e.instanceId===t.instanceId)}:n}}),e.post("/api/controlled-instances/:id/apps/sessions",async e=>{const i=mg.parse(e.params),s=qg.parse(e.body),r=await t.launchAppSession(i.id,s.appId,{...s.options,...s.cwdFolderId?{cwdFolderId:s.cwdFolderId}:{}});return n.publish("instance.app-session.launched",{instanceId:i.id,sessionId:"string"==typeof r.id?r.id:void 0,appId:s.appId}),{data:r}}),e.post("/api/controlled-instances/:id/apps/sessions/:sessionId/stop",async e=>{const i=Ig.parse(e.params),s=await t.stopAppSession(i.id,i.sessionId);return n.publish("instance.app-session.stopped",{instanceId:i.id,sessionId:i.sessionId}),{data:s}}),e.patch("/api/controlled-instances/:id/apps/sessions/:sessionId",async e=>{const i=Ig.parse(e.params),s=$g.parse(e.body),r=await t.renameAppSession(i.id,i.sessionId,s.title);return n.publish("instance.app-session.renamed",{instanceId:i.id,sessionId:i.sessionId,title:s.title}),{data:r}}),e.post("/api/controlled-instances/:id/apps/sessions/:sessionId/access",async e=>{const n=Ig.parse(e.params);Ug.parse(e.body||{});const i=await t.createAppSessionAccessToken({instanceId:n.id,sessionId:n.sessionId});return{data:{mode:i.mode,url:`/apps/access/${i.mode}?token=${encodeURIComponent(i.token)}`,token:i.token,expiresAt:i.expiresAt}}}),e.delete("/api/controlled-instances/:id/apps/sessions/:sessionId/access",async e=>{const n=Ig.parse(e.params),i=Bg.parse(e.body||{});return t.revokeAppSessionAccessToken(i.token,{instanceId:n.id,sessionId:n.sessionId}),{data:{revoked:!0}}}),e.get("/api/controlled-instances/:id/app-sessions",async e=>{const t=mg.parse(e.params),n=(await i.list()).instances.find(e=>e.instanceId===t.id);return{data:n?.appSessions||{runningCount:0,problemCount:0,sessions:[],updatedAt:(new Date).toISOString()}}}),e.get("/api/controlled-instances/:id/ai-sessions/history",async e=>{const n=mg.parse(e.params);return{data:await t.listAiSessionHistory(n.id)}}),e.get("/api/controlled-instances/:id/ai-sessions/history/:sessionId",async e=>{const n=Ig.parse(e.params);return{data:await t.getAiSessionHistoryDetail(n.id,n.sessionId)}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/timeline",async e=>{const n=Ig.parse(e.params);return{data:await t.getAiSessionTimeline(n.id,n.sessionId)}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/turns/:turnId/timeline",async e=>{const n=bg.parse(e.params);return{data:await t.getAiSessionTurnTimeline(n.id,n.sessionId,n.turnId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/resume",async e=>{const i=Ig.parse(e.params);Ug.parse(e.body||{});const s=await t.resumeAiSession(i.id,i.sessionId);return n.publish("instance.ai-session.resumed",{instanceId:i.id,sessionId:s.aiSessionId,providerSessionId:s.providerSessionId,appSessionId:s.appSessionId,disposition:s.disposition}),{data:s}}),e.get("/api/controlled-instances/:id/ai-sessions/workspace",async e=>{const n=mg.parse(e.params),i=Lg.parse(e.query||{});return{data:await t.inspectAiSessionWorkspace(n.id,i.cwdFolderId)}}),e.post("/api/controlled-instances/:id/ai-sessions",async e=>{const i=mg.parse(e.params),s=Ee.parse(e.body||{}),r=o.resolveRefs(s.attachments,i.id,s.clientRequestId),a=await t.createAiSession(i.id,{...s,attachments:r});return n.publish("instance.ai-session.created",{instanceId:i.id,sessionId:a.aiSessionId,providerSessionId:a.providerSessionId,clientRequestId:s.clientRequestId}),{data:a}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/open-app",async e=>{const i=Ig.parse(e.params),s=_e.parse(e.body||{}),r=await t.openAiSessionApp(i.id,i.sessionId,s.clientRequestId);return n.publish("instance.ai-session.app-opened",{instanceId:i.id,sessionId:i.sessionId,appSessionId:r.appSessionId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/fork",async e=>{const i=Ig.parse(e.params),s=Ne.parse(e.body||{}),r=await t.forkAiSession(i.id,i.sessionId,s);return n.publish("instance.ai-session.forked",{instanceId:i.id,sourceSessionId:i.sessionId,sessionId:r.aiSessionId,providerSessionId:r.providerSessionId,clientRequestId:s.clientRequestId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/close",async e=>{const i=Ig.parse(e.params),s=Pe.parse(e.body||{}),r=await t.closeAiSession(i.id,i.sessionId,s.clientRequestId);return n.publish("instance.ai-session.closed",{instanceId:i.id,sessionId:i.sessionId,providerSessionId:r.providerSessionId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/messages",async e=>{const i=Ig.parse(e.params),s=Ae.parse(e.body||{}),r=o.resolveRefs(s.attachments,i.id,i.sessionId),a=await t.sendAiSessionMessage(i.id,i.sessionId,s.message,s.mode,r,s.references,s.permissionMode);return n.publish("instance.ai-session.message-sent",{instanceId:i.id,sessionId:i.sessionId}),{data:a}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/mentions",async e=>{const n=Ig.parse(e.params);return{data:await t.aiSessionMentionCatalog(n.id,n.sessionId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/mentions/files",async e=>{const n=Ig.parse(e.params),i=be.parse(e.body||{});return{data:await t.searchAiSessionMentionFiles(n.id,n.sessionId,i.query)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/commands",async e=>{const i=Ig.parse(e.params),s=le.parse(e.body||{}),r=await t.executeAiSessionCommand(i.id,i.sessionId,s);return n.publish("instance.ai-session.command-executed",{instanceId:i.id,sessionId:i.sessionId,command:s.command}),{data:r}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/queue",async e=>{const n=Ig.parse(e.params);return{data:await t.aiSessionQueue(n.id,n.sessionId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId/steer",async e=>{const i=vg.parse(e.params),s=await t.steerAiSessionQueuedMessage(i.id,i.sessionId,i.queueId);return n.publish("instance.ai-session.message-sent",{instanceId:i.id,sessionId:i.sessionId}),{data:s}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId/retry",async e=>{const n=vg.parse(e.params);return{data:await t.retryAiSessionQueuedMessage(n.id,n.sessionId,n.queueId)}}),e.delete("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId",async e=>{const n=vg.parse(e.params);return{data:await t.removeAiSessionQueuedMessage(n.id,n.sessionId,n.queueId)}}),e.patch("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId",async e=>{const n=vg.parse(e.params),i=Le.parse(e.body||{});return{data:await t.editAiSessionQueuedMessage(n.id,n.sessionId,n.queueId,i)}}),e.patch("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/reorder",async e=>{const n=Ig.parse(e.params),i=Me.parse(e.body||{});return{data:await t.reorderAiSessionQueuedMessages(n.id,n.sessionId,i)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/interrupt",async e=>{const i=Ig.parse(e.params),s=await t.interruptAiSession(i.id,i.sessionId);return n.publish("instance.ai-session.interrupted",{instanceId:i.id,sessionId:i.sessionId}),{data:s}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/approval",async e=>{const i=Ig.parse(e.params),s=De.parse(e.body||{}),r=await t.resolveAiSessionApproval(i.id,i.sessionId,s.decision);return n.publish("instance.ai-session.approval-resolved",{instanceId:i.id,sessionId:i.sessionId,decision:s.decision}),{data:r}}),e.get("/api/ai-sessions",async(e,t)=>{const n=e.query;if(void 0!==n.sinceRevision){const e=Number(n.sinceRevision);if(!Number.isInteger(e)||e<0)return t.code(400).send({error:"invalid_since_revision"});try{return n.streamId?{data:await s.delta({instanceId:n.instanceId,streamId:n.streamId,sinceRevision:e})}:t.code(400).send({error:"stream_id_required"})}catch(e){if("AI_SESSION_DELTA_INSTANCE_ID_REQUIRED"===e.message)return t.code(400).send({error:"instance_id_required"});throw e}}const i=await s.list({refresh:"true"===n.refresh||"1"===n.refresh}),o=n.instanceId?{...i,instances:i.instances.filter(e=>e.instanceId===n.instanceId)}:i;for(const e of o.instances)r.reconcile(e.instanceId,e.aiSessions);return{data:{...o,instances:o.instances.map(e=>({...e,aiSessions:r.decorate(e.instanceId,e.aiSessions)}))}}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/read",async(e,t)=>{const i=Ig.parse(e.params),o=a.z.object({sessionUpdatedAt:a.z.string().datetime()}).strict().parse(e.body||{}),d=(await s.list()).instances.find(e=>e.instanceId===i.id),c=d?.aiSessions.sessions.find(e=>e.id===i.sessionId);if(!d||!c)return t.code(404).send({error:{code:"AI_SESSION_NOT_FOUND",message:"AI session was not found."}});r.reconcile(i.id,d.aiSessions);const l=r.markRead(i.id,i.sessionId,o.sessionUpdatedAt);return l?(n.publish(j,l,{topic:"ai.sessions",scope:{instanceId:i.id,sessionId:i.sessionId}}),{data:l}):t.code(404).send({error:{code:"AI_SESSION_NOT_FOUND",message:"AI session was not found."}})})}({app:t,service:n,events:i,appSessionAggregator:s,aiSessionAggregator:r,aiSessionUnread:o,aiSessionAttachments:c}),function({app:e,service:t,events:n}){e.get("/api/triggers",async()=>({data:await t.listTriggers()})),e.post("/api/triggers",async(e,i)=>{const s=t.createTrigger(e.body);return n.publish("trigger.created",{configHash:s.configHash}),i.code(201).send({data:s})}),e.put("/api/triggers/:configHash",async e=>{const i=wg.parse(e.params),s=await t.updateTrigger(i.configHash,e.body);return n.publish("trigger.updated",{previousConfigHash:i.configHash,configHash:s.trigger.configHash}),{data:s}}),e.delete("/api/triggers/:configHash",async e=>{const i=wg.parse(e.params),s=await t.deleteTrigger(i.configHash);return n.publish("trigger.deleted",{configHash:i.configHash}),{data:s}}),e.post("/api/triggers/:configHash/apply",async e=>{const i=wg.parse(e.params),s=await t.applyTrigger(i.configHash,e.body||{});return n.publish("trigger.applied",{configHash:i.configHash}),{data:s}}),e.get("/api/controlled-instances/:id/triggers",async e=>{const n=mg.parse(e.params);return{data:await t.listInstanceTriggers(n.id)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers",async e=>{const i=Ig.parse(e.params),s=await t.bindAiSessionTrigger(i.id,i.sessionId,e.body||{});return n.publish("trigger.deployment.bound",{instanceId:i.id,sessionId:i.sessionId},{topic:"triggers",scope:{instanceId:i.id}}),{data:s}}),e.delete("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers/:configHash",async e=>{const i=Ag.parse(e.params),s=await t.unbindAiSessionTrigger(i.id,i.sessionId,i.configHash);return n.publish("trigger.deployment.unbound",{instanceId:i.id,sessionId:i.sessionId,configHash:i.configHash},{topic:"triggers",scope:{instanceId:i.id}}),{data:s}}),e.post("/api/controlled-instances/:id/triggers/:configHash/run",async e=>{const i=Sg.parse(e.params),s=await t.runInstanceTrigger(i.id,i.configHash,e.body||{});return n.publish("trigger.run.requested",{instanceId:i.id,configHash:i.configHash},{topic:"triggers",scope:{instanceId:i.id}}),{data:s}})}({app:t,service:n,events:i}),function({app:e,service:t,chatGateway:n}){e.get("/api/chat/sessions",async()=>({data:t.listChatSessions()})),e.get("/api/chat/sessions/:id",async e=>({data:t.requireChatSession(mg.parse(e.params).id)})),e.get("/api/chat-gateway/status",async()=>({data:n.status()})),e.post("/api/chat-gateway/poll-ai-sessions",async()=>({data:await n.pollAiSessionsNow()})),e.get("/api/chat-gateway/bridges",async()=>({data:t.listChatBridges()})),e.post("/api/chat-gateway/bridges",async e=>({data:t.createChatBridge(e.body)})),e.patch("/api/chat-gateway/bridges/:id",async i=>{const s=mg.parse(i.params).id,r=t.requireChatBridge(s),o=dc.parse(i.body),a=t.updateChatBridge(s,i.body),d="boolean"==typeof o.enabled?o.enabled:void 0;return e.log.info({component:"control-plane-chat-gateway",action:"bridge-patch",bridgeId:s,hasEnabled:void 0!==d,requestedEnabled:d,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(s).enabled},"chat gateway bridge state changed"),void 0!==d&&d!==r.enabled&&(d?n.startBridge(s):n.stopBridge(s)),{data:a}}),e.post("/api/chat-gateway/bridges/:id/start",async i=>{const s=mg.parse(i.params).id,r=t.requireChatBridge(s);return t.updateChatBridge(s,{enabled:!0}),e.log.info({component:"control-plane-chat-gateway",action:"bridge-start-request",bridgeId:s,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(s).enabled},"chat gateway bridge state changed"),{data:n.startBridge(s)}}),e.post("/api/chat-gateway/bridges/:id/stop",async i=>{const s=mg.parse(i.params).id,r=t.requireChatBridge(s);return t.updateChatBridge(s,{enabled:!1}),e.log.info({component:"control-plane-chat-gateway",action:"bridge-stop-request",bridgeId:s,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(s).enabled},"chat gateway bridge state changed"),{data:n.stopBridge(s)}}),e.delete("/api/chat-gateway/bridges/:id",async e=>{const i=mg.parse(e.params).id;return n.stopBridge(i),{data:{deleted:t.deleteChatBridge(i)}}}),e.post("/api/chat-gateway/messages",{bodyLimit:67108864},async e=>({data:await t.handleChatGatewayMessage(Gr.parse(e.body))})),e.post("/api/chat-gateway/actions",async e=>({data:await t.handleChatGatewayAction(xg(e.body))})),e.get("/api/pending-routes",async()=>({data:await t.listPendingRoutes()}))}({app:t,service:n,chatGateway:d})}const Hg=new Set(["connection","content-length","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Wg=new Set(["authorization"]),Gg=new Set(["content-encoding"]);function Vg(e){return Object.fromEntries(Object.entries(e).flatMap(([e,t])=>{const n=e.toLowerCase();if(Hg.has(n)||Wg.has(n)||void 0===t)return[];const i=Array.isArray(t)?t.join(", "):String(t);if("cookie"!==n)return[[e,i]];const s=function(e){return e.split(";").map(e=>e.trim()).filter(e=>e&&e.slice(0,e.indexOf("=")).trim()!==vo).join("; ")}(i);return s?[[e,s]]:[]}))}function Kg(e){return Object.fromEntries(Object.entries(Vg(e)).filter(([e])=>{const t=e.toLowerCase();return"host"!==t&&"cookie"!==t&&"authorization"!==t&&(!t.startsWith("sec-websocket-")||"sec-websocket-origin"===t)}))}function Jg(e){const t=e["sec-websocket-protocol"],n=(Array.isArray(t)?t.join(","):"string"==typeof t?t:"").split(",").map(e=>e.trim()).filter(Boolean);return n.length?n:void 0}function Yg(e,t,n,i,s={}){const r=new AbortController;return t.raw.once("close",()=>r.abort()),e.proxyInstanceHttp(n,i,{...s,signal:r.signal})}function Qg(e,t,n){for(const[n,i]of Object.entries(t.headers)){const t=n.toLowerCase();Hg.has(t)||Gg.has(t)||e.header(n,i)}if(!t.body)return e.code(t.status).send();const i=m.Readable.fromWeb(t.body);return e.raw.once("close",()=>i.destroy()),e.code(t.status).send(n?i.pipe(n):i)}function Xg(e){return`/instances/${encodeURIComponent(e)}`}function Zg(e,t,n,i){const s=function(e,t){const n=e.split("?",1)[0]||"/";return t.toLowerCase().includes("text/html")&&!n.startsWith("/api/")}(i,Object.entries(t.headers).find(([e])=>"content-type"===e.toLowerCase())?.[1]||"")?function(e){const t=[];let n=0,i=!1;const s=(s,r=!1)=>{if(i)return;const o=Buffer.concat(t,n).toString("utf8");!/<head(\s[^>]*)?>/i.exec(o)&&!r&&n<65536||(i=!0,s.push(function(e,t){if(e.includes("__TASK_HANDOFF_PUBLIC_BASE__"))return e;const n=`<script>window.__TASK_HANDOFF_PUBLIC_BASE__=${JSON.stringify(t)};<\/script>`;return/<head(\s[^>]*)?>/i.test(e)?e.replace(/<head(\s[^>]*)?>/i,e=>`${e}\n${n}`):`${n}\n${e}`}(o,e)),t.length=0,n=0)};return new m.Transform({transform(e,r,o){i?this.push(e):(t.push(Buffer.from(e)),n+=e.length,s(this)),o()},flush(e){s(this,!0),e()}})}(Xg(n)):void 0;return Qg(e,t,s)}function eh(e){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):e instanceof URLSearchParams?e.toString():"string"==typeof e?e:null==e?void 0:JSON.stringify(e)}function th(e,t){if("string"!=typeof t||!e.hasContentTypeParser(t))try{e.addContentTypeParser(t,{parseAs:"buffer"},(e,t,n)=>n(null,t))}catch(e){if(e instanceof Error&&/Content type parser .* already present/i.test(e.message))return;throw e}}function nh(e){return new URL(e,"http://control-plane.local").searchParams.get("token")||""}function ih(e,t,n){const i=encodeURIComponent(e),s=encodeURIComponent(t),r=`apps/access/vnc/${i}/proxy`,o=n.vnc&&"object"==typeof n.vnc?n.vnc:{};return"kasmvnc"===("string"==typeof o.backend?o.backend:"")?`/${r}/api/apps/sessions/${s}/web/`:`/${r}/api/novnc/vnc.html?path=${encodeURIComponent(`${r}/api/apps/sessions/${s}/vnc`)}&autoconnect=1&resize=scale`}class sh{snapshots=new Map;history=new Map;advertisedStreams=new Map;recoveries=new Map;listeners=new Set;bootstrap;logger;recoverDelta;recoverSnapshot;onRecoveredEvent;recoveryCount=0;counters={streamResets:0,gaps:0,deltaRecoveries:0,snapshotRecoveries:0,recoveryFailures:0};constructor(e){this.bootstrap=e.bootstrap,this.logger=e.logger,this.recoverDelta=e.recoverDelta,this.recoverSnapshot=e.recoverSnapshot,this.onRecoveredEvent=e.onRecoveredEvent}handleEvent(e){if(e.type===R||e.type===P){const t=Bo(e.type===R?dt:ct,e.payload);return!!t.success||(this.logger?.warn?.({eventType:e.type,issues:t.error.issues,errorCode:"AI_SESSION_TRANSIENT_EVENT_INVALID"},"ai-session.aggregator.transient-event.invalid"),!1)}const t=e.type===N?rt:e.type===O?ot:e.type===_?at:void 0;if(!t)return!1;const n=Bo(t,e.payload);return n.success?e.type===N?this.applySnapshot(n.data):e.type===O?this.applyPatch(n.data):this.applyRemoved(n.data):(this.logger?.warn?.({eventType:e.type,issues:n.error.issues,errorCode:"AI_SESSION_EVENT_INVALID"},"ai-session.aggregator.event.invalid"),!1)}onSnapshot(e){return this.listeners.add(e),()=>this.listeners.delete(e)}applySnapshot(e){const t=this.advertisedStreams.get(e.meta.instanceId)?.streamId;return t&&t!==e.meta.streamId?(this.logger?.warn?.({instanceId:e.meta.instanceId,advertisedStreamId:t,streamId:e.meta.streamId,revision:e.meta.revision},"ai-session.aggregator.snapshot.obsolete-stream"),!1):this.apply({type:N,payload:e})}advertiseStream(e,t){return this.advertisedStreams.set(e,t),this.recoverStream(e,t.streamId,t.latestRevision).catch(n=>{this.counters.recoveryFailures+=1,this.logger?.warn?.({instanceId:e,streamId:t.streamId,error:n instanceof Error?n.message:String(n)},"ai-session.aggregator.recovery.failed")})}diagnostics(){return{...this.counters,recoveriesStarted:this.recoveryCount,activeRecoveries:this.recoveries.size}}removeInstance(e){this.snapshots.delete(e),this.history.delete(e),this.advertisedStreams.delete(e)}applyPatch(e){return this.apply({type:O,payload:e})}applyRemoved(e){return this.apply({type:_,payload:e})}async list(e={}){return(e.refresh||0===this.snapshots.size)&&await this.bootstrapFromInstances(),this.view()}async streamDescriptors(){return 0===this.snapshots.size&&await this.bootstrapFromInstances(),[...this.snapshots.entries()].map(([e,t])=>({topic:"ai.sessions",instanceId:e,streamId:t.streamId,latestRevision:t.revision,earliestRetainedRevision:this.history.get(e)?.[0]?.payload.meta.revision??t.revision+1}))}async delta(e){0===this.snapshots.size&&await this.bootstrapFromInstances();const t=this.resolveDeltaInstanceId(e.instanceId);this.pruneHistory(t);const n=this.snapshots.get(t)?.revision??0,i=this.snapshots.get(t)?.streamId||"unavailable",s=this.history.get(t)?.[0]?.payload.meta.revision??n+1;if(e.streamId!==i||e.sinceRevision>n)return lt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!0,events:[]});if(e.sinceRevision===n)return lt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!1,events:[]});const r=(this.history.get(t)??[]).filter(t=>t.payload.meta.revision>e.sinceRevision),o=!r.length||r[0].payload.meta.revision!==e.sinceRevision+1;return lt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:o,events:o?[]:r.map(({type:e,payload:t})=>({type:e,payload:t}))})}apply(e,t=!1){const{meta:n}=e.payload,i=this.advertisedStreams.get(n.instanceId)?.streamId;if(i&&i!==n.streamId)return this.logger?.warn?.({instanceId:n.instanceId,advertisedStreamId:i,streamId:n.streamId,revision:n.revision},"ai-session.aggregator.event.obsolete-stream"),!1;const s=this.recoveries.get(n.instanceId);if(s&&!t)return s.streamId===n.streamId&&(s.highWater=Math.max(s.highWater,n.revision)),!1;const r=this.snapshots.get(n.instanceId);e.type===N&&r&&r.streamId!==n.streamId&&(this.counters.streamResets+=1,this.logger?.info?.({instanceId:n.instanceId,previousStreamId:r.streamId,streamId:n.streamId,previousRevision:r.revision,revision:n.revision,traceId:n.traceId,resetCount:this.counters.streamResets},"ai-session.aggregator.stream-reset"));const o=function(e,t){const{meta:n}=t.payload;if(t.type===N)return e?.streamId===n.streamId&&n.revision===e.revision?{kind:"duplicate",projection:e}:e?.streamId===n.streamId&&n.revision<e.revision?{kind:"stale",projection:e}:{kind:"applied",projection:et.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:t.payload.snapshot})};if(!e||e.streamId!==n.streamId)return{kind:"snapshot-required",projection:e,streamId:n.streamId};if(n.revision===e.revision)return{kind:"duplicate",projection:e};if(n.revision<e.revision)return{kind:"stale",projection:e};if(n.revision!==e.revision+1||n.previousRevision!==e.revision)return{kind:"gap",projection:e,expectedRevision:e.revision+1,receivedRevision:n.revision};const i=new Map(e.snapshot.sessions.map(e=>[e.id,e]));if(t.type===O){for(const e of t.payload.upserted)i.set(e.id,e);for(const e of t.payload.removed)i.delete(e)}else for(const e of t.payload.sessionIds)i.delete(e);const s=[...i.values()],r=Ze.parse({runningCount:s.filter(e=>"running"===e.status).length,waitingCount:s.filter(e=>"waiting"===e.status).length,staleCount:e.snapshot.staleCount,sessions:s,updatedAt:n.generatedAt});return{kind:"applied",projection:et.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:r})}}(r,e);if("applied"!==o.kind)return this.logger?.warn?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,currentRevision:r?.revision,revision:n.revision,outcome:o.kind},`ai-session.aggregator.event.${o.kind}`),"gap"!==o.kind&&"snapshot-required"!==o.kind||("gap"===o.kind&&(this.counters.gaps+=1),this.recoverStream(n.instanceId,n.streamId,n.revision).catch(e=>{this.logger?.warn?.({instanceId:n.instanceId,streamId:n.streamId,revision:n.revision,error:e instanceof Error?e.message:String(e)},"ai-session.aggregator.recovery.failed")})),!1;const a=o.projection;this.snapshots.set(n.instanceId,a),this.rememberEvent(n.instanceId,e);const d={instanceId:n.instanceId,streamId:a.streamId,aiSessions:a.snapshot,revision:a.revision,lastEventAt:a.lastEventAt};for(const e of this.listeners)try{e(d)}catch{this.listeners.delete(e)}return this.logger?.info?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,revision:n.revision,reason:n.reason,sessionCount:a.snapshot.sessions.length},"ai-session.aggregator.event.accepted"),!0}async bootstrapFromInstances(){this.logger?.info?.({},"ai-session.aggregator.bootstrap");const e=new Map(this.snapshots),t=await this.bootstrap(),n=new Set(t.instances.map(e=>e.instanceId));for(const[t,i]of e)n.has(t)||this.snapshots.get(t)!==i||(this.snapshots.delete(t),this.history.delete(t),this.advertisedStreams.delete(t));for(const n of t.instances){const t=this.snapshots.get(n.instanceId);if(t!==e.get(n.instanceId))continue;const i=this.advertisedStreams.get(n.instanceId)?.streamId;i&&i!==n.streamId||t?.streamId===n.streamId&&t.revision>=n.revision||(t?.streamId!==n.streamId&&this.history.delete(n.instanceId),this.snapshots.set(n.instanceId,{streamId:n.streamId,snapshot:n.aiSessions,revision:n.revision,lastEventAt:n.lastEventAt}))}}recoverStream(e,t,n){const i=this.recoveries.get(e);if(i)return i.streamId===t?i.highWater=Math.max(i.highWater,n):(i.streamId=t,i.highWater=n),i.promise;if(!this.recoverDelta||!this.recoverSnapshot)return Promise.resolve();const s={promise:Promise.resolve(),streamId:t,highWater:n},r=++this.recoveryCount;return this.logger?.info?.({instanceId:e,highWater:n,recoveryNumber:r},"ai-session.aggregator.recovery.started"),s.promise=(async()=>{for(;;){const t=this.advertisedStreams.get(e);if(!t)return;s.streamId!==t.streamId&&(s.streamId=t.streamId,s.highWater=t.latestRevision);const n=this.snapshots.get(e);if(n&&n.streamId===t.streamId){if(n.revision<Math.max(t.latestRevision,s.highWater)){const t=await this.recoverDelta(e,n.streamId,n.revision);if(this.advertisedStreams.get(e)?.streamId!==t.streamId||s.streamId!==t.streamId)continue;if(t.syncRequired){const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:N,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`ais_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot-fallback"},"ai-session.aggregator.recovery.snapshot")}else{for(const e of t.events)this.apply(e,!0)&&this.onRecoveredEvent?.(e);this.counters.deltaRecoveries+=1,s.highWater=Math.max(s.highWater,t.latestRevision),this.logger?.info?.({instanceId:e,streamId:t.streamId,sinceRevision:t.sinceRevision,latestRevision:t.latestRevision,eventCount:t.events.length,recoveryNumber:r,outcome:"delta"},"ai-session.aggregator.recovery.delta")}}}else{const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:N,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`ais_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot"},"ai-session.aggregator.recovery.snapshot")}const i=this.snapshots.get(e),o=this.advertisedStreams.get(e);if(i&&o&&i.streamId===o.streamId&&i.revision>=Math.max(o.latestRevision,s.highWater))return void this.logger?.info?.({instanceId:e,streamId:i.streamId,revision:i.revision,recoveryNumber:r,outcome:"success"},"ai-session.aggregator.recovery.completed")}})().finally(()=>this.recoveries.delete(e)),this.recoveries.set(e,s),s.promise}rememberEvent(e,t){const n=this.history.get(e)??[],i=n.length&&n[0].payload.meta.streamId!==t.payload.meta.streamId?[]:n;i.push({...t,createdAtMs:Date.now()}),this.history.set(e,i),this.pruneHistory(e)}pruneHistory(e){const t=this.history.get(e);if(!t?.length)return;const n=t.filter(e=>e.createdAtMs>=Date.now()-36e5);n.length?this.history.set(e,n):this.history.delete(e)}resolveDeltaInstanceId(e){if(e)return e;const t=[...this.snapshots.keys()];if(1===t.length)return t[0];throw new Error("AI_SESSION_DELTA_INSTANCE_ID_REQUIRED")}view(){return{updatedAt:(new Date).toISOString(),instances:[...this.snapshots.entries()].map(([e,t])=>({instanceId:e,streamId:t.streamId,aiSessions:t.snapshot,revision:t.revision,lastEventAt:t.lastEventAt}))}}}const rh=a.z.object({id:a.z.string().trim().min(1),instanceId:a.z.string().trim().min(1).max(160),sessionId:a.z.string().trim().min(1).max(120),unread:a.z.boolean(),lastStatus:a.z.enum(["running","waiting","idle","failed"]),sessionUpdatedAt:a.z.string().datetime(),createdAt:a.z.string().datetime(),updatedAt:a.z.string().datetime()}).strict();class oh{records;bySession=new Map;listener;constructor(e,t={}){this.records=new fo(e.aiSessionUnreadDir,{schema:rh}),this.listener=t.onChanged}init(){this.records.init(),this.bySession.clear();for(const e of this.records.list())this.bySession.set(dh(e.instanceId,e.sessionId),e)}reconcile(e,t){const n=new Set;for(const i of t.sessions)n.add(i.id),this.reconcileSession(e,i);for(const t of[...this.bySession.values()])t.instanceId!==e||n.has(t.sessionId)||this.deleteRecord(t)}decorate(e,t){return{...t,sessions:t.sessions.map(t=>({...t,unread:this.bySession.get(dh(e,t.id))?.unread||!1}))}}markRead(e,t,n){const i=this.bySession.get(dh(e,t));return i&&i.sessionUpdatedAt===n&&i.unread?ah(this.store({...i,unread:!1,updatedAt:(new Date).toISOString()},!1)):i?ah(i):void 0}removeInstance(e){for(const t of[...this.bySession.values()])t.instanceId===e&&this.deleteRecord(t)}reconcileSession(e,t){const n=dh(e,t.id),i=this.bySession.get(n),s=(new Date).toISOString();if(!i)return void this.store({id:ch(e,t.id),instanceId:e,sessionId:t.id,unread:!1,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,createdAt:s,updatedAt:s},!1);const r=function(e,t,n){return"running"!==n&&"waiting"!==n&&("running"===t||"waiting"===t||e)}(i.unread,i.lastStatus,t.status),o=r!==i.unread;(o||i.lastStatus!==t.status||i.sessionUpdatedAt!==t.updatedAt)&&this.store({...i,unread:r,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,updatedAt:s},o)}store(e,t){const n=this.records.put(e);return this.bySession.set(dh(n.instanceId,n.sessionId),n),t&&this.listener?.(ah(n)),n}deleteRecord(e){this.records.delete(e.id),this.bySession.delete(dh(e.instanceId,e.sessionId))}}function ah(e){return q.parse({instanceId:e.instanceId,sessionId:e.sessionId,unread:e.unread,sessionUpdatedAt:e.sessionUpdatedAt,updatedAt:e.updatedAt})}function dh(e,t){return`${e}\0${t}`}function ch(e,t){return`ais_unread_${i.createHash("sha256").update(dh(e,t)).digest("hex").slice(0,32)}`}class lh{snapshots=new Map;history=new Map;advertisedStreams=new Map;recoveries=new Map;bootstrap;logger;recoverDelta;recoverSnapshot;onRecoveredEvent;recoveryCount=0;counters={streamResets:0,gaps:0,deltaRecoveries:0,snapshotRecoveries:0,recoveryFailures:0};constructor(e){this.bootstrap=e.bootstrap,this.logger=e.logger,this.recoverDelta=e.recoverDelta,this.recoverSnapshot=e.recoverSnapshot,this.onRecoveredEvent=e.onRecoveredEvent}handleEvent(e){const t=e.type===ht?Et:e.type===yt?Ct:e.type===ft?xt:void 0;if(!t)return!1;const n=Bo(t,e.payload);return n.success?e.type===ht?this.applySnapshot(n.data):e.type===yt?this.applyPatch(n.data):this.applyRemoved(n.data):(this.logger?.warn?.({eventType:e.type,issues:n.error.issues,errorCode:"APP_SESSION_EVENT_INVALID"},"app-session.aggregator.event.invalid"),!1)}applySnapshot(e){const t=this.advertisedStreams.get(e.meta.instanceId)?.streamId;return t&&t!==e.meta.streamId?(this.logger?.warn?.({instanceId:e.meta.instanceId,advertisedStreamId:t,streamId:e.meta.streamId,revision:e.meta.revision},"app-session.aggregator.snapshot.obsolete-stream"),!1):this.apply({type:ht,payload:e})}advertiseStream(e,t){return this.advertisedStreams.set(e,t),this.recoverStream(e,t.streamId,t.latestRevision).catch(n=>{this.counters.recoveryFailures+=1,this.logger?.warn?.({instanceId:e,streamId:t.streamId,error:n instanceof Error?n.message:String(n)},"app-session.aggregator.recovery.failed")})}diagnostics(){return{...this.counters,recoveriesStarted:this.recoveryCount,activeRecoveries:this.recoveries.size}}removeInstance(e){this.snapshots.delete(e),this.history.delete(e),this.advertisedStreams.delete(e)}applyPatch(e){return this.apply({type:yt,payload:e})}applyRemoved(e){return this.apply({type:ft,payload:e})}async list(e={}){return(e.refresh||0===this.snapshots.size)&&await this.bootstrapFromInstances(),this.view()}async streamDescriptors(){return 0===this.snapshots.size&&await this.bootstrapFromInstances(),[...this.snapshots.entries()].map(([e,t])=>({topic:"app.sessions",instanceId:e,streamId:t.streamId,latestRevision:t.revision,earliestRetainedRevision:this.history.get(e)?.[0]?.payload.meta.revision??t.revision+1}))}async delta(e){0===this.snapshots.size&&await this.bootstrapFromInstances();const t=this.resolveDeltaInstanceId(e.instanceId);this.pruneHistory(t);const n=this.snapshots.get(t)?.revision??0,i=this.snapshots.get(t)?.streamId||"unavailable",s=this.history.get(t)?.[0]?.payload.meta.revision??n+1;if(e.streamId!==i||e.sinceRevision>n)return Nt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!0,events:[]});if(e.sinceRevision===n)return Nt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:!1,events:[]});const r=(this.history.get(t)??[]).filter(t=>t.payload.meta.revision>e.sinceRevision),o=!r.length||r[0].payload.meta.revision!==e.sinceRevision+1;return Nt.parse({streamId:i,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:s,syncRequired:o,events:o?[]:r.map(({type:e,payload:t})=>({type:e,payload:t}))})}apply(e,t=!1){const{meta:n}=e.payload,i=this.advertisedStreams.get(n.instanceId)?.streamId;if(i&&i!==n.streamId)return this.logger?.warn?.({instanceId:n.instanceId,advertisedStreamId:i,streamId:n.streamId,revision:n.revision},"app-session.aggregator.event.obsolete-stream"),!1;const s=this.recoveries.get(n.instanceId);if(s&&!t)return s.streamId===n.streamId&&(s.highWater=Math.max(s.highWater,n.revision)),!1;const r=this.snapshots.get(n.instanceId);e.type===ht&&r&&r.streamId!==n.streamId&&(this.counters.streamResets+=1,this.logger?.info?.({instanceId:n.instanceId,previousStreamId:r.streamId,streamId:n.streamId,previousRevision:r.revision,revision:n.revision,traceId:n.traceId,resetCount:this.counters.streamResets},"app-session.aggregator.stream-reset"));const o=function(e,t){const{meta:n}=t.payload;if(t.type===ht)return e?.streamId===n.streamId&&n.revision===e.revision?{kind:"duplicate",projection:e}:e?.streamId===n.streamId&&n.revision<e.revision?{kind:"stale",projection:e}:{kind:"applied",projection:kt.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:_t(t.payload.snapshot.sessions,t.payload.snapshot.updatedAt)})};if(!e||e.streamId!==n.streamId)return{kind:"snapshot-required",projection:e,streamId:n.streamId};if(n.revision===e.revision)return{kind:"duplicate",projection:e};if(n.revision<e.revision)return{kind:"stale",projection:e};if(n.revision!==e.revision+1||n.previousRevision!==e.revision)return{kind:"gap",projection:e,expectedRevision:e.revision+1,receivedRevision:n.revision};const i=[...e.snapshot.sessions];if(t.type===yt){const e=i.findIndex(e=>e.id===t.payload.session.id);jt(t.payload.session.status)?e<0?i.push(t.payload.session):i[e]=t.payload.session:e>=0&&i.splice(e,1)}else{const e=i.findIndex(e=>e.id===t.payload.sessionId);e>=0&&i.splice(e,1)}const s=Ot(i,n.generatedAt);return{kind:"applied",projection:kt.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:s})}}(r,e);if("applied"!==o.kind)return this.logger?.warn?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,currentRevision:r?.revision,revision:n.revision,outcome:o.kind},`app-session.aggregator.event.${o.kind}`),"gap"!==o.kind&&"snapshot-required"!==o.kind||("gap"===o.kind&&(this.counters.gaps+=1),this.recoverStream(n.instanceId,n.streamId,n.revision).catch(e=>{this.logger?.warn?.({instanceId:n.instanceId,streamId:n.streamId,revision:n.revision,error:e instanceof Error?e.message:String(e)},"app-session.aggregator.recovery.failed")})),!1;const a=o.projection;return this.snapshots.set(n.instanceId,a),this.rememberEvent(n.instanceId,e),this.logger?.info?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,revision:n.revision,reason:n.reason,sessionCount:a.snapshot.sessions.length,runningCount:a.snapshot.runningCount,problemCount:a.snapshot.problemCount},"app-session.aggregator.event.accepted"),!0}async bootstrapFromInstances(){this.logger?.info?.({},"app-session.aggregator.bootstrap");const e=new Map(this.snapshots),t=await this.bootstrap(),n=new Set(t.instances.map(e=>e.instanceId));for(const[t,i]of e)n.has(t)||this.snapshots.get(t)!==i||(this.snapshots.delete(t),this.history.delete(t),this.advertisedStreams.delete(t));for(const n of t.instances){const t=this.snapshots.get(n.instanceId);if(t!==e.get(n.instanceId))continue;const i=this.advertisedStreams.get(n.instanceId)?.streamId;i&&i!==n.streamId||t?.streamId===n.streamId&&t.revision>=n.revision||(t?.streamId!==n.streamId&&this.history.delete(n.instanceId),this.snapshots.set(n.instanceId,{streamId:n.streamId,snapshot:_t(n.appSessions.sessions,n.appSessions.updatedAt),revision:n.revision,lastEventAt:n.lastEventAt}))}}recoverStream(e,t,n){const i=this.recoveries.get(e);if(i)return i.streamId===t?i.highWater=Math.max(i.highWater,n):(i.streamId=t,i.highWater=n),i.promise;if(!this.recoverDelta||!this.recoverSnapshot)return Promise.resolve();const s={promise:Promise.resolve(),streamId:t,highWater:n},r=++this.recoveryCount;return this.logger?.info?.({instanceId:e,highWater:n,recoveryNumber:r},"app-session.aggregator.recovery.started"),s.promise=(async()=>{for(;;){const t=this.advertisedStreams.get(e);if(!t)return;s.streamId!==t.streamId&&(s.streamId=t.streamId,s.highWater=t.latestRevision);const n=this.snapshots.get(e);if(n&&n.streamId===t.streamId){if(n.revision<Math.max(t.latestRevision,s.highWater)){const t=await this.recoverDelta(e,n.streamId,n.revision);if(this.advertisedStreams.get(e)?.streamId!==t.streamId||s.streamId!==t.streamId)continue;if(t.syncRequired){const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:ht,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`aps_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot-fallback"},"app-session.aggregator.recovery.snapshot")}else{for(const e of t.events)this.apply(e,!0)&&this.onRecoveredEvent?.(e);this.counters.deltaRecoveries+=1,s.highWater=Math.max(s.highWater,t.latestRevision),this.logger?.info?.({instanceId:e,streamId:t.streamId,sinceRevision:t.sinceRevision,latestRevision:t.latestRevision,eventCount:t.events.length,recoveryNumber:r,outcome:"delta"},"app-session.aggregator.recovery.delta")}}}else{const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:ht,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`aps_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot"},"app-session.aggregator.recovery.snapshot")}const i=this.snapshots.get(e),o=this.advertisedStreams.get(e);if(i&&o&&i.streamId===o.streamId&&i.revision>=Math.max(o.latestRevision,s.highWater))return void this.logger?.info?.({instanceId:e,streamId:i.streamId,revision:i.revision,recoveryNumber:r,outcome:"success"},"app-session.aggregator.recovery.completed")}})().finally(()=>this.recoveries.delete(e)),this.recoveries.set(e,s),s.promise}rememberEvent(e,t){const n=this.history.get(e)??[],i=n.length&&n[0].payload.meta.streamId!==t.payload.meta.streamId?[]:n;i.push({...t,createdAtMs:Date.now()}),this.history.set(e,i),this.pruneHistory(e)}pruneHistory(e){const t=this.history.get(e);if(!t?.length)return;const n=t.filter(e=>e.createdAtMs>=Date.now()-36e5);n.length?this.history.set(e,n):this.history.delete(e)}resolveDeltaInstanceId(e){if(e)return e;const t=[...this.snapshots.keys()];if(1===t.length)return t[0];throw new Error("APP_SESSION_DELTA_INSTANCE_ID_REQUIRED")}view(){return{updatedAt:(new Date).toISOString(),instances:[...this.snapshots.entries()].map(([e,t])=>({instanceId:e,streamId:t.streamId,appSessions:t.snapshot,revision:t.revision,lastEventAt:t.lastEventAt}))}}}function ph(e){return e.raw[0].replace(/\\\$\{/g,"${")}class uh{states=new Map;events;constructor(e){this.events=e}handle(e){if(e.type===Lr){const t=Bo(qr,e.payload);return void(t.success&&this.reconcileLifecycle(t.data))}if("instance.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";return void(t&&this.deleteState(t))}if(e.type===dr){const t=Bo(pr,e.payload);return void(t.success&&this.applyOutput(t.data))}if(e.type===cr){const t=Bo(ur,e.payload);t.success&&this.applyFinished(t.data)}}snapshots(){return[...this.states.values()].filter(e=>e.progress).map(e=>mr.parse({...e.progress,terminalTail:e.terminalTail,...e.terminalTruncated?{terminalTruncated:!0}:{}}))}close(){for(const e of this.states.values())e.timer&&clearTimeout(e.timer);this.states.clear()}deleteState(e){const t=this.states.get(e);t?.timer&&clearTimeout(t.timer),this.states.delete(e)}reconcileLifecycle(e){const t=this.states.get(e.instanceId),n=e.imageProvisioning;t&&(!n||n.generation>t.identity.generation||n.generation===t.identity.generation&&"ready"===n.phase)&&this.deleteState(e.instanceId)}applyOutput(e){const t=this.states.get(e.instanceId);if(t&&e.generation<t.identity.generation)return;if(t&&e.generation===t.identity.generation&&!e.replay&&e.sequence<=t.sequence)return;const n=this.requireState(e);e.replay&&(n.terminal=new yh,n.terminalTail="",n.layers.clear(),n.terminalTruncated=!1),n.sequence=Math.max(n.sequence,e.sequence),n.observedAt=e.observedAt,n.terminal.write(e.data);const i=`${n.terminalTail}${e.data}`;n.terminalTruncated||=i.length>262144,n.terminalTail=i.slice(-262144),function(e,t){for(const n of t.split("\n")){const t=n.trim().match(/^([a-f0-9]{6,64}):\s+(.+)$/i);if(!t)continue;const[,i,s]=t,r=s.toLowerCase(),o=["pull complete","already exists","download complete","pulling fs layer","waiting","downloading","extracting"].find(e=>r.startsWith(e));if(!o)continue;const a=e.get(i)||{status:o},d=gh(s);e.set(i,{...a,status:o,...d||{}})}}(n.layers,n.terminal.text()),n.progress=mh(n),this.schedule(n)}applyFinished(e){const t=this.states.get(e.instanceId);if(t&&e.generation<t.identity.generation)return;if(t&&e.generation===t.identity.generation&&e.sequence<=t.sequence)return;const n=this.requireState(e);n.sequence=Math.max(n.sequence,e.sequence),n.observedAt=e.observedAt,n.outcome=e.outcome,n.progress=mh(n),this.publish(n,!0)}requireState(e){const t=this.states.get(e.instanceId);if(t&&t.identity.generation===e.generation)return t;t?.timer&&clearTimeout(t.timer);const n={identity:{instanceId:e.instanceId,generation:e.generation,requestedReference:e.requestedReference},sequence:e.sequence,observedAt:e.observedAt,terminal:new yh,terminalTail:"",terminalTruncated:!1,layers:new Map};return this.states.set(e.instanceId,n),n}schedule(e){e.timer||(e.timer=setTimeout(()=>this.publish(e,!1),250),e.timer.unref?.())}publish(e,t){e.timer&&clearTimeout(e.timer),e.timer=void 0,e.progress&&(e.progress=mh(e),this.events.publish("image.pull.progress",e.progress,{topic:"instances",scope:{instanceId:e.identity.instanceId}}),t&&(e.progress=mh(e)))}}function mh(e){const t=[...e.layers.values()],n=t.filter(e=>["pull complete","already exists"].includes(e.status)).length,i=t.filter(e=>"download complete"===e.status).length,s=t.filter(e=>"downloading"===e.status).length,r=t.filter(e=>"extracting"===e.status).length;let o=0,a=0;for(const e of t)e.total&&(a+=e.total,o+=["pull complete","already exists","download complete"].includes(e.status)?e.total:Math.min(e.current||0,e.total));const d="failed"===e.outcome?"failed":"succeeded"===e.outcome?"complete":r>0?"extracting":t.length>0?"pulling":"connecting",c=t.filter(e=>"already exists"!==e.status),l=c.length>0&&c.every(e=>Boolean(e.total)),p=l&&a>0?Math.max(0,Math.min(100,o/a*100)):void 0,u="failed"===d?"Image pull failed":"complete"===d?"Image pull complete":t.length?`${n}/${t.length} layers ready${void 0===p?"":` · ${Math.round(p)}%`}`:"Connecting to image registry";return mr.parse({...e.identity,sequence:e.sequence,observedAt:e.observedAt,status:d,layers:{total:t.length,completed:n,downloaded:i,downloading:s,extracting:r},...l&&a>0?{bytes:{current:o,total:a},percent:p}:{},message:u})}function gh(e){const t=e.match(/([\d.]+)\s*([kmgt]?i?b)\s*\/\s*([\d.]+)\s*([kmgt]?i?b)/i);if(t)return{current:hh(t[1],t[2]),total:hh(t[3],t[4])}}function hh(e,t){return Number(e)*1024**({b:0,kb:1,kib:1,mb:2,mib:2,gb:3,gib:3,tb:4,tib:4}[t.toLowerCase()]||0)}class yh{lines=[[]];row=0;col=0;pending="";write(e){const t=`${this.pending}${e}`;this.pending="";for(let e=0;e<t.length;){const n=t[e];if(""===n&&"["===t[e+1]){let n=e+2;for(;n<t.length&&!/[\x40-\x7e]/.test(t[n]);)n+=1;if(n>=t.length){this.pending=t.slice(e);break}this.csi(t.slice(e+2,n),t[n]),e=n+1;continue}"\r"===n?this.col=0:"\n"===n?(this.row+=1,this.col=0,this.ensureLine()):"\b"===n?this.col=Math.max(0,this.col-1):n>=" "&&(this.ensureLine(),this.lines[this.row][this.col]=n,this.col+=1),e+=1}this.trim()}text(){return this.lines.map(e=>e.join("").trimEnd()).join("\n")}csi(e,t){const n=e.replace(/^\?/,"").split(";").map(e=>Number(e||1)),i=n[0]||1;"A"===t?this.row=Math.max(0,this.row-i):"B"===t?(this.row+=i,this.ensureLine()):"C"===t?this.col+=i:"D"===t?this.col=Math.max(0,this.col-i):"G"===t?this.col=Math.max(0,i-1):"H"===t||"f"===t?(this.row=Math.max(0,i-1),this.col=Math.max(0,(n[1]||1)-1),this.ensureLine()):"K"===t?(this.ensureLine(),2===(n[0]||0)?this.lines[this.row]=[]:this.lines[this.row].splice(this.col)):"J"===t&&2===(n[0]||0)&&(this.lines=[[]],this.row=0,this.col=0)}ensureLine(){for(;this.lines.length<=this.row;)this.lines.push([])}trim(){if(this.lines.length<=500)return;const e=this.lines.length-500;this.lines.splice(0,e),this.row=Math.max(0,this.row-e)}}const fh=a.z.object({revision:a.z.number().int().nonnegative(),invites:a.z.array(Kn),bindings:a.z.array(Zn)}).strict(),Ih={invite:new Set(Object.keys(Kn.shape)),binding:new Set(Object.keys(Zn.shape))};function bh(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e;return Object.fromEntries([...t].filter(e=>e in n).map(e=>[e,n[e]]))}function vh(e,t,n){if(!t||"object"!=typeof t||Array.isArray(t))return t;const i=t,s=Ih[e],r=Object.keys(i).filter(e=>!s.has(e));r.length>0&&n?.({kind:e,fields:r});const o=bh(i,s);return"binding"===e&&o.lastError&&(o.lastError=bh(o.lastError,Object.keys(Gn.shape))),o}function wh(e){const{tokenHash:t,...n}=e;return Jn.parse(n)}function Sh(e){const{credentialHash:t,...n}=e;return ei.parse(n)}class Ah{authority;constructor(e,t){this.authority=new Io(e,()=>({revision:0,invites:[],bindings:[]}),{schema:fh,sanitize:e=>function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,i=new Set(["revision","invites","bindings"]),s=Object.keys(n).filter(e=>!i.has(e));return s.length>0&&t?.({kind:"authority",fields:s}),{...void 0===n.revision?{}:{revision:n.revision},invites:Array.isArray(n.invites)?n.invites.map(e=>vh("invite",e,t)):n.invites,bindings:Array.isArray(n.bindings)?n.bindings.map(e=>vh("binding",e,t)):n.bindings}}(e,e=>t?.("unknown stored control-plane proxy fields were ignored",e)),logger:t,directoryMode:448,fileMode:384})}init(){this.authority.init()}snapshot(){return this.authority.get()}transaction(e){const t=this.authority.get(),n=structuredClone(t),i=e(n);return JSON.stringify(n)!==JSON.stringify(t)&&this.authority.put({...n,revision:t.revision+1}),i}listInvites(){return this.snapshot().invites}getInvite(e){return this.snapshot().invites.find(t=>t.id===e)}listBindings(){return this.snapshot().bindings}getBinding(e){return this.snapshot().bindings.find(t=>t.id===e)}}class kh extends Error{code;statusCode;retryable;details;constructor(e,t,n,i=!1,s={}){super(t),this.name="ControlPlaneProxyServiceError",this.code=e,this.statusCode=n,this.retryable=i,this.details=s}}const zh=e=>i.createHash("sha256").update(e).digest("base64url"),Th=()=>i.randomBytes(32).toString("base64url");function Eh(e,t){const n=zh(t),s=Buffer.from(e),r=Buffer.from(n);return s.length===r.length&&i.timingSafeEqual(s,r)}function Ch(e,t,n,i=!1,s={}){throw new kh(e,t,n,i,s)}class xh{store;targets;configuredProxyOrigin;proxyOriginProvider;now;createTokenValue;constructor(e,t,n){this.store=e,this.targets=t,this.configuredProxyOrigin=n.proxyOrigin,this.proxyOriginProvider=n.proxyOriginProvider,this.now=n.now??(()=>new Date),this.createTokenValue=n.createToken??Th}init(){this.store.init(),this.expireInvites()}createInvite(e,t){const n=this.resolveProxyOrigin();n||Ch(Hn.Unavailable,"Configure an externally reachable HTTPS control-plane proxy origin before creating an invite.",409,!1);const i=Yn.parse(e);this.requireManageableTarget(i.targetNodeId);const s=this.createTokenValue(),r=this.nowIso(),o={id:ho("proxy_invite"),targetNodeId:i.targetNodeId,tokenHash:zh(s),status:"active",createdBy:t,expiresAt:new Date(this.now().getTime()+1e3*i.expiresInSeconds).toISOString(),createdAt:r,updatedAt:r},a=Qn.parse({invite:wh(o),token:s,proxyOrigin:n,protocolVersion:Nn});return this.store.transaction(e=>e.invites.push(o)),a}resolveProxyOrigin(){const e=this.configuredProxyOrigin??this.proxyOriginProvider?.();if(!e)return;const t=Dn.safeParse(e);return t.success?t.data:void 0}listInvites(){return this.expireInvites(),this.store.listInvites().map(wh)}revokeInvite(e){const t=this.requireInvite(e);if("consumed"===t.status&&Ch(Hn.InviteConsumed,"A consumed proxy invite cannot be revoked independently of its binding.",409,!1,{inviteId:e}),"revoked"===t.status||"expired"===t.status)return wh(t);const n=this.nowIso(),i={...t,status:"revoked",revokedAt:n,updatedAt:n};return this.store.transaction(t=>{t.invites[t.invites.findIndex(t=>t.id===e)]=i}),wh(i)}claimInvite(e){const t=ti.parse(e);this.requireCurrentProtocol(t.protocolVersion),this.expireInvites();const n=zh(t.credential);return this.store.transaction(e=>{const i=e.bindings.find(e=>e.claimId===t.claimId);if(!t.inviteToken)return i||Ch(Hn.InviteInvalid,"Proxy invite token is required for the first claim.",401),(i.sourceControlPlaneId!==t.sourceControlPlaneId||i.bindingKeyId!==t.bindingKeyId||i.credentialHash!==n||void 0!==t.targetNodeId&&i.targetNodeId!==t.targetNodeId)&&Ch(Hn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),"revoked"===i.status&&Ch(Hn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:i.id}),this.claimResult(i,this.requireKnownTarget(i.targetNodeId));const s=e.invites.find(e=>Eh(e.tokenHash,t.inviteToken));s||Ch(Hn.InviteInvalid,"Proxy invite is invalid.",401),t.targetNodeId&&t.targetNodeId!==s.targetNodeId&&Ch(Hn.TargetMismatch,"Proxy invite is bound to a different target.",409,!1,{inviteId:s.id,targetNodeId:t.targetNodeId});const r=(o=s.id,`proxy_binding_${zh(o).slice(0,32)}`);var o;const a=e.bindings.find(e=>e.id===r),d=e.bindings.find(e=>e.claimId===t.claimId),c=a??d;if(a&&d&&a.id!==d.id&&Ch(Hn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId}),c)return this.requireExactIdentity(c,r,s.targetNodeId,t,n),"revoked"===c.status&&Ch(Hn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:c.id}),"consumed"===s.status&&s.consumedByClaimId===t.claimId||Ch(Hn.BindingIdentityConflict,"Proxy binding and invite authority are inconsistent.",409,!1,{claimId:t.claimId}),this.claimResult(c,this.requireKnownTarget(c.targetNodeId));this.requireClaimableInvite(s);const l=this.requireManageableTarget(s.targetNodeId),p=this.nowIso(),u={id:r,claimId:t.claimId,sourceControlPlaneId:t.sourceControlPlaneId,targetNodeId:s.targetNodeId,bindingKeyId:t.bindingKeyId,credentialHash:n,status:"active",revision:1,createdAt:p,updatedAt:p};return e.bindings.push(u),Object.assign(s,{status:"consumed",consumedByClaimId:t.claimId,consumedAt:p,updatedAt:p}),this.claimResult(u,l)})}listBindings(){return this.store.listBindings().map(Sh)}authenticateBinding(e,t){const n=ni.parse(t),i=this.store.getBinding(e);return i||Ch(Hn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),"active"!==i.status&&Ch(Hn.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:e}),i.sourceControlPlaneId===n.sourceControlPlaneId&&i.bindingKeyId===n.bindingKeyId&&Eh(i.credentialHash,n.credential)||Ch(Hn.AuthenticationFailed,"Proxy binding authentication failed.",401,!1,{bindingId:e}),Sh(i)}revokeBinding(e){const t=this.requireBinding(e);if("revoked"===t.status)return Sh(t);const n=this.nowIso(),i={...t,status:"revoked",revision:t.revision+1,revokedAt:n,updatedAt:n};return this.store.transaction(t=>{t.bindings[t.bindings.findIndex(t=>t.id===e)]=i}),Sh(i)}revokeTarget(e){return this.store.transaction(t=>{const n=this.nowIso();return{bindings:t.bindings.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>(Object.assign(e,{status:"revoked",revision:e.revision+1,revokedAt:n,updatedAt:n}),Sh(e))),invites:t.invites.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>(Object.assign(e,{status:"revoked",revokedAt:n,updatedAt:n}),wh(e)))}})}nowIso(){return this.now().toISOString()}requireCurrentProtocol(e){e!==Nn&&Ch(Hn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:e,supportedVersion:Nn})}requireKnownTarget(e){const t=this.targets.get(e);return t||Ch(Hn.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:e}),t}requireManageableTarget(e){const t=this.requireKnownTarget(e);return t.manageable&&"online"===t.status||Ch(Hn.TargetUnavailable,"Proxy target is not currently manageable.",503,!0,{targetNodeId:e}),t}requireInvite(e){const t=this.store.getInvite(e);return t||Ch(Hn.InviteInvalid,"Proxy invite is unknown.",404,!1,{inviteId:e}),t}requireBinding(e){const t=this.store.getBinding(e);return t||Ch(Hn.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),t}requireClaimableInvite(e){"active"!==e.status&&Ch({expired:Hn.InviteExpired,consumed:Hn.InviteConsumed,revoked:Hn.InviteRevoked}[e.status],`Proxy invite is ${e.status}.`,"expired"===e.status?410:409,!1,{inviteId:e.id})}requireExactIdentity(e,t,n,i,s){e.id===t&&e.claimId===i.claimId&&e.sourceControlPlaneId===i.sourceControlPlaneId&&e.targetNodeId===n&&e.bindingKeyId===i.bindingKeyId&&e.credentialHash===s||Ch(Hn.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:i.claimId})}claimResult(e,t){const{manageable:n,...i}=t;return ci.parse({protocolVersion:Nn,binding:Sh(e),target:i})}expireInvites(){const e=this.now().getTime();this.store.listInvites().some(t=>"active"===t.status&&Date.parse(t.expiresAt)<=e)&&this.store.transaction(t=>{const n=this.nowIso();for(const i of t.invites)"active"===i.status&&Date.parse(i.expiresAt)<=e&&(i.status="expired",i.updatedAt=n)})}}class Nh extends Error{statusCode=429;code=Hn.ResourceLimit;retryable=!0;details;constructor(e,t){super(e),this.name="NodeProxyRuntimeError",this.details=t}}class Oh{maxRequestBodyBytes;maxConcurrentHttpPerBinding;maxConcurrentStreamsPerBinding;maxHttpRequestsPerMinutePerBinding;maxConcurrentWebSocketsPerBinding;maxHttpResponseBytes;httpStreamIdleTimeoutMs;maxWebSocketFrameBytes;maxWebSocketBytes;webSocketIdleTimeoutMs;httpRequestWindowMs;bindings=new Map;requestWindows=new Map;requestWindowTimers=new Map;constructor(e={}){this.maxConcurrentHttpPerBinding=e.maxConcurrentHttpPerBinding??32,this.maxConcurrentStreamsPerBinding=e.maxConcurrentStreamsPerBinding??16,this.maxHttpRequestsPerMinutePerBinding=e.maxHttpRequestsPerMinutePerBinding??600,this.maxConcurrentWebSocketsPerBinding=e.maxConcurrentWebSocketsPerBinding??16,this.maxRequestBodyBytes=e.maxRequestBodyBytes??8388608,this.maxHttpResponseBytes=e.maxHttpResponseBytes??268435456,this.httpStreamIdleTimeoutMs=e.httpStreamIdleTimeoutMs??12e4,this.maxWebSocketFrameBytes=e.maxWebSocketFrameBytes??8388608,this.maxWebSocketBytes=e.maxWebSocketBytes??268435456,this.webSocketIdleTimeoutMs=e.webSocketIdleTimeoutMs??3e5,this.httpRequestWindowMs=e.httpRequestWindowMs??6e4}reserveHttp(e){this.consumeRequestRate(e);const t=this.activity(e);if(t.controllers.size>=this.maxConcurrentHttpPerBinding)throw this.deleteIfEmpty(e,t),this.limit("Proxy HTTP concurrency limit exceeded.",e,"http-concurrency",this.maxConcurrentHttpPerBinding);const n=new AbortController;t.controllers.add(n);let i,s=!1,r=!1,o=0;const a=()=>{r&&!s&&(i&&clearTimeout(i),i=setTimeout(()=>{n.abort(Object.assign(new Error("Proxy HTTP stream idle timeout."),{code:Hn.ResourceLimit}))},this.httpStreamIdleTimeoutMs),i.unref?.())};return{controller:n,acceptRequestBody:t=>{if(t>this.maxRequestBodyBytes)throw this.limit("Proxy request body limit exceeded.",e,"request-body",this.maxRequestBodyBytes)},beginResponseStream:()=>{if(!s&&!r){if(t.streams.size>=this.maxConcurrentStreamsPerBinding)throw this.limit("Proxy HTTP stream concurrency limit exceeded.",e,"stream-concurrency",this.maxConcurrentStreamsPerBinding);r=!0,t.streams.add(n),a()}},acceptResponseChunk:t=>{if(!s){if(o+=_h(t),o>this.maxHttpResponseBytes){const t=this.limit("Proxy HTTP response byte limit exceeded.",e,"response-bytes",this.maxHttpResponseBytes);throw n.abort(t),t}a()}},release:()=>{s||(s=!0,i&&clearTimeout(i),t.controllers.delete(n),t.streams.delete(n),this.deleteIfEmpty(e,t))}}}openHttp(e,t){const n=this.reserveHttp(e);try{return n.acceptRequestBody(t),n}catch(e){throw n.release(),e}}openWebSocket(e,t,n){const i=this.activity(e);if(i.sockets.size>=this.maxConcurrentWebSocketsPerBinding)throw this.limit("Proxy WebSocket concurrency limit exceeded.",e,"websocket-concurrency",this.maxConcurrentWebSocketsPerBinding);let s,r=!1,o=0;const a=()=>{r||(r=!0,s&&clearTimeout(s),i.sockets.delete(p),this.deleteIfEmpty(e,i),n?.())},d=e=>{a(),t.close(1009,e)},c=()=>{s&&clearTimeout(s),s=setTimeout(()=>{a(),t.close(1001,"Proxy WebSocket idle timeout.")},this.webSocketIdleTimeoutMs),s.unref?.()},l=e=>{const t=_h(e);return t>this.maxWebSocketFrameBytes?(d("Proxy WebSocket frame limit exceeded."),!1):(o+=t,o>this.maxWebSocketBytes?(d("Proxy WebSocket byte limit exceeded."),!1):(c(),!0))};c();const p={get readyState(){return t.readyState},send:e=>{!r&&l(e)&&t.send(e)},close:(e,n)=>{a(),t.close(e,n)},on:(e,n)=>{"message"!==e?"close"!==e&&"error"!==e?t.on(e,n):t.on(e,(...e)=>{a(),n(...e)}):t.on(e,(e,...t)=>{!r&&l(e)&&n(e,...t)})}};return i.sockets.add(p),p}closeBinding(e,t="Proxy binding was revoked."){const n=this.bindings.get(e);if(!n)return this.clearRequestWindow(e),{abortedRequests:0,closedSockets:0};const i=[...n.controllers],s=[...n.sockets],r=[...n.cleanup];this.bindings.delete(e);for(const e of i)e.abort(Object.assign(new Error(t),{code:Hn.BindingRevoked}));for(const e of r)e();for(const e of s)e.close(1008,t);return n.controllers.clear(),n.streams.clear(),n.sockets.clear(),n.cleanup.clear(),this.clearRequestWindow(e),{abortedRequests:i.length,closedSockets:s.length}}diagnostics(e){if(e){const t=this.bindings.get(e);return{bindingId:e,activeHttp:t?.controllers.size??0,activeStreams:t?.streams.size??0,activeWebSockets:t?.sockets.size??0}}return[...this.bindings].map(([e,t])=>({bindingId:e,activeHttp:t.controllers.size,activeStreams:t.streams.size,activeWebSockets:t.sockets.size}))}registerBindingCleanup(e,t){const n=this.activity(e);return n.cleanup.add(t),()=>{n.cleanup.delete(t),this.deleteIfEmpty(e,n)}}activity(e){const t=this.bindings.get(e);if(t)return t;const n={controllers:new Set,streams:new Set,sockets:new Set,cleanup:new Set};return this.bindings.set(e,n),n}deleteIfEmpty(e,t){0===t.controllers.size&&0===t.streams.size&&0===t.sockets.size&&0===t.cleanup.size&&this.bindings.get(e)===t&&this.bindings.delete(e)}limit(e,t,n,i){return new Nh(e,{bindingId:t,resource:n,limit:i})}consumeRequestRate(e){const t=Date.now(),n=t-this.httpRequestWindowMs,i=(this.requestWindows.get(e)||[]).filter(e=>e>n);if(i.length>=this.maxHttpRequestsPerMinutePerBinding)throw this.limit("Proxy HTTP request rate limit exceeded.",e,"request-rate",this.maxHttpRequestsPerMinutePerBinding);i.push(t),this.requestWindows.set(e,i),this.scheduleRequestWindowCleanup(e)}scheduleRequestWindowCleanup(e){const t=this.requestWindowTimers.get(e);t&&clearTimeout(t);const n=this.requestWindows.get(e);if(!n?.length)return this.requestWindows.delete(e),void this.requestWindowTimers.delete(e);const i=Math.max(1,n[0]+this.httpRequestWindowMs-Date.now()+1),s=setTimeout(()=>{this.requestWindowTimers.delete(e);const t=Date.now()-this.httpRequestWindowMs,n=(this.requestWindows.get(e)||[]).filter(e=>e>t);n.length?(this.requestWindows.set(e,n),this.scheduleRequestWindowCleanup(e)):this.requestWindows.delete(e)},i);s.unref?.(),this.requestWindowTimers.set(e,s)}clearRequestWindow(e){this.requestWindows.delete(e);const t=this.requestWindowTimers.get(e);t&&clearTimeout(t),this.requestWindowTimers.delete(e)}}function _h(e){return Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8")}class Rh{streams=new Map;historyLimit;maxEventBytes;maxHistoryBytes;createStreamId;projectTarget;unsubscribeBus;constructor(e,t){this.historyLimit=Math.max(1,t.historyLimit??256),this.maxEventBytes=Math.max(1024,t.maxEventBytes??524288),this.maxHistoryBytes=Math.max(this.maxEventBytes,t.maxHistoryBytes??16777216),this.createStreamId=t.createStreamId??(e=>`proxy_events_${e}_${i.randomUUID().replace(/-/g,"").slice(0,16)}`),this.projectTarget=t.projectTarget,this.unsubscribeBus=e.on(e=>this.accept(e))}stop(){this.unsubscribeBus();for(const e of this.streams.values())e.subscribers.clear();this.streams.clear()}cursor(e){const t=this.stream(e);return{streamId:t.streamId,revision:t.revision,earliestRetainedRevision:Ph(t)}}subscribe(e,t,n,i=()=>{}){const{bindingId:s,sourceControlPlaneId:r,targetNodeId:o}=e,a=this.stream(o),d=Ph(a);if(t>a.revision||t<d-1)return n(ai.parse({type:"control-plane-proxy.snapshot-required",protocolVersion:Nn,streamId:a.streamId,bindingId:s,sourceControlPlaneId:r,targetNodeId:o,sinceRevision:t,latestRevision:a.revision,earliestRetainedRevision:d,error:{code:Hn.SnapshotRequired,message:"Proxy target event history cannot continue from the requested revision; fetch a new snapshot.",retryable:!0,details:{targetNodeId:o}}})),{kind:"snapshot-required",close:()=>{}};n(oi.parse({type:"control-plane-proxy.events.ready",protocolVersion:Nn,streamId:a.streamId,bindingId:s,sourceControlPlaneId:r,targetNodeId:o,latestRevision:a.revision,earliestRetainedRevision:d}));for(const e of a.history)e.event.revision>t&&n(jh(e.event,s,r));const c={bindingId:s,sourceControlPlaneId:r,send:n,onDeliveryFailure:i};a.subscribers.add(c);let l=!1;return{kind:"subscribed",close:()=>{l||(l=!0,a.subscribers.delete(c))}}}diagnostics(e){const t=this.stream(e);return{targetNodeId:e,streamId:t.streamId,revision:t.revision,earliestRetainedRevision:Ph(t),historySize:t.history.length,historyBytes:t.historyBytes,subscribers:t.subscribers.size,subscriberBindings:[...t.subscribers].map(({bindingId:e,sourceControlPlaneId:t})=>({bindingId:e,sourceControlPlaneId:t}))}}accept(e){const t=e.scope?.nodeId;if("string"!=typeof t||!t)return;let n;try{n=this.projectTarget(t)}catch{return}if(!n)return;const i=this.stream(t),s=i.revision+1,r=ri.safeParse({type:"control-plane-proxy.event",protocolVersion:Nn,streamId:i.streamId,bindingId:"proxy_projection",sourceControlPlaneId:"proxy_projection",targetNodeId:t,revision:s,source:{id:e.id,seq:e.seq},target:n,event:{type:e.type,topic:e.topic,createdAt:e.createdAt}});if(!r.success)return;const{bindingId:o,sourceControlPlaneId:a,...d}=r.data,c=Dh(d);if(!(void 0===c||c>this.maxEventBytes-512)){for(i.revision=s,i.history.push({event:d,bytes:c}),i.historyBytes+=c;i.history.length>this.historyLimit||i.historyBytes>this.maxHistoryBytes;){const e=i.history.shift();e&&(i.historyBytes-=e.bytes)}for(const e of[...i.subscribers])try{const t=jh(d,e.bindingId,e.sourceControlPlaneId),n=Dh(t);if(void 0===n||n>this.maxEventBytes)throw new Error("Proxy event byte limit exceeded.");e.send(t)}catch{i.subscribers.delete(e);try{e.onDeliveryFailure()}catch{}}}}stream(e){const t=this.streams.get(e);if(t)return t;const n={streamId:this.createStreamId(e),revision:0,history:[],historyBytes:0,subscribers:new Set};return this.streams.set(e,n),n}}function Ph(e){return e.history[0]?.event.revision??e.revision+1}function jh(e,t,n){return ri.parse({...e,bindingId:t,sourceControlPlaneId:n})}function Dh(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return}}function Mh(e,t){const n=new WeakSet;let i=t,s=0;const r=e=>{if(i-=Buffer.byteLength(e,"utf8"),i<0)throw Lh("Proxy target projection byte limit exceeded.",{resource:"target-projection-bytes",limit:t})},o=(e,t)=>{if(s+=1,s>16384||t>24)throw Lh("Proxy target projection complexity limit exceeded.");if(null===e||"boolean"==typeof e)return e;if("string"==typeof e)return r(e),e;if("number"==typeof e)return Number.isFinite(e)?e:null;if("object"!=typeof e)return;if(n.has(e))throw Lh("Proxy target projection contains a cycle.",void 0,!1);if(n.add(e),Array.isArray(e)){const i=e.map(e=>o(e,t+1)??null);return n.delete(e),i}const i={};for(const[n,s]of Object.entries(e)){if("__proto__"===n||"constructor"===n||"prototype"===n)continue;r(n);const e=o(s,t+1);void 0!==e&&(i[n]=e)}return n.delete(e),i};return o(e,0)}function Lh(e,t,n=!0){return Object.assign(new Error(e),{code:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",statusCode:429,retryable:n,...t?{details:t}:{}})}function qh(e){const{manageable:t,...n}=e;return n}const $h=a.z.object({bindingId:a.z.string().trim().min(1).max(160)}).passthrough(),Bh=a.z.object({route:Mn}).strict(),Uh=a.z.object({sinceRevision:a.z.coerce.number().int().nonnegative()}).strict(),Fh=new Set(["connection","cookie","host","keep-alive","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Hh=524288;function Wh(e,t,n){const i=Xh(n.headers,$n);if(i!==Nn)throw Qh(Hn.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:i,supportedVersion:Nn});const s=Xh(n.headers,Bn),r=Xh(n.headers,Un),o=Xh(n.headers,Fn);if(!s||!r||!o)throw Qh(Hn.AuthenticationFailed,"Proxy binding authentication headers are incomplete.",401);return e.authenticateBinding(t,{sourceControlPlaneId:s,bindingKeyId:r,credential:o})}function Gh(e,t,n){const i=Wh(e,t.id,n);if(i.id!==t.id||i.revision!==t.revision||i.sourceControlPlaneId!==t.sourceControlPlaneId||i.targetNodeId!==t.targetNodeId||i.bindingKeyId!==t.bindingKeyId||"active"!==i.status)throw Qh(Hn.BindingIdentityConflict,"Proxy binding changed while the request was being established.",409,!0,{bindingId:t.id,expectedRevision:t.revision,actualRevision:i.revision})}function Vh(e,t){if(t.id!==e.targetNodeId)throw Qh(Hn.TargetMismatch,"Proxy target resolver returned another node.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}function Kh(e){for(const t of Object.keys(e)){const e=t.toLowerCase();if(e.startsWith("x-taskhandoff-node-")||e.startsWith("x-task-handoff-node-"))throw Qh(Hn.HeaderInvalid,"Caller-supplied node transport authentication headers are forbidden.",400,!1,{header:e})}const t=Object.fromEntries([...Ln].flatMap(t=>{if(Fh.has(t))return[];const n=e[t];return void 0===n?[]:[[t,Array.isArray(n)?n.join(", "):String(n)]]}));if(void 0!==t["x-request-id"]){const e=jn.safeParse(t["x-request-id"]);if(!e.success)throw Qh(Hn.HeaderInvalid,"Proxy request correlation id is invalid.",400,!1,{header:"x-request-id"});t["x-request-id"]=e.data}return t}function Jh(e,t,n){const i=Yh(t),s=Zh(n?.headers);return s&&e.header("x-request-id",s),e.code(i.statusCode).send({error:{code:i.code,message:i.message,retryable:i.retryable,...i.details?{details:i.details}:{}}})}function Yh(e){const t=e&&"object"==typeof e?e:{},n="number"==typeof t.statusCode?t.statusCode:502;return{statusCode:n,code:("string"==typeof t.code?t.code:void 0)||Hn.TransportFailed,message:e instanceof Error?e.message:"Control-plane proxy transport failed.",retryable:"boolean"==typeof t.retryable?t.retryable:n>=500,details:t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?t.details:void 0}}function Qh(e,t,n,i=!1,s){return Object.assign(new Error(t),{code:e,statusCode:n,retryable:i,...s?{details:s}:{}})}function Xh(e,t){const n=e[t];return Array.isArray(n)?n.join(","):"string"==typeof n?n:""}function Zh(e){if(!e)return;const t=jn.safeParse(Xh(e,"x-request-id"));return t.success?t.data:void 0}function ey(e){let t="";for(const n of e){if(Buffer.byteLength(t+n)>123)break;t+=n}return t}const ty=e=>Gn.parse({code:Hn.Unavailable,message:e,retryable:!0});class ny{service;subscriptions=new Map;fetchImpl;openWebSocket;reconnectDelayMs;onStateChanged;logger;running=!1;constructor(e,t={}){this.service=e,this.fetchImpl=t.fetchImpl??fetch,this.openWebSocket=t.openWebSocket??((e,t)=>new l.WebSocket(e,{headers:t})),this.reconnectDelayMs=Math.max(0,t.reconnectDelayMs??2e3),this.onStateChanged=t.onStateChanged??(()=>{}),this.logger=t.logger}start(){this.running||(this.running=!0,this.syncNow())}syncNow(){if(!this.running)return;const e=new Map(this.service.listNodes().filter(e=>"control-plane-proxy"===e.connectionMode&&!1!==e.connectionEnabled).map(e=>[e.id,e]));for(const t of this.subscriptions.keys())e.has(t)||this.remove(t);for(const t of e.values()){const e=this.subscriptionIdentity(t),n=this.subscriptions.get(t.id);if(n?.identity===e)continue;n&&this.remove(t.id);const i={generation:1,identity:e};this.subscriptions.set(t.id,i),this.connect(t.id,i.generation)}}stop(){this.running=!1;for(const e of[...this.subscriptions.keys()])this.remove(e)}remove(e){const t=this.subscriptions.get(e);t&&(t.generation+=1,t.reconnect&&clearTimeout(t.reconnect),t.socket?.close(),this.subscriptions.delete(e))}async connect(e,t){if(!this.current(e,t))return;const n=this.service.proxyPrivateStore.nodeCredential(e);if(n)try{const i=await this.fetchImpl(function(e){return new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/snapshot`,e.proxyOrigin)}(n),{headers:vd(n)});if(!this.current(e,t))return;const s=await i.json().catch(()=>{});if(!i.ok){const n=Bo(Gn,s?.error),r=n.success?n.data:ty(`Proxy snapshot failed with HTTP ${i.status}.`);return r.code===Hn.BindingRevoked?void this.onStateChanged(this.service.markProxyBindingRevoked(e,r)):void this.fail(e,t,r,r.retryable)}const r=Uo(si,s?.data);if(this.validateIdentity(n,r.binding.id,r.binding.targetNodeId),this.onStateChanged(this.service.applyProxyTargetSnapshot(e,r)),"revoked"===r.binding.status)return void this.onStateChanged(this.service.markProxyBindingRevoked(e,{code:Hn.BindingRevoked,message:"Control-plane proxy binding was revoked.",retryable:!1}));this.openEvents(e,t,n,r)}catch(n){if(!this.current(e,t))return;this.logger?.warn?.({nodeId:e,error:iy(n)},"control-plane proxy state bootstrap failed"),this.fail(e,t,ty("Trusted control-plane proxy is unavailable."),!0)}else this.fail(e,t,ty("Control-plane proxy credential is unavailable."),!1)}openEvents(e,t,n,i){const s=this.current(e,t);if(!s)return;const r=this.openWebSocket(function(e,t){const n=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/events`,e.proxyOrigin);return n.protocol="wss:",n.searchParams.set("sinceRevision",String(t)),n.toString()}(n,i.revision),vd(n));s.socket=r;let o=!1;const a=n=>{o||(o=!0,this.fail(e,t,ty(n),!0))};r.on("message",s=>{if(this.current(e,t))try{const r=Uo(di,JSON.parse(String(s)));if(r.bindingId!==n.proxyBindingId||r.sourceControlPlaneId!==n.sourceControlPlaneId||r.targetNodeId!==n.targetNodeId||r.streamId!==i.streamId)throw new Error("Proxy event stream identity changed.");if("control-plane-proxy.snapshot-required"===r.type)return void this.restart(e,t);if("control-plane-proxy.events.ready"===r.type)return;this.onStateChanged(this.service.applyProxyTargetEvent(e,r))}catch(n){this.logger?.warn?.({nodeId:e,error:iy(n)},"control-plane proxy event requires a new snapshot"),this.restart(e,t)}}),r.on("error",()=>a("Control-plane proxy event stream failed.")),r.on("close",()=>a("Control-plane proxy event stream disconnected."))}restart(e,t){const n=this.current(e,t);n&&(n.generation+=1,n.socket?.close(),n.socket=void 0,this.connect(e,n.generation))}fail(e,t,n,i){const s=this.current(e,t);if(s){if(this.onStateChanged(this.service.markProxyUnavailable(e,n)),!i)return s.generation+=1,s.socket?.close(),void this.subscriptions.delete(e);s.generation+=1,s.socket?.close(),s.socket=void 0,s.reconnect=setTimeout(()=>{s.reconnect=void 0,this.connect(e,s.generation)},this.reconnectDelayMs),s.reconnect.unref?.()}}current(e,t){const n=this.subscriptions.get(e);return this.running&&n?.generation===t?n:void 0}validateIdentity(e,t,n){if(t!==e.proxyBindingId||n!==e.targetNodeId){const e=new Error("Proxy snapshot identity does not match the private binding credential.");throw Object.assign(e,{code:Hn.BindingIdentityConflict}),e}}subscriptionIdentity(e){const t=this.service.proxyPrivateStore.nodeCredential(e.id);return JSON.stringify({connectionMode:e.connectionMode,connectionPath:e.connectionPath,credential:t&&{id:t.id,proxyOrigin:t.proxyOrigin,proxyBindingId:t.proxyBindingId,targetNodeId:t.targetNodeId,sourceControlPlaneId:t.sourceControlPlaneId,bindingKeyId:t.bindingKeyId,updatedAt:t.updatedAt}})}}function iy(e){const t=e&&"object"==typeof e?e:{};return{name:e instanceof Error?e.name:"Error",message:e instanceof Error?e.message:String(e),..."string"==typeof t.code?{code:t.code}:{}}}const sy=a.z.object({id:a.z.string().trim().min(1).max(160)}).strict(),ry=a.z.object({}).strict(),oy=a.z.object({algorithm:a.z.literal("Ed25519"),publicKey:a.z.string().regex(/^[A-Za-z0-9_-]{43}$/),privateKeyPkcs8:a.z.string().regex(/^[A-Za-z0-9_-]{64}$/)}).strip();function ay(){const{publicKey:e,privateKey:t}=i.generateKeyPairSync("ed25519"),n=e.export({format:"jwk"});if(!n.x)throw new Error("Generated Control Plane identity did not contain an Ed25519 public key.");return{algorithm:"Ed25519",publicKey:n.x,privateKeyPkcs8:t.export({format:"der",type:"pkcs8"}).toString("base64url")}}function dy(e){return`sha256:${i.createHash("sha256").update(Buffer.from(e,"base64url")).digest("base64url")}`}function cy(e){return Array.isArray(e)?`[${e.map(cy).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${cy(t)}`).join(",")}}`:JSON.stringify(e)}class ly{identity;controlPlaneId;constructor(e,t,n){this.controlPlaneId=t,this.identity=new Io(e,ay,{schema:oy,logger:n,directoryMode:448,fileMode:384})}init(){this.identity.init(),this.privateKey()}publicDocument(e,t=Date.now()){const n=this.identity.get(),s={authentication:e,aiSessions:!0,nodes:!0,instanceBoard:!0,triggers:!0},r=io.parse({version:1,kind:"control-plane",controlPlaneId:this.controlPlaneId(),publicKey:{algorithm:"Ed25519",encoding:"base64url",value:n.publicKey,fingerprint:dy(n.publicKey)},capabilities:s,protocolVersion:"2026-08-09",issuedAt:new Date(t).toISOString(),expiresAt:new Date(t+3e5).toISOString()}),o=i.sign(null,Buffer.from((a=r,JSON.stringify(io.parse(a)))),this.privateKey()).toString("base64url");var a;return so.parse({data:{payload:r,signature:o}})}publicIdentity(){const e=this.identity.get();return{controlPlaneId:this.controlPlaneId(),algorithm:e.algorithm,publicKey:e.publicKey,fingerprint:dy(e.publicKey)}}signCloudBindingChallenge(e){return i.sign(null,Buffer.from(`task-handoff:cloud-binding-challenge:v1\n${cy(e)}`),this.privateKey()).toString("base64url")}signCloudOutboundRegistration(e){return i.sign(null,Buffer.from((t=e,`task-handoff:outbound-control-registration:v1\n${Jt(an.parse(t))}`)),this.privateKey()).toString("base64url");var t}acceptCloudAccessHandshake(e,t){return function(e){const t=dn.parse(e.ticket),n=pn.parse(e.clientHello);if(t.ticketId!==n.ticketId||t.deviceSessionId!==n.deviceSessionId||t.targetPublicKeyFingerprint!==e.controlPlaneFingerprint)throw un();const s=i.generateKeyPairSync("x25519"),r=function(e){const t=e.export({format:"jwk"}).x;if(!t)throw un();return t}(s.publicKey),o=function(e,t,n){return i.createHash("sha256").update(Jt({audience:e.audience,ticketId:e.ticketId,accountId:e.accountId,deviceSessionId:e.deviceSessionId,controlPlaneId:e.controlPlaneId,bindingId:e.bindingId,bindingRevision:e.bindingRevision,nonce:e.nonce,clientEphemeralPublicKey:t,serverEphemeralPublicKey:n})).digest("base64url")}(t,n.clientEphemeralPublicKey,r);var a;const d=function(e,t){return i.createHash("sha256").update(e).update(t).update("task-handoff:control-plane-access:e2e:v1").digest()}(i.diffieHellman({privateKey:s.privateKey,publicKey:(a=n.clientEphemeralPublicKey,i.createPublicKey({key:{kty:"OKP",crv:"X25519",x:a},format:"jwk"}))}),o);return{sessionKey:d,response:{serverEphemeralPublicKey:r,transcript:o,signature:i.sign(null,Buffer.from(o),e.controlPlanePrivateKey).toString("base64url")}}}({ticket:e,clientHello:t,controlPlaneFingerprint:this.publicIdentity().fingerprint,controlPlanePrivateKey:this.privateKey()})}privateKey(){const e=this.identity.get(),t=i.createPrivateKey({key:Buffer.from(e.privateKeyPkcs8,"base64url"),format:"der",type:"pkcs8"});if(i.createPublicKey(t).export({format:"jwk"}).x!==e.publicKey)throw new Error("Stored Control Plane signing identity public and private keys do not match.");return t}}class py{observations=new Map;listeners=new Set;begin(e,t,n="connecting"){const i=this.observations.get(e),s={nodeId:e,transport:t,generation:(i?.generation||0)+1,phase:n,changedAt:(new Date).toISOString(),consecutiveFailures:i?.transport===t?i.consecutiveFailures:0,controlReachability:i?.transport===t?i.controlReachability:"unknown",controlChangedAt:i?.transport===t?i.controlChangedAt:void 0,controlError:i?.transport===t?i.controlError:void 0};return this.observations.set(e,s),this.publish(s),s.generation}update(e,t,n,i=!0){const s=this.observations.get(e);if(!s||s.generation!==t)return!1;const r={...s,...n,changedAt:(new Date).toISOString()};return this.observations.set(e,r),i&&this.publish(r),!0}connected(e,t){const n=(new Date).toISOString();return this.update(e,t,{phase:"healthy",connectedAt:n,lastSeenAt:n,nextRetryAt:void 0,error:void 0})}pong(e,t){const n=(new Date).toISOString();return this.update(e,t,{lastSeenAt:n,lastPongAt:n},!1)}stable(e,t){return this.update(e,t,{consecutiveFailures:0},!1)}observedReachable(e){if("control-plane-proxy"===e.connectionMode)return!1;const t="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http",n=this.observations.get(e.id),i=n?.transport===t?n.generation:this.begin(e.id,t,"handshaking");if("direct-http"===t){const t=(new Date).toISOString();return"reachable"===n?.controlReachability?this.update(e.id,i,{lastSeenAt:t},!1):this.update(e.id,i,{controlReachability:"reachable",controlChangedAt:t,controlError:void 0,lastSeenAt:t})}return"healthy"===n?.phase?this.update(e.id,i,{lastSeenAt:(new Date).toISOString()},!1):this.connected(e.id,i)}observedFailure(e,t){if("control-plane-proxy"===e.connectionMode)return!1;const n="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http",i=this.observations.get(e.id),s=i?.transport===n?i.generation:this.begin(e.id,n,"connecting");return"direct-http"===n?"unreachable"===i?.controlReachability?this.update(e.id,s,{controlError:t},!1):this.update(e.id,s,{controlReachability:"unreachable",controlChangedAt:(new Date).toISOString(),controlError:t}):this.disconnected(e.id,s,{error:t})}disconnected(e,t,n={}){const i=this.observations.get(e);return!(!i||i.generation!==t)&&this.update(e,t,{phase:n.nextRetryAt?"reconnecting":"offline",consecutiveFailures:i.consecutiveFailures+1,closeCode:n.closeCode,error:n.error,nextRetryAt:n.nextRetryAt})}observation(e){return this.observations.get(e)}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}project(e){if(!1===e.connectionEnabled)return{...e,status:"offline",health:"failed",connectionPhase:"offline"};if("direct-http"!==e.connectionMode&&"reverse-wss"!==e.connectionMode&&"local-ipc"!==e.connectionMode&&"local-loopback"!==e.connectionMode)return e;const t=this.observations.get(e.id),n="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http";return t&&t.transport===n?"direct-http"===n?"reachable"===t.controlReachability?{...e,status:"online",health:"unknown"===e.health||"failed"===e.health?"ok":e.health,lastSeenAt:t.lastSeenAt||e.lastSeenAt,connectionPhase:"healthy"}:{...e,status:"unreachable"===t.controlReachability?"offline":"unknown",health:"unreachable"===t.controlReachability?"failed":"unknown",lastSeenAt:t.lastSeenAt,connectionPhase:"unreachable"===t.controlReachability?"offline":"connecting"}:"healthy"===t.phase?{...e,status:"online",health:"unknown"===e.health?"ok":e.health,lastSeenAt:t.lastSeenAt||t.connectedAt,connectionPhase:t.phase}:"connecting"===t.phase||"handshaking"===t.phase||"reconnecting"===t.phase||"suspect"===t.phase?{...e,status:"offline",health:"degraded",lastSeenAt:t.lastSeenAt,connectionPhase:t.phase}:{...e,status:"offline",health:"failed",lastSeenAt:t.lastSeenAt,connectionPhase:t.phase}:"direct-http"===n?{...e,status:"unknown",health:"unknown",connectionPhase:"connecting"}:e}diagnostics(){return[...this.observations.values()].map(e=>({...e}))}publish(e){for(const t of this.listeners)t({...e})}}function uy(e,n){const i=t.extname(e);return`${i?e.slice(0,-i.length):e}.${n}${i}`}const my=1048576,gy=52428800;function hy(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}function yy(e){const i=[],s=e=>{if(n.existsSync(e))for(const r of n.readdirSync(e,{withFileTypes:!0})){const n=t.join(e,r.name);r.isSymbolicLink()||(r.isDirectory()?s(n):r.isFile()&&(r.name.endsWith(".log")||r.name.endsWith(".jsonl"))&&i.push(n))}};return s(e),i.sort()}function fy(e,i,s){const r=n.statSync(e),o=Math.min(r.size,my,s);if(o<=0)return 0;const a=Buffer.allocUnsafe(o),d=n.openSync(e,"r");try{n.readSync(d,a,0,o,Math.max(0,r.size-o))}finally{n.closeSync(d)}return n.mkdirSync(t.dirname(i),{recursive:!0,mode:448}),n.writeFileSync(i,a,{mode:384}),o}const Iy=a.z.object({version:a.z.literal(1),serviceOrigin:a.z.string().url(),status:a.z.enum(["unbound","pending-claim","active","pending-revocation","clone-conflict"]),remoteAccessEnabled:a.z.boolean(),accountId:a.z.string().optional(),bindingId:a.z.string().optional(),bindingRevision:a.z.number().int().positive().optional(),backgroundCredential:a.z.string().min(32).optional(),updatedAt:a.z.string().datetime(),connectionEpoch:a.z.number().int().nonnegative().default(0)}).strip();class by{state;challenges=new Map;identity;serviceOrigin;clock;constructor(e){this.identity=e.identity,this.serviceOrigin=new URL(e.serviceOrigin).origin,this.clock=e.clock??Date.now,this.state=new Io(e.statePath,()=>({version:1,serviceOrigin:this.serviceOrigin,status:"unbound",remoteAccessEnabled:!0,updatedAt:new Date(this.clock()).toISOString(),connectionEpoch:0}),{schema:Iy,directoryMode:448,fileMode:384})}init(){if(this.state.init(),this.state.get().serviceOrigin!==this.serviceOrigin)throw wy("CLOUD_SERVICE_ORIGIN_CHANGED","Cloud service origin does not match persisted binding authority.")}snapshot(){const{backgroundCredential:e,connectionEpoch:t,...n}=this.state.get();return{...n,identity:this.identity.publicIdentity(),hasBackgroundCredential:Boolean(e)}}createChallenge(){const e=this.state.get();if(["active","pending-revocation","clone-conflict"].includes(e.status))throw wy("active"===e.status?"CONTROL_PLANE_ALREADY_BOUND":"BINDING_STATE_CONFLICT","Existing cloud binding must be resolved first.");this.prune();const t=ho("binding_challenge"),n=i.randomBytes(32).toString("base64url"),s=this.challengePayload(t);return this.challenges.set(t,{digest:vy(n),payload:s,expiresAtMs:Date.parse(s.expiresAt)}),this.state.put({...e,status:"pending-claim",updatedAt:new Date(this.clock()).toISOString()}),{challengeCode:`${t}.${n}`,authorizationUrl:`${this.serviceOrigin}/bindings/authorize`,payload:s,signature:this.identity.signCloudBindingChallenge(s)}}consumeChallenge(e){const t=e.challengeCode.indexOf("."),n=e.challengeCode.slice(0,t),s=e.challengeCode.slice(t+1),r=this.challenges.get(n);if(r&&this.challenges.delete(n),!r||r.expiresAtMs<=this.clock()||(o=r.digest,a=vy(s),o.length!==a.length||!i.timingSafeEqual(o,a)))throw wy("BINDING_CHALLENGE_INVALID_OR_CONSUMED","Binding challenge is invalid, expired, or consumed.");var o,a;if(r.payload.controlPlaneId!==e.controlPlaneId||r.payload.publicKeyFingerprint!==e.fingerprint)throw wy("BINDING_IDENTITY_CONFLICT","Binding challenge identity does not match.");return r.payload}activate(e){const t=this.state.get();if("active"===t.status){if(t.accountId===e.accountId&&t.bindingId===e.bindingId&&t.bindingRevision===e.bindingRevision)return this.snapshot();throw wy("CONTROL_PLANE_ALREADY_BOUND","Control Plane is already bound to another account.")}if("pending-claim"!==t.status)throw wy("BINDING_STATE_CONFLICT","Control Plane has no pending binding claim.");return this.state.put({...t,status:"active",remoteAccessEnabled:!0,...e,updatedAt:new Date(this.clock()).toISOString()}),this.snapshot()}setRemoteAccess(e){const t=this.state.get();return this.state.put({...t,remoteAccessEnabled:e,updatedAt:new Date(this.clock()).toISOString()}),this.snapshot()}beginRevocation(){const e=this.state.get();return"unbound"===e.status||(this.challenges.clear(),this.state.put({...e,status:"pending-revocation",remoteAccessEnabled:!1,updatedAt:new Date(this.clock()).toISOString()})),this.snapshot()}confirmRevocation(){const e=this.state.get();return this.state.put({version:1,serviceOrigin:e.serviceOrigin,status:"unbound",remoteAccessEnabled:!1,updatedAt:new Date(this.clock()).toISOString(),connectionEpoch:e.connectionEpoch}),this.snapshot()}markCloneConflict(){const e=this.state.get();return this.challenges.clear(),this.state.put({...e,status:"clone-conflict",remoteAccessEnabled:!1,backgroundCredential:void 0,updatedAt:new Date(this.clock()).toISOString()}),this.snapshot()}backgroundCredential(){const e=this.state.get();return"active"===e.status&&e.remoteAccessEnabled?e.backgroundCredential:void 0}nextConnectionEpoch(){const e=this.state.get(),t=e.connectionEpoch+1;return this.state.put({...e,connectionEpoch:t,updatedAt:new Date(this.clock()).toISOString()}),t}challengePayload(e){const t=this.identity.publicIdentity(),n=this.clock();return{protocolVersion:"2026-08-10",audience:"task-handoff:binding",serviceOrigin:this.serviceOrigin,challengeId:e,controlPlaneId:t.controlPlaneId,publicKey:t.publicKey,publicKeyFingerprint:t.fingerprint,nonce:i.randomBytes(24).toString("base64url"),issuedAt:new Date(n).toISOString(),expiresAt:new Date(n+3e5).toISOString()}}prune(){const e=this.clock();for(const[t,n]of this.challenges)n.expiresAtMs<=e&&this.challenges.delete(t)}}function vy(e){return i.createHash("sha256").update(e).digest()}function wy(e,t){return Object.assign(new Error(t),{code:e,statusCode:e.includes("CONFLICT")||e.includes("BOUND")?409:400})}class Sy{revision=0;options;constructor(e){this.options=e}async apply(e){if(!Number.isSafeInteger(e.bindingRevision)||e.bindingRevision<this.revision)return{applied:!1,reason:"stale-revision"};if(this.revision=e.bindingRevision,"binding-revoked"===e.type||"account-disabled"===e.type||"background-credential-revoked"===e.type)this.options.state.beginRevocation(),await Promise.all([this.options.connections.stop(e.type),this.options.dataConnections.closeAll(e.type)]),this.options.state.confirmRevocation();else if("remote-access-changed"===e.type)this.options.state.setRemoteAccess(!0===e.enabled),e.enabled||await Promise.all([this.options.connections.stop("remote-access-disabled"),this.options.dataConnections.closeAll("remote-access-disabled")]);else{if("identity-clone-detected"!==e.type)return{applied:!1,reason:"unsupported-event"};this.options.state.markCloneConflict(),await Promise.all([this.options.connections.stop(e.type),this.options.dataConnections.closeAll(e.type)])}return{applied:!0}}}class Ay{attempt=0;minimumMs;maximumMs;random;constructor(e=250,t=3e4,n=Math.random){this.minimumMs=e,this.maximumMs=t,this.random=n}next(){const e=Math.min(this.maximumMs,this.minimumMs*2**this.attempt++);return Math.max(this.minimumMs,Math.floor(e*(.5+.5*this.random())))}reset(){this.attempt=0}}class ky{connection;processInstanceId=`control_plane_process_${i.randomUUID().replaceAll("-","_")}`;backoff;options;constructor(e){this.options=e,this.backoff=e.backoff??new Ay}async connectOnce(){const e=this.options.state.backgroundCredential(),t=this.options.state.snapshot();if(!t.remoteAccessEnabled||!("pending-claim"===t.status||"active"===t.status&&Boolean(e)))return{status:"disabled"};if(this.connection)return{status:"connected",reused:!0};const n=this.options.state.nextConnectionEpoch(),i=this.connection;return this.connection=await this.options.connector.connect({serviceOrigin:t.serviceOrigin,credential:e,bindingId:t.bindingId,bindingRevision:t.bindingRevision,controlPlaneId:t.identity.controlPlaneId,processInstanceId:this.processInstanceId,epoch:n,onEvent:this.options.onEvent}),await(i?.close("replaced-by-new-epoch")),this.backoff.reset(),{status:"connected",epoch:n}}reconnectDelay(){return this.backoff.next()}disconnected(){this.connection=void 0}async stop(e){const t=this.connection;this.connection=void 0,await(t?.close(e))}}class zy{connections=new Map;options;constructor(e){this.options=e}async attach(e){const t=await this.options.verifyAllocation(e),n=this.connections.get(t.allocationId);if(n&&t.epoch<=n.epoch)throw Object.assign(new Error("Cloud connection state is invalid."),{code:"STALE_CONNECTION_EPOCH"});const i=await this.options.connector.connect({relayUrl:t.relayUrl,allocation:e,epoch:t.epoch});return await(n?.connection.close("replaced-by-new-epoch")),this.connections.set(t.allocationId,{epoch:t.epoch,connection:i}),{status:"attached",allocationId:t.allocationId,epoch:t.epoch}}async closeAll(e){const t=[...this.connections.values()];this.connections.clear(),await Promise.allSettled(t.map(({connection:t})=>t.close(e)))}}class Ty{options;constructor(e){this.options=e}async disconnect(){const e=this.options.state.snapshot();if(!e.bindingId)return e;this.options.state.beginRevocation(),await this.options.connections.stop("binding-pending-revocation");try{if("revoked"===(await this.options.remote.revoke({bindingId:e.bindingId})).status)return this.options.state.confirmRevocation()}catch{}return this.options.state.snapshot()}async setRemoteAccess(e){const t=this.options.state.snapshot();if(this.options.state.setRemoteAccess(e),e||await this.options.connections.stop("remote-access-disabled"),t.bindingId)try{await this.options.remote.setRemoteAccess({bindingId:t.bindingId,enabled:e})}catch{return{...this.options.state.snapshot(),remoteResult:"unknown"}}return{...this.options.state.snapshot(),remoteResult:"confirmed"}}}class Ey{options;constructor(e){this.options=e}async connect(e){const t=e.allocation,n=ln.parse(t.attach),i=dn.parse(t.ticket),s=new(this.options.webSocket??l)(e.relayUrl,{followRedirects:!1,handshakeTimeout:1e4,perMessageDeflate:!1});return await function(e){return new Promise((t,n)=>{e.once("open",t),e.once("error",n),e.once("close",()=>n(Oy("RELAY_SOCKET_CLOSED")))})}(s),s.send(JSON.stringify({type:"attach",capability:n})),async function(e,t,n,i,s){const r=await xy(e,e=>"frame"===e?.type&&"handshake"===e.frame?.kind);if(r.frame.channelId!==t||0!==r.frame.sequence)throw Oy("RELAY_HANDSHAKE_SEQUENCE_INVALID");const o=JSON.parse(Buffer.from(r.frame.ciphertext,"base64url").toString("utf8")),a=i.acceptCloudAccessHandshake(n,o),d={...a.response,controlPlanePublicKey:i.publicIdentity().publicKey};e.send(JSON.stringify({type:"frame",frame:{protocolVersion:"2026-08-10",channelId:t,sequence:0,kind:"handshake",ciphertext:Buffer.from(JSON.stringify(d)).toString("base64url")}}));const c={type:"cloud-account",accountId:n.accountId,deviceSessionId:n.deviceSessionId,bindingId:n.bindingId,bindingRevision:n.bindingRevision},l=new Cy(e,t,a.sessionKey,c,s);return l.start(),{close:(e="normal")=>l.close(e)}}(s,(await xy(s,e=>"attached"===e?.type)).channelId,i,this.options.identity,this.options.bridge)}}class Cy{receiveSequence=1;sendSequence=1;receiveCounter=0;sendCounter=0;unsubscribe;ttys=new Map;socket;channelId;key;actor;bridge;constructor(e,t,n,i,s){this.socket=e,this.channelId=t,this.key=n,this.actor=i,this.bridge=s}start(){this.socket.on("message",e=>{this.receive(e).catch(()=>this.socket.close(4400,"encrypted-protocol-error"))}),this.socket.once("close",()=>{this.unsubscribe?.();for(const e of this.ttys.values())e.close();this.ttys.clear()})}async close(e){this.unsubscribe?.();for(const e of this.ttys.values())e.close();this.ttys.clear(),this.socket.readyState<l.CLOSING&&this.socket.close(1e3,e.slice(0,120))}async receive(e){const t=JSON.parse(e.toString()),n=t?.frame;if("frame"!==t?.type||n?.channelId!==this.channelId||n.sequence!==this.receiveSequence++)throw Oy("RELAY_FRAME_SEQUENCE_INVALID");const i=w.secretbox.open(Buffer.from(n.ciphertext,"base64url"),Ny(1,this.receiveCounter++),this.key);if(!i)throw Oy("RELAY_E2E_DECRYPT_FAILED");const s=JSON.parse(Buffer.from(i).toString("utf8"));await this.dispatch(s)}async dispatch(e){if("request"===e.type&&e.id){try{const t=await this.bridge.request(this.actor,e.body);this.send({type:"response",id:e.id,status:t.status,body:t.body})}catch(t){this.send({type:"response",id:e.id,status:Number(t?.statusCode)||500,body:{error:{code:t?.code??"CONTROL_PLANE_ERROR",message:"Control Plane request failed."}}})}return}if("event-subscribe"===e.type){this.unsubscribe?.();const t=Array.isArray(e.body?.topics)?e.body.topics.map(String):["*"];return void(this.unsubscribe=this.bridge.subscribe(this.actor,t,e=>this.send({type:"event",event:e})))}if("tty-open"===e.type&&e.streamId&&this.bridge.openTty){const t=e.streamId,n=await this.bridge.openTty(this.actor,e.body,e=>this.send({...e,streamId:t}));return this.ttys.set(t,n),void this.send({type:"tty-opened",streamId:t})}const t=e.streamId?this.ttys.get(e.streamId):void 0;if(t&&"tty-input"===e.type)return t.send(String(e.data??""));if(t&&"tty-resize"===e.type)return t.resize(Number(e.body?.cols),Number(e.body?.rows));if(t&&"tty-close"===e.type)return t.close(),this.ttys.delete(e.streamId),void this.send({type:"tty-closed",streamId:e.streamId});if("cancel"!==e.type)throw Oy("RELAY_ENVELOPE_UNSUPPORTED")}send(e){if(this.socket.readyState!==l.OPEN||this.socket.bufferedAmount>2097152)throw Oy("RELAY_BACKPRESSURE_LIMIT");const t=w.secretbox(Buffer.from(JSON.stringify(e)),Ny(2,this.sendCounter++),this.key);this.socket.send(JSON.stringify({type:"frame",frame:{protocolVersion:"2026-08-10",channelId:this.channelId,sequence:this.sendSequence++,kind:"cancel"===e.type?"cancel":"data",ciphertext:Buffer.from(t).toString("base64url")}}))}}function xy(e,t){return new Promise((n,i)=>{const s=e=>{try{const i=JSON.parse(e.toString());t(i)&&(o(),n(i))}catch(e){o(),i(e)}},r=()=>{o(),i(Oy("RELAY_SOCKET_CLOSED"))},o=()=>{e.off("message",s),e.off("close",r)};e.on("message",s),e.once("close",r)})}function Ny(e,t){const n=new Uint8Array(24);return n[0]=e,new DataView(n.buffer).setBigUint64(16,BigInt(t),!1),n}function Oy(e){return Object.assign(new Error("Cloud Relay session is invalid."),{code:e,retryable:!0})}class _y{current;options;constructor(e){this.options=e}async connect(e){const t=this.options.identity.publicIdentity(),n=Date.now(),s={protocolVersion:"2026-08-10",audience:"task-handoff:coordinator-control",connectionId:`connection_${i.randomUUID().replaceAll("-","_")}`,processInstanceId:e.processInstanceId,controlPlaneId:t.controlPlaneId,publicKey:t.publicKey,publicKeyFingerprint:t.fingerprint,...e.bindingId?{bindingId:e.bindingId,bindingRevision:e.bindingRevision}:{},epoch:e.epoch,capabilities:["request","stream","websocket"],issuedAt:new Date(n).toISOString(),expiresAt:new Date(n+3e5).toISOString()},r=new URL("/api/v1/control-plane/connect",e.serviceOrigin);r.protocol="https:"===r.protocol?"wss:":"ws:";const o=new(this.options.webSocket??l)(r.href,{followRedirects:!1,handshakeTimeout:1e4});let a;return a=await function(e,t){return new Promise((n,s)=>{const r=new Map;let o,a=!1,d=!1;const c=e=>{for(const t of r.values())t.reject(e);r.clear(),a||s(e)},p={request(t,n){if(e.readyState!==l.OPEN)return Promise.reject(Py("CLOUD_CONTROL_CONNECTION_UNAVAILABLE"));const s=`request_${i.randomUUID().replaceAll("-","_")}`;return e.send(JSON.stringify({type:"request",requestId:s,operation:t,payload:n})),new Promise((e,t)=>r.set(s,{resolve:e,reject:t}))},async close(t="normal"){d=!0,o&&clearInterval(o),e.close(1e3,t.slice(0,120))}};e.on("open",()=>e.send(JSON.stringify(t.register))),e.on("message",async i=>{let s;try{s=JSON.parse(i.toString())}catch{return e.close(1002,"invalid-json")}if("registered"===s.type)return a=!0,o=setInterval(()=>e.readyState===l.OPEN&&e.send(JSON.stringify({type:"heartbeat"})),1e4),o.unref(),n(p);if("event"===s.type)return t.onEvent(s.event);if("response"===s.type){const e=r.get(s.requestId);if(!e)return;return r.delete(s.requestId),s.error?e.reject(Object.assign(new Error(s.error.message),{code:s.error.code})):e.resolve(s.data)}if("request"===s.type&&t.onRequest)try{e.send(JSON.stringify({type:"response",requestId:s.requestId,data:await t.onRequest(s.operation,s.payload)}))}catch(t){e.send(JSON.stringify({type:"response",requestId:s.requestId,error:{code:t?.code??"REQUEST_FAILED",message:t instanceof Error?t.message:String(t)}}))}}),e.on("error",e=>c(e)),e.on("close",()=>{o&&clearInterval(o),c(Py("CLOUD_CONTROL_CONNECTION_CLOSED")),d||t.onDisconnected()})})}(o,{register:{type:"register",registration:{...s,signature:this.options.identity.signCloudOutboundRegistration(s)},backgroundCredential:e.credential},onEvent:e.onEvent,onRequest:this.options.onRequest,onDisconnected:()=>{this.current===a&&(this.current=void 0),this.options.onDisconnected()}}),this.current=a,a}async request(e,t){if(!this.current)throw Py("CLOUD_CONTROL_CONNECTION_UNAVAILABLE");return this.current.request(e,t)}}class Ry{lifecycle;dataConnections;connector;control;events;timer;running=!1;connecting;options;constructor(e){this.options=e,this.connector=new _y({identity:e.identity,webSocket:e.webSocket,onDisconnected:()=>{this.control.disconnected(),this.schedule()},onRequest:(e,t)=>this.handleRequest(e,t)});const t=e.relayConnector??(e.relayBridge?new Ey({identity:e.identity,bridge:e.relayBridge,webSocket:e.webSocket}):{async connect(){throw Py("CLOUD_RELAY_CONNECTOR_UNAVAILABLE")}});this.dataConnections=new zy({verifyAllocation:e.verifyAllocation??(t=>function(e,t){const n=e,i=ln.parse(n?.attach),s=dn.parse(n?.ticket),r=t.snapshot(),o=new URL(String(n?.relayUrl));if("relay-allocation"!==n?.type||n?.allocationId!==i.allocationId||"control-plane"!==i.role||i.ticketId!==s.ticketId||i.controlPlaneId!==s.controlPlaneId||i.accountId!==s.accountId||i.deviceSessionId!==s.deviceSessionId||i.bindingId!==s.bindingId||i.bindingRevision!==s.bindingRevision||"active"!==r.status||!r.remoteAccessEnabled||r.identity.controlPlaneId!==s.controlPlaneId||r.accountId!==s.accountId||r.bindingId!==s.bindingId||r.bindingRevision!==s.bindingRevision||s.targetPublicKeyFingerprint!==r.identity.fingerprint||Date.parse(i.expiresAt)<=Date.now())throw Oy("RELAY_ALLOCATION_AUTHORITY_INVALID");if(!function(e,t){if("wss:"!==e.protocol)return!1;if("relay.thandoff.com"===e.hostname||e.hostname.endsWith(".relay.thandoff.com"))return!0;const n=new URL(t);return"cloud.thandoff.com"!==n.hostname&&e.hostname===n.hostname}(o,r.serviceOrigin))throw Oy("UNTRUSTED_RELAY_URL");return{allocationId:i.allocationId,relayUrl:o.href,epoch:Date.parse(i.issuedAt),attach:i,ticket:s}}(t,e.state)),connector:t}),this.events=new Sy({state:e.state,connections:{stop:e=>this.control.stop(e)},dataConnections:this.dataConnections}),this.control=new ky({state:e.state,connector:this.connector,onEvent:async e=>{await this.events.apply(e)}}),this.lifecycle=new Ty({state:e.state,connections:this.control,remote:{revoke:async({bindingId:e})=>this.connector.request("revoke-binding",{bindingId:e}),setRemoteAccess:async({bindingId:e,enabled:t})=>{await this.connector.request("set-remote-access",{bindingId:e,enabled:t})}}})}start(){this.running=!0,"active"===this.options.state.snapshot().status&&this.schedule(0)}async stop(){this.running=!1,this.timer&&clearTimeout(this.timer),await Promise.all([this.control.stop("control-plane-stopping"),this.dataConnections.closeAll("control-plane-stopping")])}async publishBindingChallenge(e){await this.ensureConnected(),await this.connector.request("publish-binding-challenge",{payload:e.payload,signature:e.signature})}async request(e,t){return await this.ensureConnected(),this.connector.request(e,t)}async handleRequest(e,t){if("consume-binding-challenge"===e){const e=this.options.identity.publicIdentity();return this.options.state.consumeChallenge({challengeCode:t?.challengeCode,controlPlaneId:e.controlPlaneId,fingerprint:e.fingerprint})}if("deliver-binding-credential"===e)return this.options.state.activate(t);if("relay-allocation"===e)return this.dataConnections.attach(t);throw Py("CLOUD_CONTROL_OPERATION_UNSUPPORTED")}async ensureConnected(){if(this.connecting||(this.connecting=this.control.connectOnce().finally(()=>{this.connecting=void 0})),"connected"!==(await this.connecting).status)throw Py("CLOUD_CONTROL_CONNECTION_DISABLED")}schedule(e=this.control.reconnectDelay()){if(!this.running||this.timer)return;const t=this.options.state.snapshot();"active"===t.status&&t.remoteAccessEnabled&&(this.timer=setTimeout(()=>{this.timer=void 0,this.ensureConnected().catch(()=>this.schedule())},e),this.timer.unref())}}function Py(e){return Object.assign(new Error("Cloud background connection is unavailable."),{code:e,retryable:!0})}const jy="x-task-handoff-cloud-internal-actor",Dy=a.z.object({code:a.z.string().trim().min(1),message:a.z.string(),details:a.z.record(a.z.string(),a.z.unknown()).optional(),retryable:a.z.boolean().optional()}).strict(),My=a.z.object({error:Dy}).strict(),Ly="https://cloud.thandoff.com";function qy(e,t={}){const n=new URL(e||Ly).origin;if(n===Ly)return n;if(t.production||!0!==t.allowNonProduction)throw Object.assign(new Error("Non-production cloud service origin is not trusted by this build."),{code:"UNTRUSTED_CLOUD_SERVICE_ORIGIN"});return n}function $y(e){const t=process.env[e]?.trim();return t||void 0}const By=function(e,t=process.env,n=e){let i;return()=>{const s=t.TASK_HANDOFF_VERSION?.trim();return s||(i||=T(e,t,n),i)}}("@task-handoff/control-plane");function Uy(){return{component:"control-plane",packageName:"@task-handoff/control-plane",packageVersion:By(),protocolVersion:ui,buildId:$y("TASK_HANDOFF_BUILD_ID"),builtAt:$y("TASK_HANDOFF_BUILT_AT"),gitCommit:$y("TASK_HANDOFF_GIT_COMMIT"),imageRef:$y("TASK_HANDOFF_IMAGE_REF"),imageDigest:$y("TASK_HANDOFF_IMAGE_DIGEST")}}const Fy={".css":"text/css; charset=utf-8",".html":"text/html; charset=utf-8",".ico":"image/x-icon",".js":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".map":"application/json; charset=utf-8",".png":"image/png",".svg":"image/svg+xml",".webp":"image/webp"};function Hy(e,i){const s=t.resolve(e),r=t.resolve(s,i);if(r===s||r.startsWith(`${s}${t.sep}`))return n.existsSync(r)&&n.statSync(r).isFile()?r:void 0}function Wy(e,i,s){const r=Hy(i,s);return r?(e.header("cache-control","no-store"),e.type(Fy[t.extname(r).toLowerCase()]||"application/octet-stream"),e.send(n.createReadStream(r))):e.code(404).send({error:{code:"STATIC_FILE_NOT_FOUND",message:`${s} was not found in the Control Plane UI static directory.`}})}function Gy(e){if(e instanceof a.z.ZodError)return{statusCode:400,code:"VALIDATION_ERROR",message:e.issues.map(e=>`${e.path.join(".")||"body"}: ${e.message}`).join("; ")};const t=e&&"object"==typeof e?e:{};return{statusCode:"number"==typeof t.statusCode?t.statusCode:500,code:"string"==typeof t.code?t.code:"CONTROL_PLANE_ERROR",message:e instanceof Error?e.message:String(e),...t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?{details:t.details}:{},..."boolean"==typeof t.retryable?{retryable:t.retryable}:{},..."number"==typeof t.retryAfterSeconds?{retryAfterSeconds:t.retryAfterSeconds}:{}}}function Vy(e){const t=e.headers.authorization;if(void 0!==t){const e=/^Bearer ([^\s]+)$/.exec(t);return{token:e?.[1],clientType:"mobile"}}return{token:e.cookies[vo],clientType:"web"}}async function Ky(e,t){if(!e.enabled())return{type:"system",reason:"auth-disabled"};const n="mobile"===t.clientType?await e.userForMobileSessionToken(t.token):await e.userForSessionToken(t.token);return n?{type:"user",userId:n.id,role:n.role}:void 0}const Jy=new Set(["/api/auth/session","/api/auth/bootstrap-admin","/api/auth/login","/api/auth/logout","/api/auth/mobile/login","/api/control-plane/identity","/api/health","/api/events"]);function Yy(e,t){const n=t.split("?")[0]||"/";if(!n.startsWith("/api/"))return;if(Jy.has(n))return;const i=function(e){return"GET"===e||"HEAD"===e?"read":"POST"===e?"create":"PATCH"===e||"PUT"===e?"update":"DELETE"===e?"delete":"read"}(e);return"/api/control-plane/diagnostic-logs/export"===n?{action:"manage-settings",resource:{type:"control-plane-settings"}}:n.startsWith("/api/control-plane/settings")?{action:"GET"===e?"read":"manage-settings",resource:{type:"control-plane-settings"}}:"/api/auth/mobile/logout"===n||n.startsWith("/api/auth/mobile/sessions")||"/api/auth/password"===n?void 0:n.startsWith("/api/models")?{action:"GET"===e?"read":"manage-secrets",resource:{type:"model"}}:n.startsWith("/api/chat-gateway/bridges")?{action:"GET"===e?"read":"manage-secrets",resource:{type:"chat-bridge"}}:"/api/chat-gateway/messages"===n||"/api/chat-gateway/actions"===n?{action:"send-message",resource:{type:"ai-session"}}:"/api/chat-gateway/poll-ai-sessions"===n?{action:"manage-settings",resource:{type:"chat-bridge"}}:"/api/ai-session-attachments"===n?{action:"send-message",resource:{type:"ai-session"}}:"/api/node-join/invites"===n?{action:"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/control-plane-proxy")?{action:"GET"===e?"read":"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/nodes")?/\/(runtimes|local-folders)(\/|$)/.test(n)?{action:i,resource:{type:"runtime"}}:{action:"GET"===e?"read":"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/controlled-instances")?/\/apps\/sessions\/[^/]+\/access$/.test(n)?{action:"read",resource:{type:"instance"}}:n.includes("/ai-sessions")?n.includes("/triggers")?{action:i,resource:{type:"trigger"}}:"POST"===e&&/\/ai-sessions$/.test(n)?{action:"send-message",resource:{type:"ai-session"}}:n.endsWith("/approval")?{action:"approve",resource:{type:"ai-session"}}:n.endsWith("/interrupt")?{action:"interrupt",resource:{type:"ai-session"}}:n.endsWith("/resume")||n.endsWith("/fork")||n.endsWith("/commands")||n.includes("/messages")||n.includes("/queue/")?{action:"send-message",resource:{type:"ai-session"}}:n.endsWith("/read")||n.endsWith("/mentions/files")?{action:"read",resource:{type:"ai-session"}}:{action:i,resource:{type:"ai-session"}}:n.includes("/start")?{action:"start",resource:{type:"instance"}}:n.includes("/stop")?{action:"stop",resource:{type:"instance"}}:n.includes("/restart")?{action:"restart",resource:{type:"instance"}}:/\/config-sync(?:\/|$)/.test(n)?{action:"update",resource:{type:"instance"}}:{action:i,resource:{type:"instance"}}:n.startsWith("/api/projects")?{action:i,resource:{type:"project"}}:n.startsWith("/api/images")||n.startsWith("/api/image-options")||n.startsWith("/api/market")?{action:i,resource:{type:"runtime"}}:n.startsWith("/api/triggers")?{action:i,resource:{type:"trigger"}}:{action:i,resource:{type:"control-plane-settings"}}}async function Qy(e={}){const d=Um(e.dataDir),c=s({logger:e.logger??!0}),l=new mm,p=e.cloudConnectivityEnabled??"0"!==process.env.TASK_HANDOFF_CLOUD_CONNECTIVITY_ENABLED;let u=(g=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(g||"").trim().toLowerCase()));var g;const h=function(e,i,s,r={}){const o=(o,a,d)=>{if(i()){s[o]?.(a,d);try{!function(e,i,s=10485760,r=2){const o=Buffer.isBuffer(i)?i:Buffer.from(i),a=o.byteLength>s?o.subarray(o.byteLength-s):o;if(n.mkdirSync(t.dirname(e),{recursive:!0,mode:448}),n.existsSync(e)){const t=n.lstatSync(e);if(!t.isFile()||t.isSymbolicLink())throw new Error(`Managed log path must be a regular file: ${e}`);t.size+a.byteLength>s&&(function(e,t){if(!(t<=0)){n.rmSync(uy(e,t),{force:!0});for(let i=t-1;i>=1;i-=1){const t=uy(e,i);n.existsSync(t)&&n.renameSync(t,uy(e,i+1))}}}(e,r),r>0?t.size>s?(n.writeFileSync(uy(e,1),function(e,t){const i=n.statSync(e),s=Math.min(i.size,t),r=Buffer.allocUnsafe(s),o=n.openSync(e,"r");let a=0;try{for(;a<s;){const e=n.readSync(o,r,a,s-a,i.size-s+a);if(0===e)break;a+=e}}finally{n.closeSync(o)}return a===s?r:r.subarray(0,a)}(e,s),{mode:384}),n.rmSync(e,{force:!0})):n.renameSync(e,uy(e,1)):n.rmSync(e,{force:!0}))}n.appendFileSync(e,a,{mode:384}),n.chmodSync(e,384)}(t.join(e,"control-plane.log"),`${JSON.stringify({time:(new Date).toISOString(),level:o,message:d,data:hy(a)},(e,t)=>hy(t))}\n`,r.maxBytes??10485760,r.backupCount??2)}catch{}}};return{info:(e,t)=>o("info",e,t),warn:(e,t)=>o("warn",e,t),error:(e,t)=>o("error",e,t)}}(d.logsDir,()=>u,c.log),f=new py;f.onChange(e=>l.publish("node.connection.updated",e,{topic:"node.state",scope:{nodeId:e.nodeId}}));const I=new dp(d,{...e.service,logger:h,nodeConnectionRuntime:f}),b=new $o(d,e.auth),v=new ly(d.identitySigningPath,()=>I.proxyPrivateStore.controlPlaneId(),(e,t)=>c.log.warn(t,e)),w=new by({statePath:d.cloudConnectivityPath,identity:v,serviceOrigin:qy(e.cloudServiceOrigin||process.env.TASK_HANDOFF_CLOUD_SERVICE_ORIGIN,{production:"production"===process.env.NODE_ENV,allowNonProduction:!0===e.allowNonProductionCloudOrigin||"staging"===process.env.TASK_HANDOFF_CLOUD_ENV})}),S=new Map,k=new Ry({state:w,identity:v,relayBridge:{async request(e,t){const n=String(t?.method||"GET").toUpperCase(),s=String(t?.path||""),r=Yy(n,s);if(!s.startsWith("/api/")||!r||Jy.has(s.split("?")[0]))throw Object.assign(new Error("Cloud access route is not available."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});lg(e,r.action,r.resource);const o=i.randomBytes(32).toString("base64url");S.set(o,e);try{const e=Object.fromEntries(Object.entries(t.headers??{}).filter(([e])=>!["authorization","cookie","host","connection","upgrade",jy].includes(e.toLowerCase())).map(([e,t])=>[e,String(t)])),i=await c.inject({method:n,url:s,headers:{...e,[jy]:o},...void 0===t.body?{}:{payload:t.body}});let r;try{r=i.json()}catch{r=i.body}return{status:i.statusCode,body:r}}finally{S.delete(o)}},subscribe(e,t,n){if("cloud-account"!==e.type)throw Object.assign(new Error("Cloud account actor required."),{code:"CLOUD_ACTOR_REQUIRED"});const i=new Set(t.length?t:["*"]);return l.on(e=>{(i.has("*")||i.has(e.topic)||i.has(e.type))&&n(e)})},async openTty(e,t,n){const i=String(t?.instanceId||""),s=String(t?.sessionId||"");if(lg(e,"proxy",{type:"instance",id:i}),!i||!s)throw Object.assign(new Error("TTY target is required."),{code:"TTY_TARGET_REQUIRED",statusCode:400});const r=new Map,o=(e,...t)=>{for(const n of r.get(e)??[])n(...t)};let a=!1;const d={readyState:1,on(e,t){const n=r.get(e)??new Set;n.add(t),r.set(e,n)},send(e){try{const t=JSON.parse(String(e));if("snapshot"===t.type){const e=gt.parse(t);n(on.parse({type:"tty-snapshot",data:e.data,pendingEscape:e.pendingEscape,cols:e.cols,rows:e.rows}))}else"output"===t.type?n({type:"tty-output",data:t.data}):"resize"===t.type?n({type:"tty-resize",body:{cols:t.cols,rows:t.rows}}):"exit"===t.type?n({type:"tty-exit",code:t.code,signal:t.signal}):"error"===t.type&&n({type:"tty-error"})}catch{n({type:"tty-error"})}},close(){a||(a=!0,o("close"),n({type:"tty-closed"}))}};return await I.proxyInstanceWebSocket(i,d,`/api/apps/sessions/${encodeURIComponent(s)}/tty`,[],{}),{send(e){a||o("message",Buffer.from(JSON.stringify({type:"input",data:e})))},resize(e,t){!a&&Number.isInteger(e)&&Number.isInteger(t)&&e>0&&t>0&&o("message",Buffer.from(JSON.stringify({type:"resize",cols:e,rows:t})))},close(){d.close()}}}}}),z=e.cloudConnectivityLifecycle?.(w)??k.lifecycle,T=e.publishCloudBindingChallenge??(e=>k.publishBindingChallenge(e)),E=new uh(l),C=new oh(d,{onChanged:e=>queueMicrotask(()=>l.publish(j,e,{topic:"ai.sessions",scope:{instanceId:e.instanceId,sessionId:e.sessionId}}))});C.init();const x=new sh({bootstrap:()=>I.bootstrapAiSessionsFromInstances(),logger:h,recoverDelta:(e,t,n)=>I.recoverAiSessionDelta(e,t,n),recoverSnapshot:e=>I.recoverAiSessionSnapshot(e),onRecoveredEvent:e=>l.publish(e.type,e.payload)});x.onSnapshot(e=>C.reconcile(e.instanceId,e.aiSessions));const N=new lh({bootstrap:()=>I.bootstrapAppSessionsFromInstances(),logger:h,recoverDelta:(e,t,n)=>I.recoverAppSessionDelta(e,t,n),recoverSnapshot:e=>I.recoverAppSessionSnapshot(e),onRecoveredEvent:e=>l.publish(e.type,e.payload)});I.setAppSessionSnapshotProvider(e=>N.list(e)),I.setAiSessionSnapshotProvider(e=>x.list(e)),l.on(e=>{if(E.handle(e),"instance.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";t&&(N.removeInstance(t),x.removeInstance(t),C.removeInstance(t))}});const O=new bm;c.addHook("onClose",async()=>{O.dispose()});const _=new $m(l,{connectionRuntime:f,validateInstanceScope:(e,t)=>I.nodeOwnsInstance(e,t),onStreamsHello:(e,t)=>{for(const n of t.streams)"ai.sessions"===n.topic&&x.advertiseStream(e,n),"app.sessions"===n.topic&&N.advertiseStream(e,n)},onSessionEvent:e=>e.type.startsWith("app-session.")?N.handleEvent(e):x.handleEvent(e)}),R=e.proxyOrigin||process.env.TASK_HANDOFF_CONTROL_PLANE_PROXY_ORIGIN,P=e=>{const t=I.nodes.get(e);return t?function(e,t){const n="reverse-wss"===e.connectionMode&&t,i=n?"online":e.status;return{id:e.id,name:e.name||e.id,status:i,health:e.health,...e.lastSeenAt?{lastSeenAt:e.lastSeenAt}:{},capabilities:Mh(e.capabilities||{},262144),manageable:!1!==e.connectionEnabled&&(n||"online"===i)}}(t,_.connected(t.id)):void 0},D=new xh(new Ah(d.proxyAuthorityPath,(e,t)=>c.log.warn(t,e)),{get:P},{proxyOrigin:R,proxyOriginProvider:()=>I.getSettings().publicBaseUrl}),M=new Oh,L=new Rh(l,{projectTarget:e=>{const t=P(e);return t?qh(t):void 0}}),q=new ny(I,{fetchImpl:e.service?.fetchImpl,logger:h,onStateChanged:e=>l.publish("node.proxy-state.updated",{nodeId:e.id,proxyState:e.proxyState},{topic:"node.state",scope:{nodeId:e.id}})});let $,B,U;l.on(e=>{if("node.created"!==e.type&&"node.updated"!==e.type&&"node.deleted"!==e.type||q.syncNow(),"instance.created"===e.type||"instance.updated"===e.type||"instance.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";t&&_.invalidateInstanceScope({instanceId:t})}if("node.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"nodeId"in e.payload?String(e.payload.nodeId||""):"";if(t){_.invalidateInstanceScope({nodeId:t});const e=D.revokeTarget(t);for(const n of e.bindings)M.closeBinding(n.id,"Proxy target was deleted."),l.publish("control-plane-proxy.binding.updated",{binding:n},{topic:"control-plane-proxy",scope:{nodeId:t}})}}}),I.setNodeAgentTransport(_),I.init(),u=I.diagnosticLogsEnabled(),v.init(),w.init(),p&&k.start();const F=()=>{if($)return $;const e=I.recoverPendingPairingRevokes().then(()=>{});return $=e,e.then(()=>{$===e&&($=void 0)},()=>{$===e&&($=void 0)}),e};await F().catch(e=>c.log.warn({error:e},"pending node pairing recovery failed")),D.init(),q.start(),await I.syncLocalNodeConnection().catch(()=>{}),b.init();const H=new Du(I,e.service?.fetchImpl,{aiSessions:x,logger:h,diagnosticLogsEnabled:()=>u});H.startEnabled();const W=new Bm(I,_,{safetyIntervalMs:Number(process.env.TASK_HANDOFF_EVENT_CONNECTION_SAFETY_INTERVAL_MS)||void 0,logger:h,connectionRuntime:f});W.start(),await c.register(r),await c.register(o),c.addHook("onClose",async()=>{await k.stop(),B&&clearInterval(B),U&&clearInterval(U),await($?.catch(()=>{})),E.close(),L.stop(),q.stop(),W.stop(),H.stopAll()}),c.setErrorHandler((e,t,n)=>{const i=Gy(e);void 0!==i.retryAfterSeconds&&n.header("retry-after",String(i.retryAfterSeconds)),(u||i.statusCode>=500)&&(i.statusCode>=500?c.log.error.bind(c.log):c.log.warn.bind(c.log))({method:t.method,url:t.url,statusCode:i.statusCode,errorCode:i.code,error:i.message},"control plane request failed"),n.code(i.statusCode).send(My.parse({error:{code:i.code,message:i.message,...i.details?{details:i.details}:{},...void 0!==i.retryable?{retryable:i.retryable}:{}}}))}),c.addHook("preHandler",async(e,t)=>{const n=e.routeOptions.url,i=n&&"*"!==n?n:e.url,s=e.routeOptions.config.controlPlaneAuthBoundary,r=e.headers[jy],o="string"==typeof r?S.get(r):void 0;if(o){S.delete(r);const t=Yy(e.method,i);if(!t)throw Object.assign(new Error("Cloud access route is not authorized."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});return void lg(o,t.action,t.resource)}if("proxy-binding"===s||"node-tunnel"===s)return;const a="public"===s||"public-ui"===s&&function(e){const t=e.split("?")[0]||"/";return!t.startsWith("/api/")&&"/api"!==t&&!t.startsWith("/instances/")&&"/instances"!==t}(e.url);if(!b.enabled()||a){const t=await Ky(b,Vy(e)),n=Yy(e.method,i);return void(n&&lg(t||{type:"system",reason:"auth-disabled"},n.action,n.resource))}const d=await Ky(b,Vy(e));if(!d)return t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access the Control Plane."}});const c=Yy(e.method,i);c&&lg(d,c.action,c.resource)});const G=t.resolve(e.staticDir||process.env.TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR||t.resolve(process.cwd(),"packages","control-plane-ui","dist"));n.existsSync(G)&&(c.get("/assets/*",{config:vm},async(e,n)=>{const i=e.params["*"];return Wy(n,G,t.join("assets",i||""))}),c.get("/favicon.ico",{config:vm},async(e,t)=>Hy(G,"favicon.ico")?Wy(t,G,"favicon.ico"):t.code(204).send())),c.get("/api/health",{config:vm},async()=>fs.parse({data:{ok:!0,role:"control-plane",protocolVersion:ui,build:Uy(),dataDir:d.dataDir,serverTime:(new Date).toISOString()}})),c.get("/api/control-plane/identity",{config:vm},async()=>v.publicDocument(b.enabled()?"required":"disabled"));const V=async e=>{if(!p)throw Object.assign(new Error("Cloud connectivity is disabled by feature flag."),{code:"CLOUD_CONNECTIVITY_DISABLED",statusCode:503});lg(await Ky(b,Vy(e))||{type:"system",reason:"auth-disabled"},"manage-settings",{type:"control-plane-settings"})};return c.get("/api/cloud-connectivity",async e=>(await V(e),{data:w.snapshot()})),c.post("/api/cloud-connectivity/challenges",async(e,t)=>{await V(e),t.header("cache-control","no-store");const n=w.createChallenge();return await T(n),{data:n}}),c.post("/api/cloud-connectivity/remote-access",async e=>{await V(e);const t=a.z.object({enabled:a.z.boolean()}).strict().parse(e.body);return{data:z?await z.setRemoteAccess(t.enabled):w.setRemoteAccess(t.enabled)}}),c.post("/api/cloud-connectivity/disconnect",async e=>(await V(e),{data:z?await z.disconnect():w.beginRevocation()})),c.get("/api/session-streams/diagnostics",async()=>({data:{aiSessions:x.diagnostics(),aiSessionActions:I.aiSessionActionDiagnostics(),appSessions:N.diagnostics(),nodeConnections:{...W.diagnostics(),runtime:f.diagnostics()}}})),c.get("/install-node-agent.sh",{config:vm},async(e,t)=>(t.header("cache-control","no-store"),t.type("text/x-shellscript; charset=utf-8"),ph`#!/bin/sh
|
|
1
|
+
"use strict";var e=require("commander"),t=require("node:path"),n=require("node:fs"),s=require("node:crypto"),i=require("fastify"),r=require("@fastify/compress"),o=require("@fastify/cookie"),a=require("@fastify/websocket"),d=require("zod"),c=require("node:util"),l=require("write-file-atomic"),p=require("ws"),u=require("node:http"),h=require("node:net"),m=require("node:stream"),g=require("telegramify-markdown"),y=require("node:fs/promises"),f=require("node:os"),I=require("dingtalk-stream"),b=require("@larksuiteoapi/node-sdk"),v=require("node:child_process"),S=require("tar"),w=require("tweetnacl");function A(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(n){if("default"!==n){var s=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,s.get?s:{enumerable:!0,get:function(){return e[n]}})}}),t.default=e,Object.freeze(t)}var z=A(S);function k(e,t){try{const s=JSON.parse(n.readFileSync(e,"utf8"));if(t&&s.name!==t)return;return"string"==typeof s.version&&s.version.trim()?s.version.trim():void 0}catch{return}}function T(e){if(e)try{return t.dirname(n.realpathSync(e))}catch{return}}function C(e,n=process.env,s=e){const i=n.TASK_HANDOFF_VERSION?.trim();if(i)return i;const r=s.split("/").at(-1),o=process.argv[1]?t.resolve(process.argv[1]):void 0,a=o?t.dirname(o):void 0,d=[T(o),a,process.cwd()].filter(e=>Boolean(e));for(const n of new Set(d)){let s=n;for(;;){const n=k(t.join(s,"package.json"),e);if(n)return n;const i=t.dirname(s);if(i===s)break;s=i}}let c;for(const e of new Set(d)){let n=e;for(;;){if(r){const e=k(t.join(n,"packages",r,"package.json"),s);if(e)return e}c||=k(t.join(n,"package.json"));const e=t.dirname(n);if(e===n)break;n=e}}return c||"unknown"}const E=new Set(["authorization","cookie"]),x=20971520,N=512e3,R=41943040,O=262144,_="ai.sessions",P="ai-session.snapshot",j="ai-session.patch",D="ai-session.removed",M="ai-session.message-delta",L="ai-session.timeline-item",q="ai-session.unread.updated",$=d.z.string().trim().min(1).max(80),B=d.z.enum(["app-session","ai-session"]),F=d.z.enum(["image","file"]),U={scopeType:d.z.enum(["session","create-request"]),scopeId:d.z.string().trim().min(1).max(160),kind:F,name:d.z.string().trim().min(1).max(240),mime:d.z.string().trim().min(1).max(120)},H=d.z.object({...U,size:d.z.coerce.number().int().positive().max(x)}).strict(),W=d.z.string().regex(/^cia_[a-f0-9]{24}$/),G=d.z.object({attachmentId:W,...U,size:d.z.number().int().positive().max(x)}).strict();d.z.object({offset:d.z.coerce.number().int().nonnegative()}).strict();const V=d.z.object({attachmentId:W,offset:d.z.number().int().nonnegative()}),K=d.z.object({id:W,kind:F,name:d.z.string().trim().min(1).max(240),mime:d.z.string().trim().min(1).max(120),size:d.z.number().int().positive().max(x),expiresAt:d.z.string().datetime()});function J(e){return["image/bmp","image/gif","image/jpeg","image/png","image/webp"].includes(e.split(";",1)[0].trim().toLowerCase())}const Y=d.z.object({id:d.z.string().trim().min(1).max(120),kind:F,name:d.z.string().trim().min(1).max(240),mime:d.z.string().trim().min(1).max(120),size:d.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER)}),Q=d.z.enum(["available","expired","missing"]),X=Y.extend({contentState:Q.default("available")}).strict(),Z=d.z.object({id:d.z.string().trim().min(1).max(240),text:d.z.string(),attachments:d.z.array(X).max(6).default([])}).strict(),ee=d.z.enum(["running","waiting","idle","failed"]),te=d.z.object({instanceId:d.z.string().trim().min(1).max(160),sessionId:d.z.string().trim().min(1).max(120),unread:d.z.boolean(),sessionUpdatedAt:d.z.string().datetime(),updatedAt:d.z.string().datetime()}).strict(),ne=d.z.enum(["thinking","tool","editing","approval","responding","unknown"]),se=d.z.object({id:d.z.string().trim().min(1).max(240).optional(),kind:d.z.string().trim().min(1).max(80).optional(),name:d.z.string().trim().min(1).max(120),inputPreview:d.z.string().trim().max(500).optional(),startedAt:d.z.string().datetime().optional()}).strict(),ie=d.z.enum(["running","completed","failed","waiting"]),re=d.z.object({id:d.z.string().trim().min(1).max(240),turnId:d.z.string().trim().min(1).max(240)}).strict(),oe=re.extend({type:d.z.literal("user-message"),text:d.z.string(),attachments:d.z.array(X).max(6).optional()}).strict(),ae=re.extend({type:d.z.literal("ai-message"),text:d.z.string()}).strict(),de=re.extend({type:d.z.literal("activity"),activityKind:d.z.string().trim().min(1).max(120),title:d.z.string().trim().min(1).max(240),status:ie.optional(),summary:d.z.string().max(4e3).optional(),input:d.z.string().max(1e5).optional(),output:d.z.string().max(1e6).optional(),paths:d.z.array(d.z.string().trim().min(1).max(4096)).max(500).optional(),exitCode:d.z.number().int().optional(),durationMs:d.z.number().int().nonnegative().optional()}).strict(),ce=d.z.discriminatedUnion("type",[oe,ae,de]),le=d.z.object({sessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),items:d.z.array(ce),generatedAt:d.z.string().datetime()}).strict(),pe=d.z.object({sessionId:d.z.string().trim().min(1).max(120),turnId:d.z.string().trim().min(1).max(240),items:d.z.array(ce),generatedAt:d.z.string().datetime()}).strict(),ue=d.z.enum(["pending-init","running","interrupted","completed","errored","shutdown","not-found"]),he=d.z.enum(["started","interacted","interrupted"]),me=d.z.object({threadId:d.z.string().trim().min(1).max(240),path:d.z.string().trim().max(4096).optional(),status:ue,activity:he.optional(),message:d.z.string().trim().max(1e3).optional(),updatedAt:d.z.string().datetime()}).strict(),ge=d.z.object({toolCalls:d.z.number().int().min(0).default(0),edits:d.z.number().int().min(0).default(0),approvals:d.z.number().int().min(0).default(0)}).strict().default({toolCalls:0,edits:0,approvals:0}),ye=d.z.object({send:d.z.boolean().optional(),interrupt:d.z.boolean().optional(),approval:d.z.boolean().optional(),fork:d.z.boolean().optional(),openApp:d.z.boolean().optional(),close:d.z.boolean().optional()}).strict(),fe=d.z.object({kind:d.z.literal("fork"),parentProviderSessionId:d.z.string().trim().min(1).max(240),throughTurnId:d.z.string().trim().min(1).max(240).optional()}).strict(),Ie=d.z.union([Y.extend({source:d.z.object({type:d.z.literal("inline"),encoding:d.z.literal("base64"),data:d.z.string().min(1).max(31457280)}).strict()}).strict().superRefine((e,t)=>{const n="image"===e.kind?x:N;(e.size<=0||("file"===e.kind?e.size>=n:e.size>n))&&t.addIssue({code:d.z.ZodIssueCode.custom,path:["size"],message:`Inline ${e.kind} must be between 1 byte and ${n} bytes.`})}),Y.extend({source:d.z.object({type:d.z.literal("runtime-path"),path:d.z.string().trim().min(1).max(4096)}).strict()}).strict()]),be=Y.extend({sourceType:d.z.enum(["inline","runtime-path"])}).strict(),ve=d.z.union([d.z.object({id:d.z.string().trim().min(1).max(120),kind:F.optional(),source:d.z.object({type:d.z.literal("upload-ref")}).strict().default({type:"upload-ref"})}).strict(),d.z.object({id:d.z.string().trim().min(1).max(120),kind:F,name:d.z.string().trim().min(1).max(240),mime:d.z.string().trim().min(1).max(120),size:d.z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),source:d.z.object({type:d.z.literal("runtime-path"),path:d.z.string().trim().min(1).max(4096)}).strict()}).strict()]),Se=d.z.enum(["auto","queue","steer","immediate"]),we=d.z.enum(["ask","auto-review","full-access"]),Ae=d.z.enum(["review","rename","goal","compact"]),ze=d.z.object({command:Ae,argument:d.z.string().trim().max(4e3).optional()}).strict().superRefine((e,t)=>{"rename"!==e.command||e.argument||t.addIssue({code:"custom",path:["argument"],message:"Rename requires a thread name."}),"review"!==e.command&&"compact"!==e.command||!e.argument||t.addIssue({code:"custom",path:["argument"],message:`${e.command} does not accept an argument.`})}),ke=d.z.object({command:Ae,value:d.z.string().max(4e3).optional(),turnId:d.z.string().trim().min(1).max(240).optional()}).strict();d.z.enum(["skill","app","plugin"]);const Te=d.z.object({name:d.z.string().trim().min(1).max(240),path:d.z.string().trim().min(1).max(4096)}),Ce=d.z.discriminatedUnion("kind",[Te.extend({kind:d.z.literal("skill"),path:d.z.string().trim().min(1).max(4096).refine(e=>e.startsWith("/"),"Skill paths must be absolute.")}).strict(),Te.extend({kind:d.z.literal("app"),path:d.z.string().trim().min(7).max(4096).regex(/^app:\/\/[^\s/]+$/,"App paths must use app://<id>.")}).strict(),Te.extend({kind:d.z.literal("plugin"),path:d.z.string().trim().min(10).max(4096).regex(/^plugin:\/\/[^\s/]+$/,"Plugin paths must use plugin://<id>.")}).strict()]),Ee=d.z.array(Ce).max(20).default([]),xe=d.z.enum(["plugin","skill","file","directory","app"]),Ne=d.z.object({kind:xe,name:d.z.string().trim().min(1).max(240),description:d.z.string().trim().max(1e3).optional(),path:d.z.string().trim().min(1).max(4096),icon:d.z.string().trim().max(4096).optional()}).strict().superRefine((e,t)=>{"skill"!==e.kind||e.path.startsWith("/")||t.addIssue({code:"custom",path:["path"],message:"Skill paths must be absolute."}),"app"!==e.kind||/^app:\/\/[^\s/]+$/.test(e.path)||t.addIssue({code:"custom",path:["path"],message:"App paths must use app://<id>."}),"plugin"!==e.kind||/^plugin:\/\/[^\s/]+$/.test(e.path)||t.addIssue({code:"custom",path:["path"],message:"Plugin paths must use plugin://<id>."}),"file"!==e.kind&&"directory"!==e.kind||!e.path.startsWith("/")&&!e.path.split(/[\\/]+/).includes("..")||t.addIssue({code:"custom",path:["path"],message:"File and directory paths must be relative to the session cwd."})}),Re=d.z.object({category:d.z.enum(["skills","plugins","apps","files"]),code:d.z.string().trim().min(1).max(160),message:d.z.string().trim().min(1).max(2e3)}).strict(),Oe=d.z.object({sessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),cwd:d.z.string().trim().min(1).max(4096),candidates:d.z.array(Ne).max(1e3).default([]),diagnostics:d.z.array(Re).max(20).default([])}).strict(),_e=d.z.object({query:d.z.string().trim().max(240).default("")}).strict(),Pe=d.z.object({sessionId:d.z.string().trim().min(1).max(120),cwd:d.z.string().trim().min(1).max(4096),query:d.z.string().trim().max(240),requestId:d.z.string().trim().min(1).max(160),candidates:d.z.array(Ne.refine(e=>"file"===e.kind||"directory"===e.kind,"File search only returns files and directories.")).max(200).default([]),complete:d.z.boolean().default(!1)}).strict(),je=d.z.object({message:d.z.string().trim().min(1).max(2e4),mode:Se.optional(),permissionMode:we.optional()}),De=je.extend({attachments:d.z.array(Ie).max(6).default([]),references:Ee}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>R&&t.addIssue({code:d.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),Me=je.extend({attachments:d.z.array(ve).max(6).default([]),references:Ee}).strict(),Le=d.z.object({type:d.z.literal("runtime-path"),path:d.z.string().trim().min(1).max(4096).refine(e=>e.startsWith("/")||/^[A-Za-z]:[\\/]/.test(e),"Runtime paths must be absolute in the target controlled instance.")}).strict(),qe=De.extend({agent:$,cwd:Le,cwdFolderId:d.z.string().trim().min(1).max(120).optional(),clientRequestId:d.z.string().trim().min(1).max(160)}).strict(),$e=d.z.object({mode:d.z.enum(["current-folder","worktree"]),branch:d.z.string().trim().min(1).max(1024)}).strict(),Be=Me.extend({agent:$,cwdFolderId:d.z.string().trim().min(1).max(120).optional(),gitSelection:$e.optional(),clientRequestId:d.z.string().trim().min(1).max(160)}).strict(),Fe=d.z.object({disposition:d.z.enum(["created","already-created"]),aiSessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),creationSource:d.z.literal("ai-session")}).strict(),Ue=d.z.object({mode:d.z.enum(["current","managed-worktree"]).default("current")}).strict().default({mode:"current"}),He=d.z.object({clientRequestId:d.z.string().trim().min(1).max(160),throughTurnId:d.z.string().trim().min(1).max(240).optional(),workspace:Ue.optional().default({mode:"current"})}).strict(),We=d.z.object({disposition:d.z.enum(["created","already-created"]),aiSessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),creationSource:d.z.literal("ai-session")}).strict(),Ge=d.z.object({clientRequestId:d.z.string().trim().min(1).max(160)}).strict(),Ve=d.z.object({disposition:d.z.enum(["opened","already-open"]),aiSessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),appSessionId:d.z.string().trim().min(1).max(120),creationSource:B}).strict(),Ke=d.z.object({clientRequestId:d.z.string().trim().min(1).max(160)}).strict(),Je=d.z.object({disposition:d.z.enum(["closed","already-closed"]),aiSessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),creationSource:B}).strict();d.z.object({code:d.z.enum(["invalid-request","not-found","unsupported","provider-unavailable","materialization-failed","open-app-failed","close-failed","conflict"]),message:d.z.string().trim().min(1).max(4e3),retryable:d.z.boolean().default(!1),aiSessionId:d.z.string().trim().min(1).max(120).optional(),providerSessionId:d.z.string().trim().min(1).max(240).optional()}).strict();const Ye=d.z.object({decision:d.z.enum(["allow","deny","skip"])}).strict(),Qe=d.z.object({expectedRevision:d.z.number().int().min(0),queueIds:d.z.array(d.z.string().trim().min(1).max(120)).max(100)}).strict(),Xe=d.z.object({expectedRevision:d.z.number().int().min(0),message:d.z.string().trim().min(1).max(2e4)}).strict();d.z.object({code:d.z.string().trim().min(1).max(160),message:d.z.string(),instanceId:d.z.string().trim().min(1).max(160).optional(),nodeId:d.z.string().trim().min(1).max(160).optional(),route:d.z.string().trim().min(1).max(4096).optional()}).strict();const Ze=d.z.object({id:d.z.string().trim().min(1).max(120),messageId:d.z.string().trim().min(1).max(240).optional(),message:d.z.string().trim().min(1).max(2e4),attachments:d.z.array(be).max(6).default([]),references:Ee,permissionMode:we.optional(),status:d.z.enum(["queued","sending","failed"]).default("queued"),createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime(),error:d.z.string().trim().max(4e3).optional()}).strict(),et=d.z.object({revision:d.z.number().int().min(0).default(0),pendingCount:d.z.number().int().min(0).default(0),items:d.z.array(Ze).max(100).default([])}).strict().default({revision:0,pendingCount:0,items:[]}),tt=d.z.enum(["control","realtime","adapter-snapshot","transcript-tail","transcript-scan","process-scan","app-session"]),nt=d.z.object({id:d.z.string().trim().min(1).max(240),status:d.z.enum(["running","completed"]),startedAt:d.z.string().datetime().optional(),completedAt:d.z.string().datetime().optional()}).strict(),st=d.z.object({id:d.z.string().trim().min(1).max(240),providerTurnId:d.z.string().trim().max(240).optional(),source:tt.optional(),userPrompt:d.z.string().trim().optional(),userMessages:d.z.array(Z).max(100).optional(),status:d.z.enum(["queued","running","waiting","completed","failed"]).default("running"),phase:ne.optional(),summary:d.z.string().trim().max(1e3).optional(),lastMessage:d.z.string().trim().optional(),lastMessageItemId:d.z.string().trim().max(240).optional(),contextCompactions:d.z.array(nt).max(20).optional(),revision:d.z.number().int().min(0).default(0),sourcePriority:d.z.number().int().min(0).max(100).optional(),snapshotVersion:d.z.number().int().min(0).optional(),observedAt:d.z.string().datetime().optional(),startedAt:d.z.string().datetime().optional(),updatedAt:d.z.string().datetime().optional(),completedAt:d.z.string().datetime().optional()}).strict(),it=st.pick({id:!0,providerTurnId:!0,userPrompt:!0,userMessages:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,contextCompactions:!0,startedAt:!0,updatedAt:!0,completedAt:!0}).strict(),rt=d.z.object({id:d.z.string().trim().min(1).max(120),agent:$,creationSource:B.default("app-session"),appSessionId:d.z.string().trim().max(120).optional(),appId:d.z.string().trim().max(120).optional(),providerSessionId:d.z.string().trim().max(240).optional(),lineage:fe.optional(),providerMeta:d.z.record(d.z.string(),d.z.unknown()).optional(),appBindingKeys:d.z.array(d.z.string().trim().min(1).max(240)).max(20).optional(),actions:ye.optional(),activeTurnId:d.z.string().trim().max(240).optional(),title:d.z.string().trim().max(240).optional(),cwd:d.z.string().trim().max(4096).optional(),cwdFolderId:d.z.string().trim().min(1).max(120).optional(),userPrompt:d.z.string().trim().optional(),turns:d.z.array(st).max(50).optional(),status:ee.default("running"),phase:ne.default("unknown"),summary:d.z.string().trim().max(1e3).optional(),lastMessage:d.z.string().trim().optional(),lastMessageItemId:d.z.string().trim().max(240).optional(),currentTool:se.optional(),toolCallsSinceLastMessage:d.z.number().int().min(0).default(0),subAgents:d.z.array(me).max(50).default([]),transcriptPath:d.z.string().trim().max(4096).optional(),transcriptSize:d.z.number().int().min(0).optional(),startedAt:d.z.string().datetime(),updatedAt:d.z.string().datetime(),completedAt:d.z.string().datetime().optional(),error:d.z.string().trim().max(4e3).optional(),counters:ge,queue:et}).strict(),ot=d.z.object({session:rt,provider:d.z.string().trim().min(1).max(80),action:d.z.enum(["send","queue","steer","interrupt","approval"]),decision:d.z.enum(["allow","deny","skip"]).optional(),turnId:d.z.string().trim().min(1).max(240).optional(),providerTurnId:d.z.string().trim().min(1).max(240).optional(),queueId:d.z.string().trim().min(1).max(120).optional()}).strict(),at=500,dt=d.z.object({id:d.z.string().trim().min(1).max(120),agent:d.z.enum(["codex","claude"]),creationSource:B,providerSessionId:d.z.string().trim().min(1).max(240),lineage:fe.optional(),title:d.z.string().trim().max(240).optional(),userPrompt:d.z.string().trim().optional(),lastMessage:d.z.string().trim().optional(),cwd:d.z.string().trim().min(1).max(4096),cwdFolderId:d.z.string().trim().min(1).max(120).optional(),lastActiveAt:d.z.string().datetime(),archivedAt:d.z.string().datetime()}).strict();d.z.object({schemaVersion:d.z.literal(1).default(1),items:d.z.array(dt).max(at).default([])}).strict();const ct=d.z.object({items:d.z.array(dt).max(at).default([])}).strict(),lt=d.z.object({item:dt,turns:d.z.array(it).max(50).default([])}).strict(),pt=d.z.object({disposition:d.z.enum(["resumed","already-open"]),aiSessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),appSessionId:d.z.string().trim().min(1).max(120).optional(),creationSource:B}).strict(),ut=st.omit({userMessages:!0}),ht=rt.pick({id:!0,agent:!0,creationSource:!0,appSessionId:!0,appId:!0,providerSessionId:!0,lineage:!0,providerMeta:!0,appBindingKeys:!0,actions:!0,activeTurnId:!0,title:!0,cwd:!0,cwdFolderId:!0,userPrompt:!0,turns:!0,status:!0,phase:!0,summary:!0,lastMessage:!0,lastMessageItemId:!0,currentTool:!0,toolCallsSinceLastMessage:!0,subAgents:!0,queue:!0,startedAt:!0,updatedAt:!0,error:!0}).extend({turns:d.z.array(ut).max(50).optional()}).strict(),mt=d.z.object({runningCount:d.z.number().int().min(0).default(0),waitingCount:d.z.number().int().min(0).default(0),staleCount:d.z.number().int().min(0).default(0),sessions:d.z.array(ht).default([]),updatedAt:d.z.string().datetime()}).strict(),gt=d.z.object({streamId:d.z.string().trim().min(1).max(240),revision:d.z.number().int().min(0),lastEventAt:d.z.string().datetime(),snapshot:mt}).strict(),yt=mt.pick({runningCount:!0,waitingCount:!0,staleCount:!0,updatedAt:!0}).extend({idleCount:d.z.number().int().min(0).default(0),problemCount:d.z.number().int().min(0).default(0),revision:d.z.number().int().min(0).optional()});function ft(e,t={}){const n=e.sessions.filter(e=>"idle"===e.status).length,s=e.sessions.filter(e=>"failed"===e.status).length;return yt.parse({runningCount:e.runningCount,waitingCount:e.waitingCount,staleCount:e.staleCount,idleCount:n,problemCount:s,updatedAt:e.updatedAt,revision:t.revision})}const It=d.z.enum(["provider-event","app-session-created","app-session-updated","app-session-deleted","discovery-scan","control-action","heartbeat-sync","startup"]),bt=d.z.object({streamId:d.z.string().trim().min(1).max(240),instanceId:d.z.string().trim().min(1).max(160),nodeId:d.z.string().trim().min(1).max(160).optional(),revision:d.z.number().int().min(0),previousRevision:d.z.number().int().min(0).optional(),traceId:d.z.string().trim().min(1).max(160),generatedAt:d.z.string().datetime(),reason:It}).strict(),vt=d.z.object({meta:bt,snapshot:mt}).strict(),St=d.z.object({meta:bt,upserted:d.z.array(ht).default([]),removed:d.z.array(d.z.string().trim().min(1).max(120)).default([])}).strict(),wt=d.z.object({meta:bt,sessionIds:d.z.array(d.z.string().trim().min(1).max(120)).default([]),expiresAt:d.z.string().datetime()}).strict(),At=d.z.object({instanceId:d.z.string().trim().min(1).max(160),nodeId:d.z.string().trim().min(1).max(160).optional(),sessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),turnId:d.z.string().trim().min(1).max(240),itemId:d.z.string().trim().min(1).max(240),delta:d.z.string().min(1),generatedAt:d.z.string().datetime()}).strict(),zt=d.z.object({instanceId:d.z.string().trim().min(1).max(160),nodeId:d.z.string().trim().min(1).max(160).optional(),sessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().min(1).max(240),item:ce,generatedAt:d.z.string().datetime()}).strict(),kt=d.z.object({streamId:d.z.string().trim().min(1).max(240),instanceId:d.z.string().trim().min(1).max(160),sinceRevision:d.z.number().int().min(0),latestRevision:d.z.number().int().min(0),earliestRetainedRevision:d.z.number().int().min(0),syncRequired:d.z.boolean().default(!1),events:d.z.array(d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal(P),payload:vt}).strict(),d.z.object({type:d.z.literal(j),payload:St}).strict(),d.z.object({type:d.z.literal(D),payload:wt}).strict()])).default([])}).strict(),Tt=d.z.object({source:tt,sourcePriority:d.z.number().int().min(0).max(100).optional(),observedAt:d.z.string().datetime().optional(),snapshotVersion:d.z.number().int().min(0).optional()}).strict(),Ct=Tt.extend({type:d.z.literal("snapshot"),agent:d.z.string().trim().min(1).max(80),creationSource:B.optional(),appSessionId:d.z.string().trim().max(120).optional(),appId:d.z.string().trim().max(120).optional(),providerSessionId:d.z.string().trim().max(240).optional(),lineage:fe.optional(),providerMeta:d.z.record(d.z.string(),d.z.unknown()).optional(),appBindingKeys:d.z.array(d.z.string().trim().min(1).max(240)).max(20).optional(),actions:ye.optional(),title:d.z.string().trim().max(240).optional(),cwd:d.z.string().trim().max(4096).optional(),cwdFolderId:d.z.string().trim().min(1).max(120).optional(),activeTurnId:d.z.string().trim().max(240).optional(),userPrompt:d.z.string().trim().optional(),turns:d.z.array(st).max(50).optional(),status:ee.optional(),phase:ne.optional(),summary:d.z.string().trim().max(1e3).optional(),lastMessage:d.z.string().trim().optional(),lastMessageItemId:d.z.string().trim().max(240).optional(),error:d.z.string().trim().max(4e3).optional(),currentTool:se.optional(),toolCallsSinceLastMessage:d.z.number().int().min(0).optional(),subAgents:d.z.array(me).max(50).optional(),transcriptPath:d.z.string().trim().max(4096).optional(),transcriptSize:d.z.number().int().min(0).optional(),replaceActivity:d.z.boolean().optional()}).strict(),Et=Tt.extend({type:d.z.literal("event"),sessionId:d.z.string().trim().min(1).max(120),kind:d.z.enum(["lifecycle","send-ack","turn-started","user-message","assistant-message","approval-requested","turn-completed","session-error","tool-activity","sub-agent-activity","context-compaction"]),activeTurnId:d.z.string().trim().max(240).optional(),providerTurnId:d.z.string().trim().max(240).optional(),userPrompt:d.z.string().trim().optional(),userMessage:Z.optional(),text:d.z.string().optional(),itemId:d.z.string().trim().max(240).optional(),status:ee.optional(),phase:ne.optional(),summary:d.z.string().trim().max(1e3).optional(),error:d.z.string().trim().max(4e3).optional(),currentTool:se.nullable().optional(),toolCallsSinceLastMessage:d.z.number().int().min(0).optional(),subAgents:d.z.array(me).max(50).optional(),contextCompaction:nt.optional(),counters:d.z.object({toolCalls:d.z.number().int().min(0).optional(),edits:d.z.number().int().min(0).optional(),approvals:d.z.number().int().min(0).optional()}).strict().optional()}).strict().superRefine((e,t)=>{if("session-error"!==e.kind||e.error||t.addIssue({code:"custom",path:["error"],message:"session-error events require error"}),"context-compaction"===e.kind?e.contextCompaction||t.addIssue({code:"custom",path:["contextCompaction"],message:"context-compaction events require contextCompaction"}):void 0!==e.contextCompaction&&t.addIssue({code:"custom",path:["contextCompaction"],message:"contextCompaction is only valid for context-compaction events"}),"send-ack"!==e.kind&&"user-message"!==e.kind&&void 0!==e.userMessage&&t.addIssue({code:"custom",path:["userMessage"],message:"userMessage is only valid for send-ack and user-message events"}),"sub-agent-activity"===e.kind?e.subAgents||t.addIssue({code:"custom",path:["subAgents"],message:"sub-agent-activity events require subAgents"}):void 0!==e.subAgents&&t.addIssue({code:"custom",path:["subAgents"],message:"subAgents is only valid for sub-agent-activity events"}),"tool-activity"!==e.kind)return void 0!==e.currentTool&&t.addIssue({code:"custom",path:["currentTool"],message:"currentTool is only valid for tool-activity events"}),void(void 0!==e.toolCallsSinceLastMessage&&t.addIssue({code:"custom",path:["toolCallsSinceLastMessage"],message:"toolCallsSinceLastMessage is only valid for tool-activity events"}));"currentTool"in e||t.addIssue({code:"custom",path:["currentTool"],message:"tool-activity events require currentTool"}),void 0===e.toolCallsSinceLastMessage&&t.addIssue({code:"custom",path:["toolCallsSinceLastMessage"],message:"tool-activity events require toolCallsSinceLastMessage"})});d.z.discriminatedUnion("type",[Ct,Et]);const xt=d.z.object({type:d.z.literal("snapshot"),data:d.z.string(),pendingEscape:d.z.string(),cols:d.z.number().int().positive(),rows:d.z.number().int().positive()}).passthrough(),Nt="app-session.snapshot",Rt="app-session.patch",Ot="app-session.removed",_t=d.z.enum(["created","starting","running","stopping","stopped","exited","failed","closed","terminated","unknown"]),Pt=d.z.enum(["tty","vnc","web"]);d.z.object({mode:Pt,url:d.z.string().trim().min(1).max(4096),token:d.z.string().trim().min(1).max(512),expiresAt:d.z.string().datetime()}).strict(),d.z.object({revoked:d.z.boolean()}).strict();const jt=new Set(["stopped","failed","exited","closed","terminated"]),Dt=d.z.object({type:d.z.enum(["app-session","provider-session","adapter-key"]),id:d.z.string().trim().min(1).max(240),agent:d.z.string().trim().min(1).max(80).optional(),adapter:d.z.string().trim().min(1).max(80).optional(),key:d.z.string().trim().min(1).max(240).optional()}).strict(),Mt=d.z.record(d.z.string(),d.z.unknown()).and(d.z.object({id:d.z.string().trim().min(1).max(160),appId:d.z.string().trim().min(1).max(160).optional(),title:d.z.string().trim().max(240).optional(),kind:d.z.string().trim().max(80).optional(),status:_t.default("unknown"),bindings:d.z.array(Dt).max(40).default([]),workspace:d.z.object({cwd:d.z.string().trim().max(4096).optional()}).strict().optional(),createdAt:d.z.string().datetime().optional(),updatedAt:d.z.string().datetime().optional()})),Lt=d.z.object({runningCount:d.z.number().int().min(0).default(0),problemCount:d.z.number().int().min(0).default(0),sessions:d.z.array(Mt).default([]),updatedAt:d.z.string().datetime()}).strict(),qt=d.z.object({streamId:d.z.string().trim().min(1).max(240),revision:d.z.number().int().min(0),lastEventAt:d.z.string().datetime(),snapshot:Lt}).strict();Lt.pick({runningCount:!0,problemCount:!0,updatedAt:!0}).extend({revision:d.z.number().int().min(0).optional()});const $t=d.z.enum(["app-session-created","app-session-updated","app-session-deleted","app-session-recovered","control-action","heartbeat-sync","startup"]),Bt=d.z.object({streamId:d.z.string().trim().min(1).max(240),instanceId:d.z.string().trim().min(1).max(160),nodeId:d.z.string().trim().min(1).max(160).optional(),revision:d.z.number().int().min(0),previousRevision:d.z.number().int().min(0).optional(),traceId:d.z.string().trim().min(1).max(160),generatedAt:d.z.string().datetime(),reason:$t}).strict(),Ft=d.z.object({meta:Bt,snapshot:Lt}).strict(),Ut=d.z.object({meta:Bt,session:Mt}).strict(),Ht=d.z.object({meta:Bt,sessionId:d.z.string().trim().min(1).max(160),tombstone:Mt.optional(),expiresAt:d.z.string().datetime().optional()}).strict(),Wt=d.z.object({streamId:d.z.string().trim().min(1).max(240),instanceId:d.z.string().trim().min(1).max(160),sinceRevision:d.z.number().int().min(0),latestRevision:d.z.number().int().min(0),earliestRetainedRevision:d.z.number().int().min(0),syncRequired:d.z.boolean().default(!1),events:d.z.array(d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal(Nt),payload:Ft}).strict(),d.z.object({type:d.z.literal(Rt),payload:Ut}).strict(),d.z.object({type:d.z.literal(Ot),payload:Ht}).strict()])).default([])}).strict();function Gt(e,t=(new Date).toISOString()){const n=e.map(e=>Kt(e));return Lt.parse({runningCount:n.filter(e=>"running"===e.status).length,problemCount:n.filter(e=>"failed"===e.status).length,sessions:n,updatedAt:t})}function Vt(e,t=(new Date).toISOString()){return Gt(e.filter(e=>Yt("string"==typeof e.status?e.status:void 0)),t)}function Kt(e){const t=Jt("string"==typeof e.status?e.status:void 0),n="string"==typeof e.id?e.id:"",s=function(e){const t=nn(e.workspace),n=nn(e.tty),s=nn(e.launch),i=nn(e.ai),r=nn(i.claude),o=sn(t.cwd)||sn(n.cwd)||sn(r.cwd)||sn(s.cwd);return o?{cwd:o}:void 0}(e),{workspace:i,...r}=e;return Mt.parse({...r,status:t,bindings:tn([...(o=e.bindings,Array.isArray(o)?o.flatMap(e=>{const t=Dt.safeParse(e);return t.success?[t.data]:[]}):[]),...n?[{type:"app-session",id:n}]:[],...Zt(e)]),...s?{workspace:s}:{}});var o}function Jt(e){const t=(e||"unknown").trim().toLowerCase();return"ended"===t?"closed":"terminating"===t?"stopping":_t.options.includes(t)?t:"unknown"}function Yt(e){return!jt.has(Jt(e))}function Qt(e){return"tty"===e.kind?"tty":"gui"===e.kind?"vnc":"web"===e.kind?"web":void 0}function Xt(e){return"app-session"===e.type?`app:${e.id}`:"provider-session"===e.type?`provider:${e.agent||""}:${e.id}`:`adapter:${e.adapter||""}:${e.key||e.id}`}function Zt(e){const t=nn(e.ai),n=nn(t.claude),s=nn(t.appServer),i=nn(e.launch),r=[],o=sn(nn(i.aiSessionResume).providerSessionId),a="codex"===e.appId||"claude"===e.appId?e.appId:void 0;a&&o&&r.push({type:"provider-session",agent:a,id:o});const d=sn(n.short);d&&r.push({type:"adapter-key",adapter:"claude",agent:"claude",id:`short:${d}`,key:`short:${d}`});const c=sn(n.providerSessionId);c&&r.push({type:"provider-session",agent:"claude",id:c});const l=Array.isArray(t.threadIds)?t.threadIds.filter(e=>"string"==typeof e&&Boolean(e.trim())):[],p=sn(t.activeThreadId);for(const e of[...new Set([p,...l].filter(Boolean))])r.push({type:"provider-session",agent:"codex",id:e});const u=sn(s.socketPath);return u&&r.push({type:"adapter-key",adapter:"codex-app-server",agent:"codex",id:`socket:${u}`,key:`socket:${u}`}),r}function en(e){const t="string"==typeof e.id?e.id:"",n=nn(e.ai),s=sn(nn(n.claude).short);return[t?`app:${t}`:"",s?`claude-short:${s}`:""]}function tn(e){const t=new Map;for(const n of e)t.set(Xt(n),n);return[...t.values()]}function nn(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function sn(e){return"string"==typeof e&&e.trim()?e.trim():""}function rn(e=(new Date).toISOString()){return Lt.parse({runningCount:0,problemCount:0,sessions:[],updatedAt:e})}const on=d.z.string().trim().min(3).max(160).regex(/^[a-z][a-z0-9_-]*$/),an=d.z.string().datetime(),dn=d.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/),cn=d.z.string().min(32).max(4096),ln=d.z.strictObject({default:d.z.string().trim().min(1).max(160),translations:d.z.record(d.z.string().regex(/^[A-Za-z]{2,3}(?:-[A-Za-z0-9]{2,8})*$/),d.z.string().trim().min(1).max(160)).default({})});function pn(e){return Array.isArray(e)?`[${e.map(pn).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${pn(t)}`).join(",")}}`:JSON.stringify(e)}const un="2026-08-10",hn="2026-08-10",mn="2026-08-10",gn=Object.freeze({AccountApi:"task-handoff:official-account-api",Binding:"task-handoff:control-plane-binding",CoordinatorControl:"task-handoff:coordinator-control",RelayAllocation:"task-handoff:relay-allocation",RelayClientAttach:"task-handoff:relay-client-attach",RelayControlPlaneAttach:"task-handoff:relay-control-plane-attach",RelayRevocation:"task-handoff:relay-revocation",ControlPlaneAccess:"task-handoff:control-plane-access"});d.z.strictObject({protocolVersion:d.z.literal("2026-08-10"),audience:d.z.literal(gn.AccountApi)});const yn=d.z.string().email().max(320).transform(e=>e.trim().toLowerCase()),fn=d.z.enum(["pending-verification","active","disabled","pending-deletion"]);d.z.strictObject({id:on,email:yn,emailVerified:d.z.boolean(),hasPassword:d.z.boolean().optional(),totpEnabled:d.z.boolean().optional(),displayName:ln.optional(),status:fn,createdAt:an}),d.z.strictObject({id:on,kind:d.z.enum(["browser","mobile"]),deviceName:d.z.string().trim().min(1).max(160),platform:d.z.string().trim().min(1).max(80).optional(),createdAt:an,lastSeenAt:an.optional(),expiresAt:an,revokedAt:an.optional()}),d.z.union([d.z.object({code:cn,state:d.z.string().min(1).max(4096).optional(),redirectUri:d.z.string().url(),expiresAt:an}),d.z.object({authorizationUrl:d.z.string().url(),expiresAt:an})]),d.z.object({tokenType:d.z.literal("Bearer"),accessToken:cn,accessExpiresAt:an,refreshCredential:cn,accountId:on,deviceSessionId:on}),d.z.strictObject({enrollmentToken:cn,secret:cn,algorithm:d.z.literal("SHA1"),digits:d.z.literal(6),periodSeconds:d.z.literal(30),otpauthUri:d.z.string().url().startsWith("otpauth://totp/"),expiresAt:an});const In=d.z.strictObject({controlPlaneId:on,algorithm:d.z.literal("Ed25519"),publicKey:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:dn});d.z.strictObject({protocolVersion:d.z.literal(un),audience:d.z.literal(gn.Binding),challengeId:on,challenge:cn,serviceOrigin:d.z.string().url(),identity:In,nonce:d.z.string().min(16).max(256),initiatingAdminSessionId:on,issuedAt:an,expiresAt:an}),d.z.strictObject({code:d.z.enum(["CONTROL_PLANE_ALREADY_BOUND","REVISION_CONFLICT","REVOCATION_PENDING","IDENTITY_CLONE_CONFLICT"]),controlPlaneId:on,expectedRevision:d.z.number().int().nonnegative().optional(),actualRevision:d.z.number().int().nonnegative().optional(),retryable:d.z.boolean()});const bn=d.z.strictObject({bindingId:on.optional(),controlPlaneId:on,displayName:ln,publicKeyFingerprint:dn,bindingRevision:d.z.number().int().positive(),remoteAccess:d.z.enum(["enabled","disabled","revocation-pending"]),leaseExpiresAt:an.optional(),lastConnectedAt:an.optional(),relayUsageBytes:d.z.number().int().nonnegative(),relayQuotaBytes:d.z.number().int().nonnegative().optional(),versionWarning:d.z.string().trim().min(1).max(500).optional(),errorCode:d.z.string().trim().min(1).max(160).optional()}),vn=d.z.enum(["interactive","stream","bulk"]),Sn=d.z.object({type:d.z.literal("tty-snapshot"),streamId:d.z.string().trim().min(1).optional(),data:d.z.string(),pendingEscape:d.z.string(),cols:d.z.number().int().positive(),rows:d.z.number().int().positive()}).passthrough(),wn=d.z.strictObject({protocolVersion:d.z.literal(hn),audience:d.z.literal(gn.CoordinatorControl),connectionId:on,processInstanceId:on,controlPlaneId:on,publicKey:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/),publicKeyFingerprint:dn,bindingId:on.optional(),bindingRevision:d.z.number().int().positive().optional(),epoch:d.z.number().int().nonnegative(),capabilities:d.z.array(d.z.enum(["request","stream","websocket"])).min(1),issuedAt:an,expiresAt:an}).superRefine((e,t)=>{Boolean(e.bindingId)!==Boolean(e.bindingRevision)&&t.addIssue({code:"custom",message:"binding id and revision must be supplied together"})});wn.safeExtend({signature:cn}),d.z.strictObject({connectionId:on,controlPlaneId:on,bindingRevision:d.z.number().int().positive(),epoch:d.z.number().int().nonnegative(),relayId:on,relayRegion:d.z.string().trim().min(1).max(80),issuedAt:an,expiresAt:an});const An=d.z.strictObject({protocolVersion:d.z.literal(hn),audience:d.z.literal(gn.ControlPlaneAccess),ticketId:on,accountId:on,deviceSessionId:on,controlPlaneId:on,bindingId:on,bindingRevision:d.z.number().int().positive(),targetPublicKeyFingerprint:dn,nonce:d.z.string().min(16).max(256),trafficClasses:d.z.array(vn).min(1),issuedAt:an,expiresAt:an,signature:cn});d.z.strictObject({audience:d.z.literal(gn.ControlPlaneAccess),accountId:on,deviceSessionId:on,controlPlaneId:on,bindingId:on,bindingRevision:d.z.number().int().positive(),authenticatedAt:an,expiresAt:an,signature:cn});const zn=d.z.enum(["client","control-plane"]),kn=d.z.strictObject({protocolVersion:d.z.literal(mn),audience:d.z.enum([gn.RelayClientAttach,gn.RelayControlPlaneAttach]),allocationId:on,relayId:on,role:zn,controlPlaneId:on,accountId:on,deviceSessionId:on,bindingId:on,ticketId:on,bindingRevision:d.z.number().int().positive(),trafficClass:vn,nonce:d.z.string().min(16).max(256),issuedAt:an,expiresAt:an,signature:cn}).superRefine((e,t)=>{const n="client"===e.role?gn.RelayClientAttach:gn.RelayControlPlaneAttach;e.audience!==n&&t.addIssue({code:"custom",path:["audience"],message:`audience must match ${e.role} role`})});d.z.object({allocationId:on,relayId:on,relayRegion:d.z.string().trim().min(1).max(80),relayUrl:d.z.string().url(),clientAttach:kn,expiresAt:an}),d.z.strictObject({channelId:on,allocationId:on,controlPlaneId:on,bindingRevision:d.z.number().int().positive(),trafficClass:vn,state:d.z.enum(["waiting-for-peer","handshaking","open","closing","closed"]),clientAttached:d.z.boolean(),controlPlaneAttached:d.z.boolean(),openedAt:an.optional(),leaseExpiresAt:an}),d.z.strictObject({protocolVersion:d.z.literal(mn),channelId:on,sequence:d.z.number().int().nonnegative(),kind:d.z.enum(["handshake","data","cancel","window-update","close"]),ciphertext:d.z.string().max(1398102).optional(),creditBytes:d.z.number().int().positive().optional()}),d.z.strictObject({channelId:on,code:d.z.enum(["normal","expired","revoked","quota-exceeded","idle-timeout","slow-consumer","protocol-error","peer-disconnected"]),retryable:d.z.boolean()}),d.z.strictObject({protocolVersion:d.z.literal(mn),audience:d.z.literal(gn.RelayRevocation),revocationId:on,relayId:on.optional(),allocationId:on.optional(),accountId:on.optional(),deviceSessionId:on.optional(),bindingId:on.optional(),issuedAt:an,expiresAt:an,signature:cn}).refine(e=>[e.allocationId,e.accountId,e.deviceSessionId,e.bindingId].some(Boolean),"revocation target is required"),d.z.strictObject({data:d.z.strictObject({protocolVersion:d.z.literal(un),items:d.z.array(bn)})}),Object.keys(bn.shape);const Tn=d.z.object({ticketId:d.z.string().trim().min(3).max(160),deviceSessionId:d.z.string().trim().min(3).max(160),clientEphemeralPublicKey:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/)});function Cn(){return Object.assign(new Error("End-to-end handshake is invalid."),{code:"E2E_HANDSHAKE_INVALID"})}d.z.object({serverEphemeralPublicKey:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/),transcript:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/),signature:d.z.string().regex(/^[A-Za-z0-9_-]{86}$/)});const En=d.z.union([d.z.object({type:d.z.literal("schedule"),scheduleKind:d.z.literal("interval").default("interval"),intervalMs:d.z.number().int().min(1e3)}).strict(),d.z.object({type:d.z.literal("schedule"),scheduleKind:d.z.literal("daily"),timeOfDay:d.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),timezone:d.z.string().trim().min(1).max(120)}).strict(),d.z.object({type:d.z.literal("schedule"),scheduleKind:d.z.literal("weekly"),weekdays:d.z.array(d.z.number().int().min(0).max(6)).min(1).max(7),timeOfDay:d.z.string().regex(/^([01]\d|2[0-3]):[0-5]\d$/),timezone:d.z.string().trim().min(1).max(120)}).strict()]),xn=d.z.union([En,d.z.object({type:d.z.literal("file-change"),roots:d.z.array(d.z.string().trim().min(1).max(4096)).min(1).max(50),globs:d.z.array(d.z.string().trim().min(1).max(500)).min(1).max(100),ignore:d.z.array(d.z.string().trim().min(1).max(500)).max(100).optional(),debounceMs:d.z.number().int().min(100).max(6e4).default(1500)}).strict(),d.z.object({type:d.z.literal("ai-session"),agent:d.z.string().trim().min(1).max(80).optional(),statuses:d.z.array(d.z.enum(["running","waiting","idle","failed"])).max(20).optional(),phases:d.z.array(d.z.enum(["thinking","tool","editing","approval","responding","unknown"])).max(20).optional()}).strict()]),Nn=d.z.object({promptTemplate:d.z.string().trim().min(1).max(2e4)}).strict(),Rn=d.z.object({cooldownMs:d.z.number().int().min(0).max(864e5).optional(),maxConcurrentRuns:d.z.number().int().min(1).max(20).default(1),whenBusy:d.z.enum(["skip","queue"]).default("skip")}).strict(),On=d.z.object({configHash:d.z.string().trim().min(8).max(80),name:d.z.string().trim().min(1).max(160),description:d.z.string().trim().max(1e3).optional(),source:xn,action:Nn,policy:Rn.default({maxConcurrentRuns:1,whenBusy:"skip"}),createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime()}).strict(),_n=d.z.object({type:d.z.literal("ai-session"),aiSessionId:d.z.string().trim().min(1).max(160)}).strict(),Pn=d.z.object({configHash:d.z.string().trim().min(8).max(80),deploymentId:d.z.string().trim().min(1).max(240).optional(),instanceId:d.z.string().trim().min(1).max(160),origin:d.z.enum(["control-plane","controlled-instance"]).default("controlled-instance"),enabled:d.z.boolean().default(!0),target:_n,localName:d.z.string().trim().min(1).max(160).optional(),createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime()}).strict(),jn=d.z.object({configHash:d.z.string().trim().min(8).max(80),deploymentId:d.z.string().trim().min(1).max(240).optional(),instanceId:d.z.string().trim().min(1).max(160),status:d.z.enum(["idle","running","disabled","error"]).default("idle"),lastTriggeredAt:d.z.string().datetime().optional(),lastCompletedAt:d.z.string().datetime().optional(),lastSkippedAt:d.z.string().datetime().optional(),lastError:d.z.string().trim().max(4e3).optional(),runCount:d.z.number().int().min(0).default(0),skippedCount:d.z.number().int().min(0).default(0)}).strict(),Dn=d.z.object({id:d.z.string().trim().min(1).max(160),configHash:d.z.string().trim().min(8).max(80),deploymentId:d.z.string().trim().min(1).max(240).optional(),instanceId:d.z.string().trim().min(1).max(160),eventType:d.z.enum(["manual","schedule","file-change","ai-session"]),status:d.z.enum(["started","completed","failed","skipped"]),target:_n,promptPreview:d.z.string().trim().max(500),eventSummary:d.z.string().trim().max(1e3).optional(),error:d.z.string().trim().max(4e3).optional(),startedAt:d.z.string().datetime(),completedAt:d.z.string().datetime().optional()}).strict();d.z.object({schemaVersion:d.z.literal(1).default(1),configs:d.z.array(On).default([]),deployments:d.z.array(Pn).default([]),runtime:d.z.array(jn).default([]),recentRuns:d.z.array(Dn).default([])}).strict();const Mn=d.z.object({instanceId:d.z.string().trim().min(1).max(160),instanceName:d.z.string().trim().min(1).max(160),deployment:Pn,runtime:jn.optional()}).strip(),Ln=Dn.extend({instanceName:d.z.string().trim().min(1).max(160).optional()}).strip(),qn=d.z.object({configHash:d.z.string().trim().min(8).max(80),config:On,deploymentCount:d.z.number().int().min(0),enabledCount:d.z.number().int().min(0),runningCount:d.z.number().int().min(0),errorCount:d.z.number().int().min(0),ownedByControlPlane:d.z.boolean(),controlPlaneDeploymentCount:d.z.number().int().min(0),deployments:d.z.array(Mn),recentRuns:d.z.array(Ln)}).strip(),$n=d.z.object({updatedAt:d.z.string().datetime(),triggers:d.z.array(qn)}).strip();function Bn(e){const t=Hn({source:e.source,action:e.action,policy:Rn.parse(e.policy||{})});return`trg_${function(e){const t=(new TextEncoder).encode(e),n=64*Math.ceil((t.length+9)/64),s=new Uint8Array(n);s.set(t),s[t.length]=128;const i=new DataView(s.buffer),r=8*t.length;i.setUint32(n-8,Math.floor(r/4294967296)),i.setUint32(n-4,r>>>0);const o=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),a=new Uint32Array(64);for(let e=0;e<n;e+=64){for(let t=0;t<16;t+=1)a[t]=i.getUint32(e+4*t);for(let e=16;e<64;e+=1){const t=a[e-15],n=a[e-2],s=Un(t,7)^Un(t,18)^t>>>3,i=Un(n,17)^Un(n,19)^n>>>10;a[e]=a[e-16]+s+a[e-7]+i>>>0}let[t,n,s,r,d,c,l,p]=o;for(let e=0;e<64;e+=1){const i=p+(Un(d,6)^Un(d,11)^Un(d,25))+(d&c^~d&l)+Fn[e]+a[e]>>>0,o=t&n^t&s^n&s;p=l,l=c,c=d,d=r+i>>>0,r=s,s=n,n=t,t=i+((Un(t,2)^Un(t,13)^Un(t,22))+o>>>0)>>>0}o[0]=o[0]+t>>>0,o[1]=o[1]+n>>>0,o[2]=o[2]+s>>>0,o[3]=o[3]+r>>>0,o[4]=o[4]+d>>>0,o[5]=o[5]+c>>>0,o[6]=o[6]+l>>>0,o[7]=o[7]+p>>>0}return[...o].map(e=>e.toString(16).padStart(8,"0")).join("")}(JSON.stringify(t)).slice(0,24)}`}d.z.object({name:On.shape.name,description:On.shape.description,source:xn,action:Nn,policy:Rn.partial().optional()}).strict(),d.z.object({scope:d.z.enum(["node","instance"]),nodeId:d.z.string().trim().min(1).max(160).optional(),instanceId:d.z.string().trim().min(1).max(160).optional(),code:d.z.string().trim().min(1).max(160),message:d.z.string().trim().min(1).max(4e3)}).strip();const Fn=[1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298];function Un(e,t){return e>>>t|e<<32-t}function Hn(e){return Array.isArray(e)?e.map(Hn):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>[e,Hn(t)])):e}const Wn="2026-08-01",Gn=d.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Proxy protocol version must use YYYY-MM-DD format."),Vn=d.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Kn=d.z.string().datetime(),Jn=d.z.string().trim().min(32).max(4096),Yn=Vn,Qn=d.z.string().trim().max(2048).transform((e,t)=>{try{return function(e){const t=new URL(e.trim());if("https:"!==t.protocol||t.username||t.password||"/"!==t.pathname||t.search||t.hash)throw new Error("Proxy origin must be an HTTPS origin without credentials, path, query, or fragment.");return t.origin}(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),d.z.NEVER}}),Xn=d.z.string().trim().min(1).max(4096).transform((e,t)=>{try{return function(e){const t=e.trim();if(!t.startsWith("/")||t.startsWith("//")||t.includes("\\")||/%25/i.test(t))throw new Error("Proxy route must be a single-encoded node-agent relative route.");const n=t.split("?",1)[0];let s,i;try{s=n.split("/").map(e=>decodeURIComponent(e))}catch{throw new Error("Proxy route contains invalid percent encoding.")}if(s.some(e=>".."===e||"."===e))throw new Error("Proxy route cannot traverse outside the node-agent API.");try{i=new URL(t,"https://node-agent.invalid")}catch{throw new Error("Proxy route is invalid.")}if("https://node-agent.invalid"!==i.origin||i.username||i.password)throw new Error("Proxy route cannot select an absolute upstream URL.");return`${i.pathname}${i.search}`}(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),d.z.NEVER}}),Zn=new Set(["accept","accept-language","authorization","content-type","if-match","if-none-match","range","x-request-id","x-task-handoff-trace-id"]),es=new Set(["cache-control","content-disposition","content-language","content-length","content-range","content-type","etag","last-modified","server-timing","x-request-id","x-task-handoff-trace-id"]),ts="x-task-handoff-proxy-protocol-version",ns="x-task-handoff-proxy-source-control-plane-id",ss="x-task-handoff-proxy-binding-key-id",is="x-task-handoff-proxy-credential",rs={ProtocolUnsupported:"CONTROL_PLANE_PROXY_PROTOCOL_UNSUPPORTED",InviteInvalid:"CONTROL_PLANE_PROXY_INVITE_INVALID",InviteExpired:"CONTROL_PLANE_PROXY_INVITE_EXPIRED",InviteConsumed:"CONTROL_PLANE_PROXY_INVITE_CONSUMED",InviteRevoked:"CONTROL_PLANE_PROXY_INVITE_REVOKED",TargetUnavailable:"CONTROL_PLANE_PROXY_TARGET_UNAVAILABLE",TargetMismatch:"CONTROL_PLANE_PROXY_TARGET_MISMATCH",BindingUnknown:"CONTROL_PLANE_PROXY_BINDING_UNKNOWN",BindingRevoked:"CONTROL_PLANE_PROXY_BINDING_REVOKED",BindingIdentityConflict:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",AuthenticationFailed:"CONTROL_PLANE_PROXY_AUTHENTICATION_FAILED",RouteInvalid:"CONTROL_PLANE_PROXY_ROUTE_INVALID",HeaderInvalid:"CONTROL_PLANE_PROXY_HEADER_INVALID",ResourceLimit:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",SnapshotRequired:"CONTROL_PLANE_PROXY_SNAPSHOT_REQUIRED",Unavailable:"CONTROL_PLANE_PROXY_UNAVAILABLE",TransportFailed:"CONTROL_PLANE_PROXY_TRANSPORT_FAILED"},os=d.z.enum(Object.values(rs)),as=d.z.object({code:os,message:d.z.string().trim().min(1).max(2048),retryable:d.z.boolean(),details:d.z.record(d.z.string(),d.z.unknown()).optional()}).strict(),ds=d.z.enum(["active","revoked"]),cs=d.z.object({id:Vn,targetNodeId:Vn,status:ds,createdBy:Vn,expiresAt:Kn,revokedAt:Kn.optional(),createdAt:Kn,updatedAt:Kn}).strict(),ls=d.z.object({targetNodeId:Vn,expiresInSeconds:d.z.number().int().min(60).max(3600).default(600)}).strict(),ps=d.z.object({invite:cs,token:d.z.string().trim().min(24).max(512),proxyOrigin:Qn,protocolVersion:Gn}).strict(),us=d.z.enum(["active","revoked"]),hs=d.z.object({id:Vn,claimId:Vn,sourceControlPlaneId:Vn,targetNodeId:Vn,bindingKeyId:Vn,status:us,revision:d.z.number().int().positive(),lastError:as.optional(),revokedAt:Kn.optional(),createdAt:Kn,updatedAt:Kn}).strict(),ms=d.z.object({protocolVersion:Gn,inviteToken:d.z.string().trim().min(24).max(512).optional(),claimId:Vn,sourceControlPlaneId:Vn,targetNodeId:Vn.optional(),bindingKeyId:Vn,credential:Jn}).strict(),gs=d.z.object({sourceControlPlaneId:Vn,bindingKeyId:Vn,credential:Jn}).strict(),ys=d.z.object({id:Vn,name:d.z.string().trim().min(1).max(160),status:d.z.enum(["unknown","online","offline","degraded"]),health:d.z.enum(["unknown","ok","degraded","failed"]),lastSeenAt:Kn.optional(),capabilities:d.z.record(d.z.string(),d.z.unknown()).default({})}).strict(),fs=d.z.object({protocolVersion:Gn,binding:hs,streamId:Vn,revision:d.z.number().int().nonnegative(),observedAt:Kn,target:ys}).strict(),Is=d.z.object({type:d.z.literal("control-plane-proxy.event"),protocolVersion:Gn,streamId:Vn,bindingId:Vn,sourceControlPlaneId:Vn,targetNodeId:Vn,revision:d.z.number().int().positive(),source:d.z.object({id:d.z.string().trim().min(1).max(512),seq:d.z.number().int().nonnegative()}).strict(),target:ys,event:d.z.object({type:d.z.string().trim().min(1).max(240),topic:d.z.string().trim().min(1).max(240),createdAt:Kn}).strict()}).strict(),bs=d.z.object({type:d.z.literal("control-plane-proxy.events.ready"),protocolVersion:Gn,streamId:Vn,bindingId:Vn,sourceControlPlaneId:Vn,targetNodeId:Vn,latestRevision:d.z.number().int().nonnegative(),earliestRetainedRevision:d.z.number().int().nonnegative()}).strict(),vs=d.z.object({type:d.z.literal("control-plane-proxy.snapshot-required"),protocolVersion:Gn,streamId:Vn,bindingId:Vn,sourceControlPlaneId:Vn,targetNodeId:Vn,sinceRevision:d.z.number().int().nonnegative(),latestRevision:d.z.number().int().nonnegative(),earliestRetainedRevision:d.z.number().int().nonnegative(),error:as}).strict(),Ss=d.z.discriminatedUnion("type",[Is,bs,vs]),ws=d.z.object({protocolVersion:Gn,binding:hs,target:fs.shape.target}).strict(),As=d.z.object({id:Vn,claimId:Vn,proxyOrigin:Qn,requestedName:d.z.string().trim().min(1).max(160).optional(),sourceControlPlaneId:Vn,targetNodeId:Vn.optional(),bindingKeyId:Vn,credential:Jn,status:d.z.enum(["pending","compensation-required"]),createdAt:Kn,updatedAt:Kn,expiresAt:Kn}).strict();As.omit({credential:!0});const zs=d.z.object({id:Vn,nodeId:Vn,proxyOrigin:Qn,proxyBindingId:Vn,targetNodeId:Vn,sourceControlPlaneId:Vn,bindingKeyId:Vn,credential:Jn,createdAt:Kn,updatedAt:Kn}).strict(),ks="2026-08-20",Ts=new Set(["2026-08-01","2026-08-16","2026-08-17",ks]),Cs=d.z.string().regex(/^\d{4}-\d{2}-\d{2}$/,"Protocol version must use YYYY-MM-DD format."),Es=d.z.string().trim().min(1).max(120);function xs(){return{features:{appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]},aiSessionConversationAttachments:{metadataAgents:[],contentAgents:[],uploadAgents:[],retentionSettings:!1}}}}const Ns=d.z.object({sessionReadAgents:d.z.array(Es).max(100).default([]),turnReadAgents:d.z.array(Es).max(100).default([]),liveItemAgents:d.z.array(Es).max(100).default([])}).passthrough(),Rs=d.z.object({metadataAgents:d.z.array(Es).max(100).default([]),contentAgents:d.z.array(Es).max(100).default([]),uploadAgents:d.z.array(Es).max(100).default([]),retentionSettings:d.z.boolean().default(!1)}).passthrough(),Os=d.z.object({appRuntime:d.z.boolean().default(!1),tty:d.z.boolean().default(!1),gui:d.z.boolean().default(!1),browser:d.z.boolean().default(!1),screenshots:d.z.boolean().default(!1),logs:d.z.boolean().default(!1),aiSessionWorkspaceSelection:d.z.boolean().default(!1),aiSessionPersistenceSettings:d.z.boolean().default(!1),aiSessionTimeline:Ns.default(function(){return{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}),aiSessionConversationAttachments:Rs.optional()}).passthrough(),_s=d.z.object({features:Os.default(function(){return{appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]},aiSessionConversationAttachments:{metadataAgents:[],contentAgents:[],uploadAgents:[],retentionSettings:!1}}})}).passthrough();function Ps(e){const t={features:{appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]},aiSessionConversationAttachments:{metadataAgents:[],contentAgents:[],uploadAgents:[],retentionSettings:!1}}};if(!e||"object"!=typeof e||Array.isArray(e))return t;const n=e,s=n.features;if(!s||"object"!=typeof s||Array.isArray(s))return t;const i=s,r={appRuntime:!1,tty:!1,gui:!1,browser:!1,screenshots:!1,logs:!1,aiSessionWorkspaceSelection:!1,aiSessionPersistenceSettings:!1,aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]},aiSessionConversationAttachments:{metadataAgents:[],contentAgents:[],uploadAgents:[],retentionSettings:!1}};for(const e of["appRuntime","tty","gui","browser","screenshots","logs","aiSessionWorkspaceSelection","aiSessionPersistenceSettings"]){const t=d.z.boolean().safeParse(i[e]);t.success&&(r[e]=t.data)}const o=Ns.safeParse(i.aiSessionTimeline);o.success&&(r.aiSessionTimeline=o.data);const a=Rs.safeParse(i.aiSessionConversationAttachments);return a.success&&(r.aiSessionConversationAttachments=a.data),_s.parse({...n,features:{...i,...r}})}function js(e,t){const n=function(e){return Ps(e).features.aiSessionTimeline}(e);return"session-read"===t?n.sessionReadAgents:"turn-read"===t?n.turnReadAgents:n.liveItemAgents}const Ds=d.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Ms=d.z.string().datetime(),Ls=d.z.record(d.z.string(),d.z.string()).default({}),qs=d.z.record(d.z.string(),d.z.string()).default({});function $s(e){if(null!=e){if("string"==typeof e)return{encoding:"utf8",data:e};if(Buffer.isBuffer(e))return{encoding:"base64",data:e.toString("base64")};if(e instanceof ArrayBuffer)return{encoding:"base64",data:Buffer.from(e).toString("base64")};if(ArrayBuffer.isView(e))return{encoding:"base64",data:Buffer.from(e.buffer,e.byteOffset,e.byteLength).toString("base64")};throw new TypeError("Node tunnel request body must be a string or binary buffer.")}}d.z.object({encoding:d.z.enum(["utf8","base64"]),data:d.z.string()}).strict().superRefine((e,t)=>{"base64"===e.encoding&&Buffer.from(e.data,"base64").toString("base64")!==e.data&&t.addIssue({code:"custom",path:["data"],message:"Node tunnel binary body must use canonical base64 encoding."})});const Bs=/^[A-Za-z0-9_][A-Za-z0-9_.-]{0,127}$/,Fs=/^sha256:([a-fA-F0-9]{64})$/,Us=/^(?:localhost|[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?)(?::[1-9][0-9]{0,4})?$/,Hs=/^[a-z0-9]+(?:(?:[._]|__|-+)[a-z0-9]+)*$/;function Ws(e){const t=e.trim();if(!t||t.length>512||t.includes("://")||/\s/.test(t))throw new Error("Docker image reference must not contain a URL scheme or whitespace.");const n=t.indexOf("@");if(-1!==n&&n!==t.lastIndexOf("@"))throw new Error("Docker image reference contains more than one digest separator.");const s=-1===n?void 0:t.slice(n+1),i=-1===n?t:t.slice(0,n),r=s?Fs.exec(s):void 0;if(s&&!r)throw new Error("Docker image digest must use sha256 followed by 64 hexadecimal characters.");const o=i.lastIndexOf("/"),a=i.lastIndexOf(":"),d=a>o,c=d?i.slice(a+1):void 0,l=d?i.slice(0,a):i;if(c&&!Bs.test(c))throw new Error("Docker image tag is invalid.");if(!c&&!r)throw new Error("Docker image reference must include an explicit tag or sha256 digest.");const p=l.split("/");if(!p.length||p.some(e=>!e))throw new Error("Docker image repository path is invalid.");const u=p.length>1&&(p[0].includes(".")||p[0].includes(":")||"localhost"===p[0]),h=u?p.slice(1):p;if(u&&!Us.test(p[0].toLowerCase()))throw new Error("Docker image registry host or port is invalid.");if(!h.length||h.some(e=>!Hs.test(e)))throw new Error("Docker image repository names must be lowercase and use valid separators.");const m=p.map((e,t)=>u&&0===t?e.toLowerCase():e).join("/"),g=r?`sha256:${r[1].toLowerCase()}`:void 0;return`${m}${c?`:${c}`:""}${g?`@${g}`:""}`}function Gs(e){const t=Ws(e),n=t.indexOf("@"),s=-1===n?void 0:t.slice(n+1),i=-1===n?t:t.slice(0,n),r=i.lastIndexOf("/"),o=i.lastIndexOf(":"),a=o>r;return{reference:t,repository:a?i.slice(0,o):i,tag:a?i.slice(o+1):void 0,digest:s}}const Vs=d.z.string().trim().min(1).max(512).transform((e,t)=>{try{return Ws(e)}catch(e){return t.addIssue({code:"custom",message:e instanceof Error?e.message:String(e)}),d.z.NEVER}}),Ks=d.z.string().trim().transform((e,t)=>{const n=Fs.exec(e);return n?`sha256:${n[1].toLowerCase()}`:(t.addIssue({code:"custom",message:"Docker image digest must use sha256 followed by 64 hexadecimal characters."}),d.z.NEVER)}),Js=d.z.object({codexModelHash:Ds.nullable().optional(),claudeModelHash:Ds.nullable().optional()}).strict().default({}),Ys=d.z.object({imageId:Ds,tag:d.z.string().trim().min(1).max(128).regex(Bs).optional()}).strict(),Qs=d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal("image"),imageSelection:Ys}).strict(),d.z.object({type:d.z.literal("template"),environmentTemplateId:Ds}).strict()]),Xs=d.z.enum(["creating","ready","failed","deleting"]),Zs=d.z.enum(["linux","darwin","win32","freebsd","openbsd","aix","sunos","unknown"]),ei=d.z.enum(["x64","arm64","arm","ia32","ppc64","s390x","riscv64","unknown"]),ti=d.z.object({code:d.z.string().trim().min(1).max(120),message:d.z.string().trim().min(1).max(2048),phase:d.z.enum(["validate","commit","inspect","security-check","persist","delete","recovery"]).optional()}).strict(),ni=d.z.object({templateId:Ds,nodeId:Ds,imageId:Ks,name:d.z.string().trim().min(1).max(160),platform:Zs,architecture:ei}).strict(),si=d.z.enum(["data","agent-home","workspace"]),ii=d.z.object({deleteVolumes:d.z.boolean()}).strict(),ri=d.z.object({role:si,name:d.z.string().trim().min(1).max(255),mountPath:d.z.string().trim().startsWith("/").max(4096),status:d.z.enum(["deleted","retained","missing","failed"]),error:d.z.object({code:d.z.string().trim().min(1).max(120),message:d.z.string().trim().min(1).max(2048)}).strict().optional()}).strict(),oi=d.z.object({instanceId:Ds,containerDeleted:d.z.boolean(),completed:d.z.boolean(),deletedVolumes:d.z.array(ri),retainedVolumes:d.z.array(ri),volumeResults:d.z.array(ri)}).strict(),ai={img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"};function di(e,t){if(e&&"object"==typeof e&&!Array.isArray(e)){const t=e;return{imageId:"string"==typeof t.imageId&&ai[t.imageId]||t.imageId,..."string"==typeof t.tag?{tag:t.tag}:{}}}if("string"==typeof t)return{imageId:ai[t]||t}}function ci(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,{defaultImageId:n,...s}=t;return{...s,defaultImageSelection:di(t.defaultImageSelection,n)}}const li=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(120),kind:d.z.enum(["tty","gui","web"]),source:d.z.enum(["builtin","custom"]),availability:d.z.enum(["available","missing-dependency"]),capabilities:d.z.object({automation:d.z.enum(["cdp"]).optional(),supportsCwdSelection:d.z.boolean().default(!1)}).strict().default({supportsCwdSelection:!1}),diagnosticCode:d.z.enum(["APP_EXECUTABLE_NOT_FOUND"]).optional()}).strict(),pi=d.z.object({code:d.z.enum(["APP_CATALOG_INVALID"]),message:d.z.string().trim().min(1).max(500)}).strict(),ui=d.z.object({items:d.z.array(li).max(256),observedAt:Ms,issues:d.z.array(pi).max(32).default([])}).strict(),hi=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(160),sourceInstanceId:Ds,nodeId:Ds,imageId:Ks.optional(),internalTag:d.z.string().trim().min(1).max(512).optional(),platform:Zs.optional(),architecture:ei.optional(),sizeBytes:d.z.number().int().nonnegative().optional(),status:Xs,error:ti.optional(),createdAt:Ms,updatedAt:Ms}).strict().superRefine((e,t)=>{if("ready"===e.status)for(const n of["imageId","internalTag","platform","architecture","sizeBytes"])void 0===e[n]&&t.addIssue({code:"custom",path:[n],message:`Ready environment template requires ${n}.`});"failed"!==e.status||e.error||t.addIssue({code:"custom",path:["error"],message:"Failed environment template requires an error diagnostic."})}),mi=d.z.enum(["apt","dnf","brew","npm"]),gi=d.z.enum(["user","passwordless-sudo","root"]),yi=d.z.object({platform:Zs,arch:ei,installers:d.z.array(mi).max(8),privilege:gi,installerAccess:d.z.object({npmGlobalWritable:d.z.boolean().optional()}).strict().optional()}).strict(),fi=d.z.enum(["installed","not-installed","broken","unsupported"]),Ii=d.z.enum(["recipe","bundled","external","none"]),bi=d.z.object({code:d.z.enum(["BUNDLED","EXTERNALLY_MANAGED","ALREADY_INSTALLED","NOT_INSTALLED","UNSUPPORTED_PLATFORM","INSTALLER_UNAVAILABLE","INSTALLER_NOT_WRITABLE","INSUFFICIENT_PRIVILEGE","OPERATION_IN_PROGRESS"]),message:d.z.string().trim().min(1).max(500)}).strict(),vi=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(120),kind:d.z.enum(["tty","gui","web"]),description:d.z.string().trim().max(500).optional(),state:fi,managementSource:Ii,version:d.z.string().trim().max(120).optional(),canInstall:d.z.boolean(),canUninstall:d.z.boolean(),installReason:bi.optional(),uninstallReason:bi.optional(),activeJobId:Ds.optional()}).strict(),Si=d.z.enum(["install","uninstall"]),wi=d.z.enum(["queued","running","succeeded","failed","cancelled","interrupted"]),Ai=d.z.object({current:d.z.number().finite().nonnegative().optional(),total:d.z.number().finite().positive().optional(),unit:d.z.string().trim().min(1).max(40).optional()}).strict().refine(e=>void 0===e.total||void 0===e.current||e.current<=e.total,{message:"Progress current must not exceed total.",path:["current"]}),zi=d.z.object({executable:d.z.string().trim().min(1).max(4096),args:d.z.array(d.z.string().max(4096)).max(128)}).strict(),ki=d.z.object({code:d.z.string().trim().min(1).max(120).regex(/^[a-z0-9][a-z0-9._-]*$/),message:d.z.string().trim().min(1).max(4096),retryable:d.z.boolean(),sessionIds:d.z.array(Ds).max(64).optional()}).strict(),Ti=d.z.object({id:Ds,requestId:Ds.optional(),appId:Ds,operation:Si,state:wi,phase:d.z.string().trim().min(1).max(120).optional(),progress:Ai.optional(),command:zi.optional(),logTail:d.z.string().max(32768).optional(),logTruncated:d.z.boolean().optional(),error:ki.optional(),requestedAt:Ms,startedAt:Ms.optional(),finishedAt:Ms.optional(),updatedAt:Ms}).strict(),Ci=d.z.object({streamId:Ds,sequence:d.z.number().int().nonnegative(),capabilities:yi,apps:d.z.array(vi).max(256),activeJobs:d.z.array(Ti).max(256),recentJobs:d.z.array(Ti).max(256),observedAt:Ms}).strict(),Ei=d.z.object({requestId:Ds.optional()}).strict(),xi=d.z.object({job:Ti}).strict();d.z.object({type:d.z.literal("app-management"),streamId:Ds,sequence:d.z.number().int().nonnegative(),observedAt:Ms,job:Ti.optional(),snapshot:Ci.optional()}).strict().refine(e=>void 0!==e.job||void 0!==e.snapshot,{message:"An app management event requires a job or snapshot."});const Ni=d.z.object({component:d.z.enum(["control-plane","node-agent","controlled-instance"]),packageName:d.z.string().trim().max(160).optional(),packageVersion:d.z.string().trim().max(80).optional(),protocolVersion:Cs.optional(),buildId:d.z.string().trim().max(160).optional(),builtAt:d.z.string().trim().max(120).optional(),gitCommit:d.z.string().trim().max(120).optional(),imageRef:d.z.string().trim().max(512).optional(),imageDigest:d.z.string().trim().max(240).optional()}).strict(),Ri=d.z.object({data:d.z.object({ok:d.z.literal(!0),role:d.z.literal("control-plane"),protocolVersion:Cs,build:Ni.extend({component:d.z.literal("control-plane"),packageVersion:d.z.string().trim().min(1).max(80)}).loose(),serverTime:Ms}).loose()}).loose(),Oi=d.z.enum(["stable","beta","alpha"]),_i=d.z.object({packageName:d.z.literal("@task-handoff/controlled-instance"),version:d.z.string().trim().min(1).max(80),platform:d.z.string().trim().min(1).max(40),arch:d.z.string().trim().min(1).max(40),formatVersion:d.z.number().int().positive(),launcherAbi:d.z.number().int().positive(),entrypoint:d.z.string().trim().min(1).max(512),sha256:d.z.string().regex(/^[a-f0-9]{64}$/)}).strict(),Pi=d.z.object({code:d.z.enum(["INSTANCE_RUNTIME_VERSION_MISMATCH","INSTANCE_RUNTIME_ARTIFACT_UNAVAILABLE","INSTANCE_RUNTIME_ARTIFACT_INVALID","INSTANCE_RUNTIME_INSTALL_FAILED","INSTANCE_RUNTIME_RESTART_FAILED","INSTANCE_RUNTIME_VERIFICATION_FAILED","INSTANCE_BASE_RUNTIME_INCOMPATIBLE","NODE_UPDATE_PREFLIGHT_FAILED","NODE_UPDATE_FAILED","LEGACY_INSTANCE_UPDATE_RETIRED"]),message:d.z.string().trim().min(1).max(4096),expectedVersion:d.z.string().trim().min(1).max(80).optional(),actualVersion:d.z.string().trim().min(1).max(80).optional(),retryable:d.z.boolean().default(!1)}).strict(),ji=d.z.object({desiredVersion:d.z.string().trim().min(1).max(80),actualVersion:d.z.string().trim().min(1).max(80).optional(),phase:d.z.enum(["pending","draining","installing","restarting","verifying","matched","failed"]),attempt:d.z.number().int().nonnegative().default(0),lastAttemptAt:Ms.optional(),matchedAt:Ms.optional(),error:Pi.optional()}).strict(),Di=d.z.object({runningInstanceCount:d.z.number().int().nonnegative(),stoppedInstanceCount:d.z.number().int().nonnegative(),activeInstanceCount:d.z.number().int().nonnegative(),restartInstanceCount:d.z.number().int().nonnegative(),runningInstanceIds:d.z.array(Ds).max(1024).default([]),stoppedInstanceIds:d.z.array(Ds).max(1024).default([]),activeInstanceIds:d.z.array(Ds).max(1024).default([])}).strict(),Mi=d.z.object({phase:d.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),desiredVersion:d.z.string().trim().min(1).max(80),nodeVersion:d.z.string().trim().min(1).max(80).optional(),expectedInstanceIds:d.z.array(Ds).max(1024).default([]),expectedInstanceCount:d.z.number().int().nonnegative(),matchedInstanceCount:d.z.number().int().nonnegative(),pendingInstanceCount:d.z.number().int().nonnegative(),failedInstanceCount:d.z.number().int().nonnegative(),deferredInstanceCount:d.z.number().int().nonnegative().default(0)}).strict(),Li=d.z.object({channel:Oi.default("stable")}).strict(),qi=d.z.object({source:d.z.literal("npm"),channel:Oi,currentVersion:d.z.string().trim().max(240).optional(),availableVersion:d.z.string().trim().min(1).max(240),artifactRef:d.z.string().trim().min(1).max(512).optional(),runtimeArtifacts:d.z.array(_i).default([]),impact:Di,updateAvailable:d.z.boolean(),supported:d.z.boolean().default(!0),reason:d.z.string().trim().max(2048).optional(),checkedAt:Ms,preflightToken:d.z.string().trim().min(16).max(240).optional()}).strict(),$i=d.z.object({id:Ds,nodeId:Ds,source:d.z.literal("npm"),channel:Oi,fromVersion:d.z.string().trim().max(240).optional(),toVersion:d.z.string().trim().min(1).max(240),artifactRef:d.z.string().trim().min(1).max(512).optional(),runtimeArtifacts:d.z.array(_i).default([]),impact:Di,rollout:Mi,status:d.z.enum(["queued","updating-node","restarting-node","converging-instances","succeeded","degraded","failed"]),error:Pi.optional(),startedAt:Ms.optional(),completedAt:Ms.optional(),createdAt:Ms,updatedAt:Ms}).strict(),Bi=d.z.object({channel:Oi,targetVersion:d.z.string().trim().min(1).max(240),preflightToken:d.z.string().trim().min(16).max(240)}).strict(),Fi=d.z.object({type:d.z.enum(["branch","tag","commit"]),name:d.z.string().trim().min(1).max(240).optional(),commit:d.z.string().trim().max(80).optional()}).strict(),Ui=d.z.object({type:d.z.enum(["none","ssh-key","https-token"]).default("none"),secretId:d.z.string().trim().min(1).max(120).optional()}).strict(),Hi=d.z.object({depth:d.z.number().int().positive().max(1e5).optional(),submodules:d.z.boolean().default(!1),lfs:d.z.boolean().default(!1),subdirectory:d.z.string().trim().max(240).default("")}).strict();d.z.object({id:Ds,name:d.z.string().trim().min(1).max(160),url:d.z.string().trim().min(1).max(2048),provider:d.z.string().trim().max(80).optional(),ref:Fi.default({type:"branch",name:"main"}),auth:Ui.default({type:"none"}),clone:Hi.default({submodules:!1,lfs:!1,subdirectory:""}),defaultImageSelection:Ys.optional(),labels:Ls,createdAt:Ms,updatedAt:Ms}).strict();const Wi=d.z.object({id:Ds,nodeId:Ds,name:d.z.string().trim().min(1).max(160),path:d.z.string().trim().min(1).max(4096),defaultImageSelection:Ys.optional(),labels:Ls,createdAt:Ms,updatedAt:Ms}).strict(),Gi=d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal("git-repository"),repositoryId:Ds.optional(),url:d.z.string().trim().min(1).max(2048),provider:d.z.string().trim().max(80).optional(),ref:Fi.default({type:"branch",name:"main"}),auth:Ui.default({type:"none"}),clone:Hi.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),d.z.object({type:d.z.literal("git-template"),url:d.z.string().trim().min(1).max(2048),templateId:d.z.string().trim().min(1).max(120).optional(),ref:Fi.default({type:"branch",name:"main"}),auth:Ui.default({type:"none"}),clone:Hi.default({submodules:!1,lfs:!1,subdirectory:""})}).strict(),d.z.object({type:d.z.literal("local-folder"),localFolderId:Ds.optional(),path:d.z.string().trim().min(1).max(4096),ownerNodeId:Ds.optional()}).strict()]),Vi=d.z.object({mode:d.z.enum(["local-bind","git-clone","empty-volume","persistent-volume"]),path:d.z.string().trim().min(1).max(4096).default("/workspace"),volumeName:d.z.string().trim().max(240).optional(),readOnly:d.z.boolean().default(!1)}).strict(),Ki=d.z.enum(["codex","claude"]),Ji=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(160),source:Gi,defaultImageSelection:Ys.optional(),defaultNodeId:Ds.optional(),defaultRuntimeId:Ds.optional(),workspacePolicy:Vi,labels:Ls,createdAt:Ms,updatedAt:Ms}).strict(),Yi=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(160),endpoint:d.z.string().trim().min(1).max(2048),key:d.z.string().trim().min(1).max(4096),model:d.z.string().trim().min(1).max(240),app:Ki,enabled:d.z.boolean().default(!0),order:d.z.number().int().min(0).max(1e6).default(0),labels:Ls,createdAt:Ms,updatedAt:Ms}).strict(),Qi=Yi.omit({key:!0}).extend({keyPreview:d.z.string().trim().min(1).max(160),keySet:d.z.boolean()}).strict(),Xi=Qi.extend({referenceCount:d.z.number().int().min(0)}).strict(),Zi=d.z.object({instanceId:Ds,codexModelHash:Ds.optional(),claudeModelHash:Ds.optional(),updatedAt:Ms}).strict(),er=d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal("control-plane"),name:Yi.shape.name,enabled:Yi.shape.enabled,order:Yi.shape.order}).strict(),d.z.object({type:d.z.literal("node"),nodeId:Ds,name:Yi.shape.name,enabled:Yi.shape.enabled,order:Yi.shape.order,referenceCount:d.z.number().int().min(0)}).strict()]),tr=d.z.object({id:Ds,model:Qi,locations:d.z.array(er).min(1),referenceCount:d.z.number().int().min(0).default(0)}).strict(),nr=d.z.object({nodeId:Ds,code:d.z.string().trim().min(1).max(120),message:d.z.string().trim().min(1).max(2e3)}).strict(),sr=d.z.object({models:d.z.array(tr),nodeDiagnostics:d.z.array(nr).default([]),updatedAt:Ms}).strict();function ir(e){const t={app:Ki.parse(e.app),endpoint:Yi.shape.endpoint.parse(e.endpoint),key:Yi.shape.key.parse(e.key),model:Yi.shape.model.parse(e.model)};return`mdl_${s.createHash("sha256").update(JSON.stringify(t)).digest("hex")}`}Yi.omit({id:!0,createdAt:!0,updatedAt:!0}).strict().partial().strict(),d.z.object({modelSelection:Js,codexModelHash:Ds.optional(),claudeModelHash:Ds.optional()}).strict();const rr=d.z.enum(["market","custom"]),or=d.z.enum(["active","deprecated","yanked"]),ar=d.z.discriminatedUnion("kind",[d.z.object({kind:d.z.literal("builtin"),key:d.z.string().trim().min(1).max(120)}).strict(),d.z.object({kind:d.z.literal("remote"),url:d.z.string().trim().url().max(2048),mediaType:d.z.enum(["image/png","image/jpeg","image/webp"]).optional(),digest:Ks.optional()}).strict()]),dr={kind:"builtin",key:"default-image-cover"},cr=d.z.array(d.z.string().trim().min(1).max(80)).default([]),lr=d.z.array(d.z.string().trim().min(1).max(120)).default([]),pr=d.z.record(d.z.string().trim().min(2).max(35),d.z.string().trim().min(1).max(4096)),ur=d.z.object({os:d.z.string().trim().min(1).max(40),architecture:d.z.string().trim().min(1).max(40),digest:Ks.optional(),downloadSizeBytes:d.z.number().int().positive().optional(),unpackedSizeBytes:d.z.number().int().positive().optional()}).strict(),hr=d.z.object({name:d.z.string().trim().min(1).max(128).regex(Bs),version:d.z.string().trim().min(1).max(160).optional(),reference:Vs,manifestDigest:Ks.optional(),publishedAt:Ms.optional(),platforms:d.z.array(ur).default([]),status:or.default("active")}).strict(),mr=d.z.object({id:Ds,publisher:d.z.string().trim().min(1).max(160),slug:d.z.string().trim().min(1).max(160),name:d.z.string().trim().min(1).max(160),description:d.z.string().trim().min(1).max(4096),localizedDescriptions:pr.optional(),cover:ar.optional(),repository:d.z.string().trim().min(1).max(512),defaultTag:d.z.string().trim().min(1).max(128).regex(Bs),tags:d.z.array(hr).min(1),capabilities:cr,optionalApps:lr,defaultEnv:qs,labels:Ls,status:or.default("active")}).strict().superRefine((e,t)=>{e.tags.some(t=>t.name===e.defaultTag)||t.addIssue({code:"custom",path:["defaultTag"],message:"Market defaultTag must identify one of the image tags."})}),gr=d.z.object({protocolVersion:Cs,catalogId:Ds,revision:d.z.string().trim().min(1).max(240),source:d.z.enum(["embedded","remote","cache"]),generatedAt:Ms,expiresAt:Ms.optional(),items:d.z.array(mr)}).strict(),yr=d.z.object({source:d.z.enum(["embedded","remote","cache"]),state:d.z.enum(["ready","refreshing","stale","failed"]),revision:d.z.string().trim().min(1).max(240),updatedAt:Ms,error:d.z.string().trim().max(4096).optional()}).strict(),fr=d.z.object({id:Ds,origin:d.z.literal("custom"),name:d.z.string().trim().min(1).max(160),description:d.z.string().trim().max(4096).optional(),localizedDescriptions:pr.optional(),cover:ar.optional(),reference:Vs,repository:d.z.string().trim().min(1).max(512),tag:d.z.string().trim().min(1).max(128).regex(Bs).optional(),pullPolicy:d.z.literal("if-not-present").default("if-not-present"),capabilities:cr,optionalApps:lr,defaultEnv:qs,labels:Ls,createdAt:Ms,updatedAt:Ms}).strict(),Ir=d.z.object({name:d.z.string().trim().min(1).max(128).regex(Bs),version:d.z.string().trim().min(1).max(160).optional(),reference:Vs,manifestDigest:Ks.optional(),status:or}).strict(),br=d.z.object({id:Ds,origin:rr,name:d.z.string().trim().min(1).max(160),description:d.z.string().trim().max(4096).optional(),localizedDescriptions:pr.optional(),cover:ar,repository:d.z.string().trim().min(1).max(512),tag:d.z.string().trim().min(1).max(128).regex(Bs).optional(),availableTags:d.z.array(Ir),reference:Vs,digest:Ks.optional(),downloadSizeBytes:d.z.number().int().positive().optional(),unpackedSizeBytes:d.z.number().int().positive().optional(),capabilities:cr,optionalApps:lr,defaultEnv:qs,labels:Ls,readOnly:d.z.boolean(),lifecycleStatus:or.optional(),market:d.z.object({catalogId:Ds,catalogRevision:d.z.string().trim().min(1).max(240),publisher:d.z.string().trim().min(1).max(160),version:d.z.string().trim().min(1).max(160).optional()}).strict().optional()}).strict(),vr=d.z.object({id:Ds,origin:rr,name:d.z.string().trim().min(1).max(160),description:d.z.string().trim().max(4096).optional(),localizedDescriptions:pr.optional(),cover:ar.optional(),repository:d.z.string().trim().min(1).max(512),tag:d.z.string().trim().min(1).max(128).regex(Bs).optional(),requestedReference:Vs,resolvedDigest:Ks.optional(),resolvedReference:Vs.optional(),downloadSizeBytes:d.z.number().int().positive().optional(),pullPolicy:d.z.literal("if-not-present").default("if-not-present"),capabilities:cr,optionalApps:lr,defaultEnv:qs,labels:Ls,market:d.z.object({catalogId:Ds,catalogRevision:d.z.string().trim().min(1).max(240),publisher:d.z.string().trim().min(1).max(160),version:d.z.string().trim().min(1).max(160).optional()}).strict().optional(),createdAt:Ms,updatedAt:Ms}).strict(),Sr=d.z.object({phase:d.z.enum(["checking-image","pulling-image","resolving-image","ready","failed"]),requestedReference:Vs,generation:d.z.number().int().nonnegative().default(0),error:d.z.string().trim().max(4096).optional(),startedAt:Ms,updatedAt:Ms}).strict(),wr="image.pull.terminal.output",Ar="image.pull.terminal.finished",zr=d.z.object({instanceId:Ds,generation:d.z.number().int().nonnegative(),requestedReference:Vs,sequence:d.z.number().int().nonnegative(),observedAt:Ms}).strict(),kr=zr.extend({data:d.z.string().min(1).max(65536),replay:d.z.boolean().optional()}).strict(),Tr=zr.extend({outcome:d.z.enum(["succeeded","failed"])}).strict(),Cr=zr.extend({status:d.z.enum(["connecting","pulling","extracting","complete","failed"]),layers:d.z.object({total:d.z.number().int().nonnegative(),completed:d.z.number().int().nonnegative(),downloaded:d.z.number().int().nonnegative(),downloading:d.z.number().int().nonnegative(),extracting:d.z.number().int().nonnegative()}).strict(),bytes:d.z.object({current:d.z.number().finite().nonnegative(),total:d.z.number().finite().positive()}).strict().optional(),percent:d.z.number().finite().min(0).max(100).optional(),message:d.z.string().trim().min(1).max(500),terminalTail:d.z.string().max(262144).optional(),terminalTruncated:d.z.boolean().optional()}).strict();function Er(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=new Set(["id","origin","name","description","localizedDescriptions","cover","reference","repository","tag","image","registry","pullPolicy","capabilities","optionalApps","defaultEnv","labels","createdAt","updatedAt"]);for(const e of Object.keys(n))s.has(e)||t?.({imageId:"string"==typeof n.id?n.id:void 0,field:e});const i="string"==typeof n.id?n.id:void 0,r="string"==typeof n.image?n.image:void 0;void 0!==r&&t?.({imageId:i,field:"image"}),Object.prototype.hasOwnProperty.call(n,"registry")&&t?.({imageId:i,field:"registry"});let o,a="string"==typeof n.reference?n.reference:r;if(a)try{a=Ws(a)}catch{if(!a.includes("@")&&a.lastIndexOf(":")<=a.lastIndexOf("/"))try{a=Ws(`${a}:latest`),t?.({imageId:i,field:"reference:implicit-latest"})}catch{}}try{o=a?Gs(a):void 0}catch{}return{id:n.id,origin:"custom",name:n.name,description:n.description,localizedDescriptions:n.localizedDescriptions,cover:io(n.cover,["kind","key","url","mediaType","digest"]),reference:o?.reference??a,repository:o?.repository??n.repository,tag:o?.tag??n.tag,pullPolicy:n.pullPolicy??"if-not-present",capabilities:n.capabilities,optionalApps:n.optionalApps,defaultEnv:n.defaultEnv,labels:n.labels,createdAt:n.createdAt,updatedAt:n.updatedAt}}const xr=d.z.discriminatedUnion("kind",[d.z.object({kind:d.z.literal("direct")}).strict(),d.z.object({kind:d.z.literal("control-plane-proxy"),proxyId:Ds,proxyBindingId:Ds,targetNodeId:Ds}).strict()]);d.z.object({pingRttMs:d.z.number().nonnegative().optional(),pingRttP95Ms:d.z.number().nonnegative().optional(),consecutiveReconnects:d.z.number().int().nonnegative(),nextRetryAt:Ms.optional()}).strict();const Nr=d.z.object({reachability:d.z.enum(["unknown","reachable","unreachable"]),bindingStatus:d.z.enum(["unknown","active","revoked"]),bindingRevision:d.z.number().int().positive().optional(),streamId:d.z.string().trim().min(1).max(160).optional(),revision:d.z.number().int().nonnegative().optional(),observedAt:Ms.optional(),target:ys.optional(),lastError:as.optional(),updatedAt:Ms}).strict(),Rr=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(160),connectionMode:d.z.enum(["local-ipc","local-loopback","direct-http","reverse-wss","control-plane-proxy"]).default("direct-http"),connectionPath:xr.default({kind:"direct"}),connectionEnabled:d.z.boolean().default(!0),auth:d.z.object({mode:d.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Ds.optional(),secret:d.z.string().trim().max(4096).optional(),pairedAt:Ms.optional(),pairing:d.z.object({status:d.z.enum(["pending","paired","expired"]).default("pending"),joinToken:d.z.string().trim().max(4096).optional(),expiresAt:Ms.optional()}).strict().optional()}).strict().default({mode:"local-static-key"}),endpoint:d.z.string().trim().max(2048).optional(),controlEndpoint:d.z.string().trim().max(2048).optional(),containerEndpoint:d.z.string().trim().max(2048).optional(),publicWebBase:d.z.string().trim().max(2048).optional(),status:d.z.enum(["unknown","online","offline","degraded"]).default("unknown"),health:d.z.enum(["unknown","ok","degraded","failed"]).default("unknown"),capabilities:d.z.record(d.z.string(),d.z.unknown()).default({}),proxyState:Nr.optional(),appInventory:ui.optional(),labels:Ls,lastSeenAt:Ms.optional(),createdAt:Ms,updatedAt:Ms}).strict().superRefine((e,t)=>{"control-plane-proxy"===e.connectionPath.kind&&"control-plane-proxy"!==e.connectionMode&&t.addIssue({code:"custom",path:["connectionPath"],message:"Control-plane proxy paths require control-plane-proxy connection mode."}),"control-plane-proxy"===e.connectionMode&&"control-plane-proxy"!==e.connectionPath.kind&&t.addIssue({code:"custom",path:["connectionPath"],message:"Control-plane proxy nodes require a control-plane-proxy connection path."})}),Or=d.z.object({id:Ds,nodeId:Ds,name:d.z.string().trim().min(1).max(160),type:d.z.enum(["docker","kubernetes","local"]),status:d.z.enum(["unknown","online","offline","degraded"]).default("unknown"),accessStrategy:d.z.enum(["node-proxy","direct-port","kubernetes-ingress","kubernetes-port-forward"]).default("node-proxy"),capabilities:d.z.record(d.z.string(),d.z.unknown()).default({}),labels:Ls,createdAt:Ms,updatedAt:Ms}).strict(),_r=d.z.object({instanceId:Ds,runtimeKind:d.z.literal("docker"),state:d.z.enum(["pending","available","stopped","unavailable"]),sampledAt:Ms,cpu:d.z.object({usagePercent:d.z.number().nonnegative()}).strict().optional(),memory:d.z.object({usageBytes:d.z.number().nonnegative(),limitBytes:d.z.number().nonnegative().optional(),usagePercent:d.z.number().nonnegative().optional()}).strict().optional(),network:d.z.object({rxBytes:d.z.number().nonnegative(),txBytes:d.z.number().nonnegative()}).strict().optional(),blockIo:d.z.object({readBytes:d.z.number().nonnegative(),writeBytes:d.z.number().nonnegative()}).strict().optional(),pids:d.z.number().int().nonnegative().optional(),error:d.z.string().trim().max(2048).optional()}).strict(),Pr=d.z.object({modelEndpointProbe:d.z.boolean().optional(),aiSessionHistoryLimit:d.z.boolean().optional(),aiSessionAttachmentRetention:d.z.boolean().optional(),folderPlaces:d.z.boolean().optional(),localFolderNameUpdate:d.z.boolean().optional()}).strip(),jr=d.z.object({ok:d.z.boolean().optional(),role:d.z.string().optional(),nodeId:Ds.optional(),platform:Zs.optional(),arch:ei.optional(),protocolVersion:Cs.optional(),capabilities:Pr.optional(),build:Ni.strip().optional(),process:d.z.object({pid:d.z.number().int().positive(),startIdentity:d.z.string().trim().min(1).optional()}).strip().optional(),listener:d.z.object({host:d.z.string().trim().min(1),port:d.z.number().int().min(1).max(65535)}).strip().optional(),instanceProxy:d.z.object({requests:d.z.number().int().nonnegative(),active:d.z.number().int().nonnegative(),completed:d.z.number().int().nonnegative(),aborted:d.z.number().int().nonnegative(),limitRejected:d.z.number().int().nonnegative(),responseBytes:d.z.number().nonnegative(),totalDurationMs:d.z.number().nonnegative(),maxResponseBytes:d.z.number().int().nonnegative()}).partial().strip().optional(),serverTime:Ms.optional()}).strip(),Dr=d.z.object({bindScope:d.z.enum(["loopback","all-ipv4"]),port:d.z.number().int().min(1).max(65535)}).strict().extend({host:d.z.enum(["127.0.0.1","0.0.0.0"]),status:d.z.enum(["listening","error"]),source:d.z.enum(["bootstrap","persisted"]),error:d.z.string().trim().max(2048).optional()}).strict(),Mr=d.z.object({nodeId:Ds,joinToken:d.z.string().trim().min(1),expiresAt:Ms}).passthrough(),Lr=d.z.object({nodeId:Ds,keyId:Ds,secret:d.z.string().regex(/^[A-Za-z0-9_-]{32,128}$/),pairedAt:Ms}).strict(),qr=d.z.object({id:Ds,keyId:Ds,name:d.z.string().trim().min(1).max(160).optional(),pairedAt:Ms,updatedAt:Ms,current:d.z.boolean()}).passthrough(),$r=d.z.object({keyId:Ds,revoked:d.z.literal(!0),revokedAt:Ms}).strict(),Br=d.z.object({id:Ds,pairingKeyId:Ds,url:d.z.string().trim().min(1).max(2048),name:d.z.string().trim().min(1).max(160).optional(),enabled:d.z.boolean(),createdAt:Ms,updatedAt:Ms,status:d.z.enum(["disabled","connecting","connected","reconnecting","failed"]),pingRttMs:d.z.number().nonnegative().optional(),pingRttP95Ms:d.z.number().nonnegative().optional(),consecutiveReconnects:d.z.number().int().nonnegative().optional(),nextRetryAt:Ms.optional(),lastConnectedAt:Ms.optional(),lastDisconnectedAt:Ms.optional(),error:d.z.string().optional()}).passthrough(),Fr=d.z.object({pairing:qr,connection:d.z.object({id:Ds,pairingKeyId:Ds,url:d.z.string().trim().min(1).max(2048),name:d.z.string().trim().min(1).max(160).optional(),enabled:d.z.boolean(),createdAt:Ms,updatedAt:Ms}).passthrough(),tunnel:d.z.object({status:d.z.enum(["disabled","saved","connecting","connected","failed"]),error:d.z.string().trim().max(2048).optional()}).passthrough()}).passthrough(),Ur=d.z.object({deleted:d.z.boolean().optional()}).passthrough(),Hr=d.z.object({repository:d.z.string().trim().optional(),tag:d.z.string().trim().optional(),id:d.z.string().trim(),createdSince:d.z.string().trim().optional(),size:d.z.string().trim().optional(),sizeBytes:d.z.number().int().nonnegative().optional(),reference:d.z.string().trim().min(1),repoDigests:d.z.array(d.z.string().trim().min(1).max(512)).default([])}).passthrough(),Wr=d.z.object({image:br,status:d.z.enum(["available","pull-required","unknown"]),localImage:Hr.optional(),localSizeBytes:d.z.number().int().nonnegative().optional(),downloadSizeBytes:d.z.number().int().positive().optional(),unpackedSizeBytes:d.z.number().int().positive().optional(),error:d.z.string().trim().max(2048).optional()}).strict(),Gr=d.z.lazy(()=>d.z.object({name:d.z.string().trim().min(1),path:d.z.string().trim().min(1).max(4096),children:d.z.array(Gr)}).passthrough()),Vr=d.z.object({kind:d.z.enum(["home","root"]),name:d.z.string().trim().min(1),path:d.z.string().trim().min(1).max(4096)}).passthrough(),Kr=d.z.object({status:d.z.number().int().min(100).max(599).optional(),headers:d.z.record(d.z.string(),d.z.string()).optional(),bodyBase64:d.z.string().optional()}).passthrough(),Jr=d.z.object({strategy:d.z.enum(["node-proxy","direct-port","kubernetes-ingress","kubernetes-port-forward"]).default("node-proxy"),web:d.z.string().trim().max(2048).optional(),api:d.z.string().trim().max(2048).optional(),vnc:d.z.string().trim().max(2048).optional(),tty:d.z.string().trim().max(2048).optional(),logs:d.z.string().trim().max(2048).optional(),status:d.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown")}).strict(),Yr=d.z.object({...Jr.shape}).strict(),Qr=d.z.object({strategy:d.z.enum(["control-plane-proxy","direct-port","node-proxy","kubernetes-ingress","kubernetes-port-forward"]).default("control-plane-proxy"),web:d.z.string().trim().max(2048).optional(),api:d.z.string().trim().max(2048).optional(),ws:d.z.string().trim().max(2048).optional(),status:d.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown")}).strict().default({strategy:"control-plane-proxy",status:"unknown"}),Xr=d.z.object({mode:d.z.enum(["local-bind","git-clone","empty-volume","persistent-volume"]).optional(),status:d.z.enum(["unknown","pending","ready","failed"]).default("unknown"),path:d.z.string().trim().max(4096).optional(),resolvedCommit:d.z.string().trim().max(120).optional(),error:d.z.string().trim().max(2048).optional()}).passthrough(),Zr=d.z.object({id:Ds,name:d.z.string().trim().min(1).max(160),projectId:Ds.optional(),source:Gi,sourceSnapshot:d.z.record(d.z.string(),d.z.unknown()).default({}),modelSelection:Js,nodeId:Ds,runtimeId:Ds,imageSelection:Ys.optional(),environmentSource:Qs.optional(),environmentTemplateOrigin:ni.optional(),imageSnapshot:vr.optional(),imageProvisioning:Sr.optional(),stateRevision:d.z.number().int().min(0).default(0),processIncarnationId:d.z.string().trim().min(1).max(120).optional(),status:d.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]).default("created"),health:d.z.enum(["unknown","ok","degraded","failed"]).default("unknown"),connectionStatus:d.z.enum(["unknown","online","offline","endpoint-unreachable"]).default("unknown"),agentStatus:d.z.enum(["unknown","online","offline"]).default("unknown"),targetStatus:d.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown"),uiAccessStatus:d.z.enum(["unknown","reachable","endpoint-unreachable"]).default("unknown"),controlMode:d.z.enum(["standalone","controlled"]).default("controlled"),protocolVersion:Cs.optional(),instanceVersion:d.z.string().trim().max(80).optional(),build:Ni.optional(),runtimeVersion:ji.optional(),ready:d.z.boolean().default(!1),capabilities:_s.default(xs),appInventory:ui.optional(),config:d.z.object({autoImportAgentConfigs:d.z.boolean().default(!0),defaultCodexPermissionMode:we.default("ask"),aiSessionHistoryLimit:d.z.number().int().min(1).max(at).default(50),aiSessionAttachmentRetentionDays:d.z.number().int().min(0).max(365).default(30)}).strict().default({autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask",aiSessionHistoryLimit:50,aiSessionAttachmentRetentionDays:30}),workspace:Xr.default({status:"unknown"}),target:Jr.default({strategy:"direct-port",status:"unknown"}),access:Qr,apps:d.z.object({runningCount:d.z.number().int().min(0).default(0),problemCount:d.z.number().int().min(0).default(0),updatedAt:Ms.optional(),revision:d.z.number().int().min(0).optional()}).strict().default({runningCount:0,problemCount:0}),aiSessions:mt.default(()=>({runningCount:0,waitingCount:0,staleCount:0,sessions:[],updatedAt:(new Date).toISOString()})),triggers:d.z.object({enabledCount:d.z.number().int().min(0).default(0),runningCount:d.z.number().int().min(0).default(0),errorCount:d.z.number().int().min(0).default(0),configs:d.z.array(d.z.object({configHash:d.z.string().trim().min(1),config:On,deployments:d.z.array(Pn).default([]),runtime:d.z.array(jn).default([])}).strict()).default([]),recentRuns:d.z.array(Dn).default([])}).strict().optional(),runtime:d.z.object({kind:d.z.string().trim().max(80).optional(),containerName:d.z.string().trim().max(240).optional(),containerId:d.z.string().trim().max(240).optional(),workspacePath:d.z.string().trim().max(4096).optional(),pid:d.z.number().int().positive().optional(),port:d.z.number().int().positive().max(65535).optional(),labels:d.z.record(d.z.string(),d.z.string()).default({})}).strict().default({labels:{}}),registrationToken:d.z.string().trim().min(1).max(240).optional(),lastHeartbeatAt:Ms.optional(),createdAt:Ms,updatedAt:Ms}).strict(),eo="instance.lifecycle.snapshot",to=d.z.object({instanceId:Zr.shape.id,revision:d.z.number().int().min(0),updatedAt:Ms,status:Zr.shape.status.unwrap(),health:Zr.shape.health.unwrap(),connectionStatus:Zr.shape.connectionStatus.unwrap(),accessStatus:d.z.enum(["reachable","endpoint-unreachable"]),imageProvisioning:Sr.optional(),workspace:Xr,runtime:Zr.shape.runtime.unwrap(),runtimeVersion:ji.optional(),ready:d.z.boolean(),lastHeartbeatAt:Ms.optional()}).strict();function no(e,t,n,s,i){if(!t||"object"!=typeof t||Array.isArray(t))return;let r=structuredClone(t);for(let t=0;t<20;t+=1){const t=e.safeParse(r);if(t.success)return t.data;let n=!1;for(const e of t.error.issues){if("unrecognized_keys"!==e.code)continue;const t=so(r,e.path);if(t&&"object"==typeof t&&!Array.isArray(t))for(const s of e.keys)Object.prototype.hasOwnProperty.call(t,s)&&(delete t[s],n=!0)}if(!n){const n=structuredClone(r);let s=!1;for(const e of t.error.issues){if(!e.path.length||"string"!=typeof e.path.at(-1))continue;const t=so(n,e.path.slice(0,-1)),i=e.path.at(-1);t&&"object"==typeof t&&!Array.isArray(t)&&Object.prototype.hasOwnProperty.call(t,i)&&(delete t[i],s=!0)}if(s){const t=e.safeParse(n);if(t.success)return t.data}break}}}function so(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function io(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e;return Object.fromEntries(t.filter(e=>Object.prototype.hasOwnProperty.call(n,e)).map(e=>[e,n[e]]))}d.z.object({instanceId:Ds.optional(),projectId:Ds.optional(),source:Gi.optional(),nodeId:Ds.optional(),runtimeId:Ds.optional(),imageSelection:Ys.optional(),instanceVersion:d.z.string().trim().max(80).optional(),protocolVersion:Cs,build:Ni.optional(),controlMode:d.z.enum(["standalone","controlled"]).default("controlled"),capabilities:_s.default(xs),appInventory:ui.optional(),target:Yr.optional(),workspace:Xr.default({status:"unknown"}),registrationToken:d.z.string().trim().max(240).optional(),processIncarnationId:d.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{Ts.has(e.protocolVersion)&&!e.appInventory&&t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol register payload requires appInventory."})}),d.z.object({status:Zr.shape.status.optional(),health:Zr.shape.health.optional(),protocolVersion:Cs,build:Ni.optional(),capabilities:Zr.shape.capabilities.optional(),appInventory:ui.optional(),apps:Zr.shape.apps.optional(),aiSessions:Zr.shape.aiSessions.optional(),triggers:Zr.shape.triggers.optional(),workspace:Xr.optional(),target:Yr.optional(),processIncarnationId:d.z.string().trim().min(1).max(120).optional()}).strict().superRefine((e,t)=>{Ts.has(e.protocolVersion)&&!e.appInventory&&t.addIssue({code:"custom",path:["appInventory"],message:"Current protocol heartbeat payload requires appInventory."})});const ro=d.z.enum(["web","telegram","wechat","dingding","lark"]),oo=d.z.object({id:Ds,channel:ro,name:d.z.string().trim().min(1).max(160),enabled:d.z.boolean().default(!1),token:d.z.string().trim().max(4096).optional(),defaultChatId:d.z.string().trim().max(240).optional(),allowedUserIds:d.z.array(d.z.string().trim().min(1).max(240)).default([]),pollIntervalMs:d.z.number().int().positive().max(6e4).default(3e3),settings:d.z.record(d.z.string(),d.z.unknown()).default({}),createdAt:Ms,updatedAt:Ms}).strict(),ao=d.z.object({id:Ds,channel:ro,bridgeId:Ds.optional(),chatSessionId:d.z.string().trim().min(1).max(240),userId:d.z.string().trim().max(240).optional(),activeProjectId:Ds.optional(),activeInstanceId:Ds.optional(),activeAiSessionId:d.z.string().trim().min(1).max(120).optional(),lastUsedAt:Ms,createdAt:Ms,updatedAt:Ms}).strict(),co=d.z.object({source:d.z.object({type:d.z.literal("chat-gateway").default("chat-gateway"),channel:ro,bridgeId:Ds.optional(),chatSessionId:d.z.string().trim().min(1).max(240),userId:d.z.string().trim().max(240).optional()}).strict(),message:d.z.object({text:d.z.string().trim().max(2e4).default(""),attachments:d.z.array(Ie).max(6).default([])}).strict().superRefine((e,t)=>{e.attachments.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>R&&t.addIssue({code:d.z.ZodIssueCode.custom,path:["attachments"],message:"Inline attachments must be 41943040 bytes or less in total."})}),target:d.z.object({instanceId:Ds,aiSessionId:d.z.string().trim().min(1).max(120)}).strict().optional()}).strict(),lo=d.z.object({id:Ds,instanceId:Ds,projectId:Ds.optional(),aiSessionId:d.z.string().trim().min(1).max(120),providerSessionId:d.z.string().trim().max(240).optional(),result:d.z.string().default(""),timeoutMs:d.z.number().positive().optional(),source:d.z.string().trim().max(120).optional(),kind:d.z.enum(["task","approval"]).default("task"),status:d.z.enum(["pending","unreachable"]).default("pending"),error:d.z.string().trim().max(2048).optional(),lastSeenAt:Ms}).strict();function po(e){return!1!==e.ready&&(!e.runtimeVersion||["matched","failed"].includes(e.runtimeVersion.phase))}const uo=6048e5;function ho(e,n){const s=t.resolve(e),i=t.resolve(s,n);if(t.dirname(i)!==s||t.basename(i)!==n)throw new Error(`Retention entry is not a direct child of its managed root: ${n}`);return i}function mo(e){if(n.existsSync(e)){const t=n.lstatSync(e);if(!t.isDirectory()||t.isSymbolicLink())throw new Error(`Managed persistence path must be a real directory: ${e}`)}n.mkdirSync(e,{recursive:!0,mode:448}),n.chmodSync(e,448)}function go(e){return e.startsWith("ai-session.")||e.startsWith("ai.session.")?"ai.sessions":e.startsWith("app-session.")?"app.sessions":e.startsWith("app.management")?"apps":e.startsWith("trigger.")?"triggers":e.startsWith("instance.")?"instances":e.startsWith("node.")?"nodes":e.startsWith("project.")?"projects":e.startsWith("model.")?"models":e.startsWith("image.")?"images":e.startsWith("market.")?"market":"system"}const yo=d.z.object({replaySince:d.z.string().datetime().optional(),messageDeltas:d.z.object({allInstances:d.z.boolean().default(!1),instanceIds:d.z.array(d.z.string().trim().min(1).max(160)).max(1e3).default([])}).default({allInstances:!1,instanceIds:[]}),timelineAllSessions:d.z.boolean().default(!1),timelineSessions:d.z.array(d.z.object({instanceId:d.z.string().trim().min(1).max(160),sessionId:d.z.string().trim().min(1).max(120)})).max(1e3).default([])});function fo(e,t){if(!e)return!0;if("ai-session.message-delta"!==t.type&&"ai-session.timeline-item"!==t.type)return!0;const n=t.payload&&"object"==typeof t.payload&&!Array.isArray(t.payload)?t.payload:{},s=String(n.instanceId||t.scope?.instanceId||"");return"ai-session.message-delta"===t.type?e.messageDeltas.allInstances||e.messageDeltas.instanceIds.includes(s):e.timelineAllSessions||e.timelineSessions.some(e=>e.instanceId===s&&e.sessionId===n.sessionId)}const Io=d.z.enum(["ai.sessions","app.sessions"]),bo=d.z.object({topic:Io,instanceId:d.z.string().trim().min(1).max(160),streamId:d.z.string().trim().min(1).max(240),latestRevision:d.z.number().int().min(0),earliestRetainedRevision:d.z.number().int().min(0)}).strict(),vo=d.z.object({protocolVersion:d.z.literal(1),streams:d.z.array(bo)}).strict(),So=d.z.object({authentication:d.z.enum(["required","disabled"]),aiSessions:d.z.boolean(),nodes:d.z.boolean(),instanceBoard:d.z.boolean(),triggers:d.z.boolean().optional()}).strict(),wo=d.z.object({version:d.z.literal(1),kind:d.z.literal("control-plane"),controlPlaneId:d.z.string().trim().min(1).max(160),publicKey:d.z.object({algorithm:d.z.literal("Ed25519"),encoding:d.z.literal("base64url"),value:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/),fingerprint:d.z.string().regex(/^sha256:[A-Za-z0-9_-]{43}$/)}).strict(),capabilities:So,protocolVersion:d.z.string().regex(/^\d{4}-\d{2}-\d{2}$/),issuedAt:d.z.string().datetime(),expiresAt:d.z.string().datetime()}).strict(),Ao=d.z.object({data:d.z.object({payload:wo,signature:d.z.string().regex(/^[A-Za-z0-9_-]{86}$/)}).strict()}).strict(),zo=d.z.object({id:d.z.string().trim().min(8).max(160),name:d.z.string().trim().min(1).max(160),platform:d.z.enum(["ios","android"]),appVersion:d.z.string().trim().min(1).max(80).optional()}).strict(),ko=d.z.object({username:d.z.string().trim().min(1).max(80),password:d.z.string().min(1).max(4096),device:zo}).strict(),To=d.z.object({id:d.z.string().trim().min(1),username:d.z.string().trim().min(1).max(80),role:d.z.enum(["viewer","operator","admin"]),createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime(),lastLoginAt:d.z.string().datetime().optional()}).strict(),Co=d.z.object({id:d.z.string().trim().min(1),expiresAt:d.z.string().datetime(),createdAt:d.z.string().datetime(),lastSeenAt:d.z.string().datetime().optional(),device:zo,user:To}).strict();function Eo(){return(new Date).toISOString()}d.z.object({data:d.z.object({sessionToken:d.z.string().trim().min(32),session:Co}).strict()}).strict(),d.z.object({data:d.z.array(Co)}).strict(),d.z.object({data:d.z.object({revoked:d.z.boolean()}).strict()}).strict();function xo(e,t=448){n.mkdirSync(e,{recursive:!0,mode:t}),n.chmodSync(e,t)}function No(e,s,i={}){const r=i.directoryMode??448,o=i.fileMode??384;xo(t.dirname(e),r),l.sync(e,`${JSON.stringify(s,null,2)}\n`,{encoding:"utf8",mode:o}),n.chmodSync(e,o)}function Ro(e,t){console.warn(JSON.stringify({message:e,...t}))}function Oo(e){return e&&"object"==typeof e&&"issues"in e?{issues:e.issues}:{error:e instanceof Error?e.message:String(e)}}function _o(e,t){const s=t.logger||Ro;let i;try{i=JSON.parse(n.readFileSync(e,"utf8"))}catch(t){return void s("stored JSON could not be read",{filePath:e,...Oo(t)})}if(!t.schema)return i;const r=t.sanitize?t.sanitize(i):i,o=t.schema.safeParse(r);if(o.success)return o.data;const a="strip"in t.schema&&"function"==typeof t.schema.strip?t.schema.strip().safeParse(r):void 0;if(a?.success)return s("unknown stored fields were ignored",{filePath:e,issues:o.error.issues}),a.data;s("stored record failed validation and was isolated",{filePath:e,issues:o.error.issues})}function Po(e){return`${e}_${s.randomUUID().replace(/-/g,"").slice(0,20)}`}function jo(){return s.randomBytes(24).toString("base64url")}class Do{directory;options;permissionsInitialized=!1;constructor(e,t={}){this.directory=e,this.options=t}init(){if(this.permissionsInitialized&&n.existsSync(this.directory))return;xo(this.directory,this.options.directoryMode??448);const e=this.options.fileMode??384;for(const s of n.readdirSync(this.directory).filter(e=>e.endsWith(".json")))n.chmodSync(t.join(this.directory,s),e);this.permissionsInitialized=!0}filePath(e){return t.join(this.directory,`${e}.json`)}list(){return this.init(),n.readdirSync(this.directory).filter(e=>e.endsWith(".json")).sort().flatMap(e=>{const n=_o(t.join(this.directory,e),this.options);return n?[n]:[]})}get(e){this.init();const t=this.filePath(e);return n.existsSync(t)?_o(t,this.options):void 0}put(e){const t=this.options.sanitize?this.options.sanitize(e):e,n=this.options.schema?this.options.schema.parse(t):t;return No(this.filePath(n.id),n,this.options),n}patch(e,t){const n=this.get(e);if(!n)return;const s={...n,...t,id:n.id,createdAt:n.createdAt,updatedAt:(new Date).toISOString()};return this.put(s)}delete(e){const t=this.filePath(e);return!!n.existsSync(t)&&(n.unlinkSync(t),!0)}}class Mo{filePathValue;defaults;options;constructor(e,t,n={}){this.filePathValue=e,this.defaults=t,this.options=n}init(){xo(t.dirname(this.filePathValue),this.options.directoryMode??448),n.existsSync(this.filePathValue)?n.chmodSync(this.filePathValue,this.options.fileMode??384):this.put(this.defaults())}get(){return this.init(),n.existsSync(this.filePathValue)?_o(this.filePathValue,this.options)??this.defaults():this.defaults()}put(e){const t=this.options.sanitize?this.options.sanitize(e):e,n=this.options.schema?this.options.schema.parse(t):t;return No(this.filePathValue,n,this.options),n}}const Lo=c.promisify(s.scrypt),qo="task_handoff_cp_session",$o=d.z.enum(["disabled","password"]),Bo=d.z.string().trim().min(1).max(80).regex(/^[a-zA-Z0-9_.@-]+$/),Fo=d.z.string().min(8).max(4096),Uo=d.z.object({username:Bo,password:Fo}).strict(),Ho=d.z.object({username:d.z.string().trim().min(1).max(80),password:d.z.string().min(1).max(4096)}).strict(),Wo=d.z.object({currentPassword:d.z.string().min(1).max(4096),newPassword:Fo}).strict(),Go=d.z.object({username:Bo,password:Fo}).strict(),Vo=d.z.object({id:d.z.string().trim().min(1),createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime()}),Ko=Vo.extend({username:Bo,passwordHash:d.z.string().trim().min(1),role:d.z.enum(["viewer","operator","admin"]),lastLoginAt:d.z.string().datetime().optional()}).strict(),Jo=Vo.extend({userId:d.z.string().trim().min(1),tokenHash:d.z.string().trim().min(1),expiresAt:d.z.string().datetime(),lastSeenAt:d.z.string().datetime().optional(),clientType:d.z.enum(["web","mobile"]).default("web"),device:zo.optional()}).strict().refine(e=>"mobile"!==e.clientType||Boolean(e.device),{path:["device"],message:"Mobile sessions require device metadata."});function Yo(e,t){return Number.isInteger(e)&&Number(e)>0?Number(e):t}class Qo{options;sourceFailures=new Map;usernameFailures=new Map;concurrent=0;constructor(e={}){this.options=function(e={}){return{windowMs:Yo(e.windowMs,9e5),maxFailuresPerSource:Yo(e.maxFailuresPerSource,20),maxFailuresPerUsername:Yo(e.maxFailuresPerUsername,10),maxConcurrent:Yo(e.maxConcurrent,4)}}(e)}begin(e,t){const n=Date.now();if(this.assertBucketAvailable(this.sourceFailures,e,this.options.maxFailuresPerSource,n),this.assertBucketAvailable(this.usernameFailures,t,this.options.maxFailuresPerUsername,n),this.concurrent>=this.options.maxConcurrent)throw Xo("Too many password verifications are already in progress.",1e3);this.concurrent+=1}finish(){this.concurrent=Math.max(0,this.concurrent-1)}recordFailure(e,t){const n=Date.now();this.record(this.sourceFailures,e,n),this.record(this.usernameFailures,t,n),this.sourceFailures.size+this.usernameFailures.size>1e4&&(this.pruneAll(n),this.trimOldest(this.sourceFailures,5e3),this.trimOldest(this.usernameFailures,5e3))}assertBucketAvailable(e,t,n,s){const i=this.currentFailures(e,t,s);if(!(i.length<n))throw Xo("Too many failed sign-in attempts. Try again later.",i[0]+this.options.windowMs-s)}record(e,t,n){const s=this.currentFailures(e,t,n);s.push(n),e.set(t,s)}currentFailures(e,t,n){const s=n-this.options.windowMs,i=(e.get(t)||[]).filter(e=>e>s);return i.length?e.set(t,i):e.delete(t),i}pruneAll(e){for(const[t]of this.sourceFailures)this.currentFailures(this.sourceFailures,t,e);for(const[t]of this.usernameFailures)this.currentFailures(this.usernameFailures,t,e)}trimOldest(e,t){for(;e.size>t;){const t=e.keys().next().value;if(void 0===t)return;e.delete(t)}}}function Xo(e,t){const n=new Error(e);return Object.assign(n,{statusCode:429,code:"AUTH_LOGIN_RATE_LIMITED",retryable:!0,retryAfterSeconds:Math.max(1,Math.ceil(t/1e3))}),n}function Zo(e){return s.createHash("sha256").update(e).digest("base64url")}async function ea(e){const t=s.randomBytes(16).toString("base64url");return`scrypt$${t}$${(await Lo(e,t,64)).toString("base64url")}`}async function ta(e,t){const[n,i,r]=t.split("$");if("scrypt"!==n||!i||!r)return!1;const o=await Lo(e,i,64),a=Buffer.from(r,"base64url");return a.length===o.length&&s.timingSafeEqual(a,o)}function na(e){return{id:e.id,username:e.username,role:e.role,createdAt:e.createdAt,updatedAt:e.updatedAt,lastLoginAt:e.lastLoginAt}}function sa(e,t){return Co.parse({id:e.id,expiresAt:e.expiresAt,createdAt:e.createdAt,lastSeenAt:e.lastSeenAt,device:e.device,user:na(t)})}class ia{mode;users;sessions;loginRateLimiter;bootstrapAdminInProgress=!1;credentialUpdateInProgress=!1;constructor(e,t={}){this.mode=function(e={}){return $o.parse(e.mode||process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"disabled")}(t),this.users=new Do(e.authUsersDir,{schema:Ko}),this.sessions=new Do(e.authSessionsDir,{schema:Jo}),this.loginRateLimiter=new Qo(t.loginRateLimit)}init(){this.users.init(),this.sessions.init()}enabled(){return"password"===this.mode}state(){return{mode:this.mode,enabled:this.enabled(),requiresBootstrap:this.enabled()&&0===this.users.list().length}}async bootstrapAdmin(e){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}if(this.bootstrapAdminInProgress){const e=new Error("Control Plane admin initialization is already in progress.");throw Object.assign(e,{statusCode:409,code:"AUTH_BOOTSTRAP_IN_PROGRESS"}),e}if(this.users.list().length>0){const e=new Error("Control Plane admin user already exists.");throw Object.assign(e,{statusCode:409,code:"AUTH_BOOTSTRAP_ALREADY_DONE"}),e}const t=Uo.parse(e);this.bootstrapAdminInProgress=!0;try{const e=Eo();return na(this.users.put({id:Po("user"),username:t.username,passwordHash:await ea(t.password),role:"admin",createdAt:e,updatedAt:e}))}finally{this.bootstrapAdminInProgress=!1}}async login(e,t={}){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}const n=Ho.parse(e),s=await this.authenticate(n.username,n.password,t),i=this.createSession(s,"web");return{user:na(s),sessionToken:i.token,expiresAt:i.record.expiresAt}}async loginMobile(e,t={}){const n=ko.parse(e),s=await this.authenticate(n.username,n.password,t),i=this.createSession(s,"mobile",n.device);return{sessionToken:i.token,session:sa(i.record,s)}}async changePassword(e,t,n={}){const s=this.resolveSessionToken(e,"web");if(!s){const e=new Error("Sign in to change the password.");throw Object.assign(e,{statusCode:401,code:"CONTROL_PLANE_AUTH_REQUIRED"}),e}const i=Wo.parse(t);if(this.credentialUpdateInProgress){const e=new Error("Control Plane credentials are already being updated.");throw Object.assign(e,{statusCode:409,code:"AUTH_CREDENTIAL_UPDATE_IN_PROGRESS"}),e}this.credentialUpdateInProgress=!0;const r=String(n.sourceId||"unknown").trim()||"unknown",o=s.storedUser.username.toLocaleLowerCase("en-US");let a=!1;try{if(this.loginRateLimiter.begin(r,o),a=!0,!await ta(i.currentPassword,s.storedUser.passwordHash)){this.loginRateLimiter.recordFailure(r,o);const e=new Error("The current password is incorrect.");throw Object.assign(e,{statusCode:400,code:"AUTH_CURRENT_PASSWORD_INVALID"}),e}if(await ta(i.newPassword,s.storedUser.passwordHash)){const e=new Error("The new password must be different from the current password.");throw Object.assign(e,{statusCode:400,code:"AUTH_PASSWORD_UNCHANGED"}),e}const e=Eo(),t=this.users.put({...s.storedUser,passwordHash:await ea(i.newPassword),updatedAt:e});this.revokeUserSessions(t.id);const n=this.createSession(t,"web");return{user:na(t),sessionToken:n.token,expiresAt:n.record.expiresAt}}finally{a&&this.loginRateLimiter.finish(),this.credentialUpdateInProgress=!1}}async replaceCredentials(e){const t=Go.parse(e),n=this.users.list();if(0===n.length){const e=new Error("Control Plane administrator has not been initialized.");throw Object.assign(e,{statusCode:409,code:"AUTH_ACCOUNT_NOT_INITIALIZED"}),e}if(1!==n.length){const e=new Error("The account to update is ambiguous.");throw Object.assign(e,{statusCode:409,code:"AUTH_ACCOUNT_AMBIGUOUS"}),e}const s=Eo(),i=this.users.put({...n[0],username:t.username,passwordHash:await ea(t.password),updatedAt:s});return this.revokeUserSessions(i.id),na(i)}async authenticate(e,t,n){if(!this.enabled()){const e=new Error("Control Plane authentication is disabled.");throw Object.assign(e,{statusCode:400,code:"AUTH_DISABLED"}),e}const s=String(n.sourceId||"unknown").trim()||"unknown",i=e.toLocaleLowerCase("en-US");this.loginRateLimiter.begin(s,i);try{const n=this.users.list().find(t=>t.username===e);if(!n||!await ta(t,n.passwordHash)){this.loginRateLimiter.recordFailure(s,i);const e=new Error("Invalid username or password.");throw Object.assign(e,{statusCode:401,code:"AUTH_LOGIN_FAILED"}),e}const r=Eo();return this.users.put({...n,lastLoginAt:r,updatedAt:r})}finally{this.loginRateLimiter.finish()}}createSession(e,t,n){const s=Eo(),i=jo(),r=this.sessions.put({id:Po("mobile"===t?"msess":"sess"),userId:e.id,tokenHash:Zo(i),expiresAt:new Date(Date.now()+12096e5).toISOString(),createdAt:s,updatedAt:s,lastSeenAt:s,clientType:t,...n?{device:n}:{}});return{record:r,token:`${r.id}.${i}`}}revokeUserSessions(e){for(const t of this.sessions.list())t.userId===e&&this.sessions.delete(t.id)}async userForSessionToken(e){const t=this.resolveSessionToken(e,"web");return t?.user}async userForMobileSessionToken(e){const t=this.resolveSessionToken(e,"mobile");return t?.user}resolveSessionToken(e,t){if(!this.enabled()||!e)return;const[n,s]=e.split(".");if(!n||!s)return;const i=this.sessions.get(n);if(!i||t&&i.clientType!==t||i.expiresAt<=Eo()||i.tokenHash!==Zo(s))return;const r=this.users.get(i.userId);if(!r)return;const o=Eo();return{session:this.sessions.put({...i,lastSeenAt:o,updatedAt:o}),user:na(r),storedUser:r}}async currentSession(e,t="web"){const n=this.state(),s="mobile"===t?await this.userForMobileSessionToken(e):await this.userForSessionToken(e);return{...n,authenticated:!this.enabled()||Boolean(s),user:s}}logout(e){const t=e?.split(".")[0];return t&&this.sessions.delete(t),{ok:!0}}mobileSessions(e){const t=this.resolveSessionToken(e);if(t)return this.sessions.list().filter(e=>"mobile"===e.clientType&&e.userId===t.storedUser.id&&e.expiresAt>Eo()).map(e=>sa(e,t.storedUser))}revokeMobileSession(e,t){const n=this.resolveSessionToken(e);if(!n)return;const s=this.sessions.get(t);return!(!s||"mobile"!==s.clientType||s.userId!==n.storedUser.id)&&this.sessions.delete(s.id)}}function ra(e,t){let n=la(t);for(let t=0;t<100;t+=1){const t=e.safeParse(n);if(t.success)return t;const s=aa(t.error.issues);let i=!1;for(const e of s){const t=ca(n,e.path);if(t&&"object"==typeof t&&!Array.isArray(t))for(const n of e.keys)Object.prototype.hasOwnProperty.call(t,n)&&(delete t[n],i=!0)}if(!i)return t}return e.safeParse(n)}function oa(e,t){const n=ra(e,t);if(!n.success)throw n.error;return n.data}function aa(e,t=[]){const n=[];for(const s of e){if("unrecognized_keys"===s.code){n.push({code:"unrecognized_keys",keys:s.keys,path:[...t,...s.path]});continue}if("invalid_union"!==s.code||!Array.isArray(s.errors))continue;const e=s.errors.filter(e=>Array.isArray(e));if(!e.length)continue;const i=e.reduce((e,t)=>da(t)<da(e)?t:e);n.push(...aa(i,[...t,...s.path]))}return n}function da(e){return e.reduce((e,t)=>{if("unrecognized_keys"===t.code)return e;if("invalid_union"!==t.code||!Array.isArray(t.errors))return e+1;const n=t.errors.filter(e=>Array.isArray(e));return e+(n.length?Math.min(...n.map(da)):1)},0)}function ca(e,t){let n=e;for(const e of t){if(!n||"object"!=typeof n)return;n=n[e]}return n}function la(e){return Array.isArray(e)?e.map(la):e&&"object"==typeof e?Object.getPrototypeOf(e)!==Object.prototype&&null!==Object.getPrototypeOf(e)?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,la(t)])):e}const pa=d.z.enum(["import","export"]),ua=d.z.object({id:d.z.string().trim().min(1).max(120),label:d.z.string().trim().min(1).max(120),directoryName:d.z.string().trim().min(1).max(120)}).strict(),ha=d.z.object({direction:pa,programIds:d.z.array(d.z.string().trim().min(1).max(120)).min(1).max(20).refine(e=>new Set(e).size===e.length,"Config sync program ids must be unique."),workspaceFolder:d.z.string().trim().min(1).max(1e3)}).strict(),ma=d.z.object({import:d.z.string().trim().min(1).max(1e3).default("."),export:d.z.string().trim().min(1).max(1e3).default(".")}).strict(),ga=d.z.object({programs:d.z.array(ua),preferences:ma}).strict(),ya=d.z.object({id:d.z.string().trim().min(1).max(120),type:d.z.enum(["file","dir"]),projectPath:d.z.string().trim().min(1).max(1e3),containerPath:d.z.string().trim().min(1).max(1e3),source:d.z.string().trim().min(1).max(4096),target:d.z.string().trim().min(1).max(4096),status:d.z.enum(["copied","skipped_missing_source","failed"]),error:d.z.string().trim().max(4096).optional()}).strict(),fa=d.z.object({preset:d.z.object({id:d.z.string().trim().min(1).max(120),label:d.z.string().trim().min(1).max(120),projectRoot:d.z.string().trim().min(1).max(1e3)}).strict(),direction:pa,items:d.z.array(ya).max(100)}).strict(),Ia=d.z.object({direction:pa,workspaceFolder:d.z.string().trim().min(1).max(1e3),programs:d.z.array(fa).min(1).max(20)}).strict(),ba="x-task-handoff-trace-id";function va(e,t){return`${e};dur=${(Number.isFinite(t)?Math.max(0,t):0).toFixed(1)}`}function Sa(...e){return e.map(e=>String(e||"").trim()).filter(Boolean).join(", ")}const wa=d.z.string().trim().min(1).max(160).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Aa=d.z.string().datetime(),za=d.z.string().trim().min(1).max(255).refine(e=>!(/[\u0000-\u001f\u007f ~^:?*[\\]/.test(e)||e.includes("..")||e.endsWith(".")||e.endsWith("/")),"Invalid Git name."),ka=d.z.string().min(1).max(4096).refine(e=>!(e.includes("\0")||e.startsWith("/")||e.startsWith("\\")||/^[a-zA-Z]:[\\/]/.test(e))&&e.split("/").every(e=>e.length>0&&"."!==e&&".."!==e&&".git"!==e),"Path must be a safe repository-relative path."),Ta=d.z.enum(["ai-session","app-session"]),Ca=d.z.enum(["available","session-not-found","session-inactive","cwd-missing","cwd-inaccessible","git-unavailable","not-worktree"]),Ea=d.z.enum(["branch","detached","unborn"]),xa=d.z.enum(["review-changes","resolve-conflicts","publish-branch","push","pull","diverged","up-to-date"]),Na=d.z.enum(["conflict","staged","unstaged","untracked"]),Ra=d.z.enum(["added","modified","deleted","renamed","copied","type-changed","unmerged","untracked"]),Oa=d.z.object({state:Ea,oid:d.z.string().regex(/^[0-9a-f]{40,64}$/).optional(),branch:d.z.string().min(1).max(1024).optional()}).strict(),_a=d.z.object({ref:d.z.string().min(1).max(2048),remote:za,branch:d.z.string().min(1).max(1024),ahead:d.z.number().int().nonnegative(),behind:d.z.number().int().nonnegative()}).strict(),Pa=d.z.object({id:wa,isCurrent:d.z.boolean(),isMain:d.z.boolean(),managed:d.z.boolean(),head:Oa,dirty:d.z.boolean(),locked:d.z.boolean(),lockReason:d.z.string().max(1e3).optional(),prunable:d.z.boolean(),activeAiSessionIds:d.z.array(wa).max(256).default([]),activeAppSessionIds:d.z.array(wa).max(256).default([])}).strict(),ja=d.z.enum(["main-worktree","external-worktree","outside-workspace-roots","dirty","locked","prunable","session-occupied","path-inaccessible"]),Da=Pa.extend({canCreateAiSession:d.z.boolean(),canRemove:d.z.boolean(),createAiSessionBlockers:d.z.array(ja).max(16).default([]),removeBlockers:d.z.array(ja).max(16).default([])}).strict(),Ma=d.z.object({repositoryId:wa,repositoryContextId:wa,snapshotId:wa,items:d.z.array(Da).max(1e4)}).strict(),La=d.z.object({conflicts:d.z.number().int().nonnegative(),staged:d.z.number().int().nonnegative(),unstaged:d.z.number().int().nonnegative(),untracked:d.z.number().int().nonnegative()}).strict(),qa=d.z.object({name:za,fetchUrl:d.z.string().max(4096).optional(),pushUrl:d.z.string().max(4096).optional()}).strict(),$a=d.z.object({availability:Ca,sessionKind:Ta,sessionId:wa,observedAt:Aa,snapshotId:wa.optional(),repositoryId:wa.optional(),repositoryContextId:wa.optional(),repositoryRoot:d.z.string().min(1).max(4096).optional(),displayName:d.z.string().trim().min(1).max(255).optional(),cwdRelativePath:d.z.string().max(4096).optional(),head:Oa.optional(),upstream:_a.optional(),currentWorktree:Pa.optional(),changes:La.optional(),remotes:d.z.array(qa).max(128).optional(),primaryAction:xa.optional()}).strict(),Ba=d.z.enum(["directory","file","symlink","submodule","nested-repository","special"]),Fa=d.z.object({executable:d.z.boolean(),gitMode:d.z.enum(["100644","100755","120000","160000"]).optional()}).strict(),Ua=d.z.object({name:d.z.string().min(1).max(1024),path:ka,kind:Ba,traversable:d.z.boolean(),editable:d.z.boolean(),size:d.z.number().int().nonnegative().optional(),mode:Fa.optional()}).strict();d.z.object({path:d.z.string().max(4096),entries:d.z.array(Ua).max(1e4),snapshotId:wa}).strict();const Ha=d.z.string().min(16).max(160).regex(/^[a-zA-Z0-9_.:-]+$/),Wa=d.z.object({path:ka,content:d.z.string(),byteLength:d.z.number().int().nonnegative(),version:Ha,mode:Fa}).strict(),Ga=d.z.object({path:ka,oldPath:ka.optional(),scope:Na,status:Ra,version:Ha,binary:d.z.boolean().default(!1)}).strict(),Va=d.z.object({snapshotId:wa,summary:La,entries:d.z.array(Ga).max(1e5)}).strict();d.z.object({file:Wa.optional(),snapshotId:wa,context:$a,changes:Va}).strict();const Ka=d.z.object({kind:d.z.enum(["metadata","hunk","context","addition","deletion"]),content:d.z.string(),oldLine:d.z.number().int().positive().optional(),newLine:d.z.number().int().positive().optional(),oldStart:d.z.number().int().nonnegative().optional(),oldCount:d.z.number().int().nonnegative().optional(),newStart:d.z.number().int().nonnegative().optional(),newCount:d.z.number().int().nonnegative().optional(),heading:d.z.string().optional(),hunkId:d.z.string().min(1).max(200).optional()}).strict();d.z.object({path:ka,oldPath:ka.optional(),scope:Na,binary:d.z.boolean(),complete:d.z.boolean(),truncated:d.z.boolean(),byteLimit:d.z.number().int().positive(),content:d.z.string(),lines:d.z.array(Ka).max(2e5),contextGaps:d.z.array(d.z.object({gapId:d.z.string().min(1).max(500),beforeHunkId:d.z.string().min(1).max(200).optional(),afterHunkId:d.z.string().min(1).max(200).optional(),lines:d.z.array(Ka).max(6e3),startLineCount:d.z.number().int().nonnegative().max(3e3),hasMore:d.z.boolean()}).strict()).max(2e4),version:Ha,snapshotId:wa}).strict();const Ja=d.z.object({name:d.z.string().min(1).max(1024),oid:d.z.string().regex(/^[0-9a-f]{40,64}$/),kind:d.z.enum(["local","remote-tracking"]),current:d.z.boolean(),upstream:d.z.string().min(1).max(2048).optional(),ahead:d.z.number().int().nonnegative().optional(),behind:d.z.number().int().nonnegative().optional(),checkedOutWorktreeIds:d.z.array(wa).max(256).default([])}).strict(),Ya=d.z.object({snapshotId:wa,branches:d.z.array(Ja).max(1e5)}).strict();d.z.object({snapshotId:wa,context:$a,branches:Ya}).strict(),d.z.object({ok:d.z.literal(!0),snapshotId:wa,context:$a,changes:Va.optional(),commitOid:d.z.string().regex(/^[0-9a-f]{40,64}$/).optional()}).strict();const Qa=d.z.enum(["REPOSITORY_REQUEST_INVALID","REPOSITORY_SESSION_NOT_FOUND","REPOSITORY_SESSION_INACTIVE","REPOSITORY_CWD_MISSING","REPOSITORY_CWD_INACCESSIBLE","REPOSITORY_GIT_UNAVAILABLE","REPOSITORY_NOT_WORKTREE","REPOSITORY_PATH_INVALID","REPOSITORY_PATH_FORBIDDEN","REPOSITORY_FILE_NOT_FOUND","REPOSITORY_FILE_EXISTS","REPOSITORY_FILE_UNSUPPORTED","REPOSITORY_FILE_TOO_LARGE","REPOSITORY_FILE_BINARY","REPOSITORY_FILE_STALE","REPOSITORY_STATE_STALE","REPOSITORY_WORKTREE_NOT_FOUND","REPOSITORY_WORKTREE_OCCUPIED","REPOSITORY_WORKTREE_UNSAFE","REPOSITORY_BRANCH_INVALID","REPOSITORY_BRANCH_OCCUPIED","REPOSITORY_BRANCH_UNMERGED","REPOSITORY_CONFLICT","REPOSITORY_DIRTY","REPOSITORY_NOTHING_TO_COMMIT","REPOSITORY_IDENTITY_MISSING","REPOSITORY_HOOK_FAILED","REPOSITORY_SIGNING_FAILED","REPOSITORY_AUTHENTICATION_FAILED","REPOSITORY_NON_FAST_FORWARD","REPOSITORY_UPSTREAM_MISSING","REPOSITORY_COMMAND_TIMEOUT","REPOSITORY_OUTPUT_LIMIT","REPOSITORY_OPERATION_ABORTED","REPOSITORY_OPERATION_FAILED"]);d.z.object({ok:d.z.literal(!1),error:d.z.object({code:Qa,message:d.z.string().trim().min(1).max(2e3),retryable:d.z.boolean(),details:d.z.record(d.z.string(),d.z.union([d.z.string(),d.z.number(),d.z.boolean()])).optional()}).strict()}).strict();const Xa=d.z.object({expectedSnapshotId:wa}).strict(),Za=d.z.object({path:ka,expectedVersion:Ha}).strict();d.z.object({path:ka,content:d.z.string().max(4194304),expectedAbsent:d.z.literal(!0),expectedSnapshotId:wa}).strict(),d.z.object({path:ka,content:d.z.string().max(4194304),expectedVersion:Ha,expectedSnapshotId:wa}).strict(),d.z.object({path:ka,destination:ka,expectedVersion:Ha,expectedDestinationAbsent:d.z.literal(!0),expectedSnapshotId:wa}).strict(),d.z.object({path:ka,expectedVersion:Ha,expectedSnapshotId:wa,confirm:d.z.literal(!0)}).strict(),Xa.extend({paths:d.z.array(Za).min(1).max(1e3)}).strict(),Xa.extend({paths:d.z.array(Za).min(1).max(1e3)}).strict(),Xa.extend({paths:d.z.array(Za).min(1).max(1e3),confirm:d.z.literal(!0)}).strict(),Xa.extend({paths:d.z.array(Za).min(1).max(1e3),confirm:d.z.literal(!0)}).strict(),Xa.extend({message:d.z.string().trim().min(1).max(65536)}).strict();const ed=d.z.discriminatedUnion("mode",[d.z.object({mode:d.z.literal("new-branch"),branchName:za,startRef:d.z.string().trim().min(1).max(2048),expectedSnapshotId:wa}).strict(),d.z.object({mode:d.z.literal("existing-branch"),branchName:za,expectedSnapshotId:wa}).strict()]);Xa.extend({worktreeId:wa,confirm:d.z.literal(!0)}).strict(),d.z.object({worktreeId:wa,worktrees:Ma}).strict(),d.z.object({removedWorktreeId:wa,branchRetained:d.z.boolean(),worktrees:Ma}).strict();const td=d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal("current")}).strict(),d.z.object({type:d.z.literal("worktree"),repositoryContextId:wa,worktreeId:wa}).strict()]);d.z.object({agent:d.z.enum(["codex","claude"]),workspaceSelection:td,message:d.z.string().trim().min(1).max(2e4),clientRequestId:wa,permissionMode:d.z.enum(["ask","auto-review","full-access"]).optional()}).strict(),d.z.object({agent:d.z.enum(["codex","claude"]),worktree:ed,message:d.z.string().trim().min(1).max(2e4),clientRequestId:wa,permissionMode:d.z.enum(["ask","auto-review","full-access"]).optional()}).strict(),d.z.object({aiSessionId:wa,providerSessionId:d.z.string().trim().min(1).max(240),worktreeId:wa,disposition:d.z.literal("started")}).strict();const nd=d.z.object({name:d.z.string().min(1).max(1024),kind:d.z.enum(["branch","head"]).default("branch"),current:d.z.boolean(),currentFolderSelectable:d.z.boolean(),worktreeSelectable:d.z.boolean(),worktreeCheckout:d.z.enum(["attached","detached"]).default("attached"),currentFolderReason:d.z.enum(["dirty","session-occupied","branch-occupied"]).optional(),worktreeReason:d.z.enum(["current-branch","branch-occupied","worktree-unavailable"]).optional()}).strict(),sd=d.z.object({availability:Ca,currentBranch:d.z.string().min(1).max(1024).optional(),dirty:d.z.boolean().default(!1),branches:d.z.array(nd).max(1e5).default([])}).strict();d.z.object({cwd:Le}).strict();const id=$e;qe.extend({gitSelection:id}).strict(),Be.extend({cwd:Le,gitSelection:id}).strict(),Xa.extend({name:za}).strict(),Xa.extend({branch:d.z.string().trim().min(1).max(2048)}).strict(),Xa.extend({name:za,remoteTrackingRef:d.z.string().trim().min(1).max(2048)}).strict(),Xa.extend({name:za,confirm:d.z.literal(!0)}).strict(),Xa.extend({remote:za}).strict(),Xa.extend({remote:za,sourceBranch:za,targetBranch:za,setUpstream:d.z.boolean(),confirmSetUpstream:d.z.boolean().optional()}).strict().refine(e=>!e.setUpstream||!0===e.confirmSetUpstream,{message:"Setting an upstream requires explicit confirmation.",path:["confirmSetUpstream"]}),Xa.extend({remote:za,sourceBranch:za,targetBranch:za}).strict();class rd{options;resumeSnapshotRefreshFailures=0;lastResumeSnapshotRefreshFailure;constructor(e){this.options=e}async resolveApproval(e,t,n){return oa(ot,await this.post(e,ld(t,"approval"),{decision:n}))}async listHistory(e){return oa(ct,await this.get(e,"/ai-sessions/history"))}async historyDetail(e,t){return oa(lt,await this.get(e,`/ai-sessions/history/${encodeURIComponent(t)}`))}async detail(e,t){return oa(rt,await this.get(e,`/ai-sessions/${encodeURIComponent(t)}`))}async timeline(e,t){const n=await this.options.requireInstance(e);if(!function(e){return js(e.capabilities,"session-read").length>0}(n))throw function(){const e=new Error("The controlled instance does not support AI session Timeline reads.");return Object.assign(e,{statusCode:409,code:"AI_SESSION_TIMELINE_UNSUPPORTED"}),e}();return oa(le,await this.options.request(n,ld(t,"timeline"),{method:"GET"}))}async turnTimeline(e,t,n){const s=await this.options.requireInstance(e);if(!function(e){return js(e.capabilities,"turn-read").length>0}(s))throw function(){const e=new Error("The controlled instance does not support per-turn AI session Timeline reads.");return Object.assign(e,{statusCode:409,code:"AI_SESSION_TURN_TIMELINE_UNSUPPORTED"}),e}();return oa(pe,await this.options.request(s,`${ld(t,"turns")}/${encodeURIComponent(n)}/timeline`,{method:"GET"}))}async resume(e,t){const n=oa(pt,await this.post(e,ld(t,"resume"),{}));return await this.refreshAfterCommittedResume(e,t),n}async create(e,t){ud((t.attachments||[]).filter(e=>"upload-ref"!==e.source.type));const n=await this.options.requireInstance(e),s=od(n);if(t.gitSelection&&!s)throw ad();const i=t.permissionMode||("codex"===t.agent?n.config.defaultCodexPermissionMode:void 0),r=t.gitSelection?"/repository/ai-session-workspace/create":"/ai-sessions",{cwdFolderId:o,...a}=t;return oa(Fe,await this.options.request(n,r,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({...a,...s&&o?{cwdFolderId:o}:{},...i?{permissionMode:i}:{}})}))}async inspectWorkspace(e,t){const n=await this.options.requireInstance(e);if(!od(n))throw ad();return oa(sd,await this.options.request(n,"/repository/ai-session-workspace/inspect",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({cwd:t})}))}async fork(e,t,n){const s=oa(We,await this.post(e,ld(t,"fork"),n));try{await this.options.refreshSnapshots()}catch(n){try{this.options.warn?.({instanceId:e,aiSessionId:t,providerSessionId:s.providerSessionId,code:dd(n),message:cd(n)},"AI session Fork committed but snapshot refresh failed")}catch{}}return s}async openApp(e,t,n){return oa(Ve,await this.post(e,ld(t,"open-app"),{clientRequestId:n}))}async close(e,t,n){return oa(Je,await this.post(e,ld(t,"close"),{clientRequestId:n}))}async refreshAfterCommittedResume(e,t){try{await this.options.refreshSnapshots()}catch(n){const s={instanceId:e,aiSessionId:t,code:dd(n),message:cd(n),occurredAt:(new Date).toISOString()};this.resumeSnapshotRefreshFailures+=1,this.lastResumeSnapshotRefreshFailure=s;try{this.options.warn?.(s,"AI session resumed but snapshot refresh failed")}catch{}}}diagnostics(){return{resumeSnapshotRefreshFailures:this.resumeSnapshotRefreshFailures,lastResumeSnapshotRefreshFailure:this.lastResumeSnapshotRefreshFailure}}async sendMessage(e,t,n,s,i=[],r=[],o,a){const d=i.filter(e=>"upload-ref"!==e.source.type);ud(d);const c=await this.options.requireInstance(e);i.some(e=>"runtime-path"===e.source.type)&&function(e,t){if(!e.some(e=>"runtime-path"===e.source.type)||"local"===t)return;const n=new Error("Runtime path attachments are currently available only for Local Runtime instances.");throw Object.assign(n,{statusCode:400,code:"AI_SESSION_RUNTIME_PATH_UNSUPPORTED"}),n}(d,(await this.options.requireRuntime(c.nodeId,c.runtimeId)).type);const l=c.aiSessions.sessions.find(e=>e.id===t),p=o||("codex"===l?.agent?c.config.defaultCodexPermissionMode:void 0);return oa(ot,await this.options.request(c,ld(t,"messages"),{method:"POST",headers:{"content-type":"application/json",...a?.traceId?{[ba]:a.traceId}:{}},body:JSON.stringify({message:n,...s?{mode:s}:{},...i.length?{attachments:i}:{},...r.length?{references:r}:{},...p?{permissionMode:p}:{}})},a?.onTiming))}async mentionCatalog(e,t){return oa(Oe,await this.get(e,ld(t,"mentions")))}async searchMentionFiles(e,t,n){return oa(Pe,await this.post(e,ld(t,"mentions/files"),{query:n}))}async executeCommand(e,t,n){return oa(ke,await this.post(e,ld(t,"commands"),n))}async queue(e,t){return oa(et,await this.get(e,ld(t,"queue")))}async steerQueuedMessage(e,t,n){return oa(ot,await this.post(e,pd(t,n,"steer"),{}))}async retryQueuedMessage(e,t,n){return oa(rt,await this.post(e,pd(t,n,"retry"),{}))}async removeQueuedMessage(e,t,n){const s=await this.options.requireInstance(e);return oa(rt,await this.options.request(s,pd(t,n),{method:"DELETE"}))}async editQueuedMessage(e,t,n,s){const i=Xe.parse(s);return oa(rt,await this.patch(e,pd(t,n),i))}async reorderQueuedMessages(e,t,n){const s=Qe.parse(n);return oa(rt,await this.patch(e,ld(t,"queue/reorder"),s))}async interrupt(e,t){return oa(ot,await this.post(e,ld(t,"interrupt"),{}))}async get(e,t){return this.options.request(await this.options.requireInstance(e),t)}async post(e,t,n){return this.options.request(await this.options.requireInstance(e),t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}async patch(e,t,n){return this.options.request(await this.options.requireInstance(e),t,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}}function od(e){return Ps(e.capabilities).features.aiSessionWorkspaceSelection}function ad(){const e=new Error("The controlled instance does not support AI session workspace selection.");return Object.assign(e,{statusCode:409,code:"AI_SESSION_WORKSPACE_SELECTION_UNSUPPORTED"}),e}function dd(e){return e&&"object"==typeof e&&"code"in e&&"string"==typeof e.code?e.code:"AI_SESSION_SNAPSHOT_REFRESH_FAILED"}function cd(e){return e instanceof Error?e.message:String(e)}function ld(e,t){return`/ai-sessions/${encodeURIComponent(e)}/${t}`}function pd(e,t,n){return`${ld(e,"queue")}/${encodeURIComponent(t)}${n?`/${n}`:""}`}function ud(e){if(e.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)<=R)return;const t=new Error("Inline attachments must be 41943040 bytes or less in total.");throw Object.assign(t,{statusCode:400,code:"AI_SESSION_ATTACHMENTS_TOO_LARGE"}),t}class hd{requestImpl;logger;constructor(e){this.requestImpl=e.request,this.logger=e.logger}async request(e,t,n={}){const s=n.method||"GET";let i,r;try{i=await this.requestImpl(e,t,n)}catch(n){throw this.logger?.warn?.({nodeId:e.id,route:t,method:s,error:n instanceof Error?n.message:String(n),errorCode:"NODE_AGENT_TRANSPORT_FAILED"},"node agent transport failed"),n}try{r=await i.json()}catch(n){this.logger?.warn?.({nodeId:e.id,route:t,method:s,statusCode:i.status,error:n instanceof Error?n.message:String(n),errorCode:"NODE_AGENT_RESPONSE_INVALID_JSON"},"node agent response was not valid json");const r=new Error(`Node agent ${e.id} returned invalid JSON for ${t}.`);throw Object.assign(r,{statusCode:502,code:"NODE_AGENT_RESPONSE_INVALID_JSON",nodeId:e.id,route:t}),r}if(!i.ok){const n=new Error(r.error?.message||`Node agent request failed with HTTP ${i.status}`);throw Object.assign(n,{statusCode:i.status,code:r.error?.code||"NODE_AGENT_REQUEST_FAILED",nodeId:e.id,route:t}),this.logger?.warn?.({nodeId:e.id,route:t,method:s,statusCode:i.status,errorCode:r.error?.code||"NODE_AGENT_REQUEST_FAILED",error:n.message},"node agent request failed"),n}return this.logger?.info?.({nodeId:e.id,route:t,method:s,statusCode:i.status},"node agent request ok"),r.data??r}async requestSchema(e,t,n,s={}){return this.parse(e,t,n,await this.request(e,t,s),s.method||"GET")}parse(e,t,n,s,i="GET"){const r=ra(n,s);if(r.success)return r.data;this.logger?.warn?.({nodeId:e.id,route:t,method:i,errorCode:"NODE_AGENT_PROTOCOL_INVALID",issues:r.error.issues},"node agent protocol response did not match schema");const o=new Error(`Node agent ${e.id} returned invalid protocol data for ${t}.`);throw Object.assign(o,{statusCode:502,code:"NODE_AGENT_PROTOCOL_INVALID",nodeId:e.id,route:t,issues:r.error.issues}),o}}class md{client;fleetRequestTimeoutMs;fleetSnapshotFreshMs;fleetRetryBaseMs;fleetRetryMaxMs;onFleetStateChanged;runtimeSnapshots=new Map;instanceSnapshots=new Map;modelSnapshots=new Map;fleetRefreshes=new Map;fleetRevisions=new Map;fleetRetryAttempts=new Map;fleetRetryTimers=new Map;disposed=!1;constructor(e,t={}){this.client=e,this.fleetRequestTimeoutMs=Number.isFinite(t.fleetRequestTimeoutMs)&&Number(t.fleetRequestTimeoutMs)>0?Number(t.fleetRequestTimeoutMs):2e3,this.fleetSnapshotFreshMs=Number.isFinite(t.fleetSnapshotFreshMs)&&Number(t.fleetSnapshotFreshMs)>=0?Number(t.fleetSnapshotFreshMs):15e3,this.fleetRetryBaseMs=Number.isFinite(t.fleetRetryBaseMs)&&Number(t.fleetRetryBaseMs)>0?Number(t.fleetRetryBaseMs):1e3,this.fleetRetryMaxMs=Number.isFinite(t.fleetRetryMaxMs)&&Number(t.fleetRetryMaxMs)>=this.fleetRetryBaseMs?Number(t.fleetRetryMaxMs):Math.max(3e4,this.fleetRetryBaseMs),this.onFleetStateChanged=t.onFleetStateChanged}request(e,t,n={}){return this.client.request(e,t,n)}forgetNode(e){this.runtimeSnapshots.delete(e),this.instanceSnapshots.delete(e),this.modelSnapshots.delete(e);for(const t of["runtimes","instances","models"])this.resetFleetRetry(`${t}:${e}`)}dispose(){this.disposed=!0;for(const e of this.fleetRetryTimers.values())clearTimeout(e);this.fleetRetryTimers.clear(),this.fleetRetryAttempts.clear()}health(e){return this.client.requestSchema(e,"/health",jr)}checkUpdate(e,t){return this.client.requestSchema(e,"/updates/check",qi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}applyUpdate(e,t){return this.client.requestSchema(e,"/updates/apply",$i,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listUpdateJobs(e){return this.client.requestSchema(e,"/updates/jobs",d.z.array($i))}getExternalListener(e){return this.client.requestSchema(e,"/settings/external-listener",Dr)}updateExternalListener(e,t){return this.client.requestSchema(e,"/settings/external-listener",Dr,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}createPairingInvite(e,t={}){return this.client.requestSchema(e,"/pairing/invites",Mr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t&&"object"==typeof t?t:{})})}createControlPlaneConnection(e,t){return this.client.requestSchema(e,"/control-plane-connections",Fr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}listControlPlanePairings(e){return this.client.requestSchema(e,"/control-plane-pairings",d.z.array(qr))}deleteControlPlanePairing(e,t){return this.client.requestSchema(e,`/control-plane-pairings/${encodeURIComponent(t)}`,Ur,{method:"DELETE"})}listControlPlaneConnections(e){return this.client.requestSchema(e,"/control-plane-connections",d.z.array(Br))}deleteControlPlaneConnection(e,t){return this.client.requestSchema(e,`/control-plane-connections/${encodeURIComponent(t)}`,Ur,{method:"DELETE"})}listDockerImages(e){return this.client.requestSchema(e,"/docker/images",d.z.array(Hr))}listFolderTree(e,t={}){const n=new URLSearchParams;t.path&&n.set("path",t.path),void 0!==t.depth&&n.set("depth",String(t.depth));const s=n.toString();return this.client.requestSchema(e,"/folders/tree"+(s?`?${s}`:""),d.z.array(Gr))}listFolderPlaces(e){return this.client.requestSchema(e,"/folders/places",d.z.array(Vr))}listLocalFolders(e,t={}){return this.client.requestSchema(e,"/local-folders",d.z.array(Wi),t)}createLocalFolder(e,t){return this.client.requestSchema(e,"/local-folders",Wi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}updateLocalFolder(e,t,n){return this.client.requestSchema(e,`/local-folders/${encodeURIComponent(t)}`,Wi,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}async requireLocalFolder(e,t){const n=(await this.listLocalFolders(e)).find(e=>e.id===t);if(!n){const n=new Error(`Local folder ${t} was not found on node ${e.id}.`);throw Object.assign(n,{statusCode:404,code:"NODE_LOCAL_FOLDER_NOT_FOUND",nodeId:e.id,route:"/local-folders"}),n}return n}listRuntimes(e,t={}){return this.client.requestSchema(e,"/runtimes",d.z.array(Or),t)}async createRuntime(e,t){const n=await this.client.requestSchema(e,"/runtimes",Or,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)});return this.invalidateFleetResource(e,"runtimes"),n}async updateRuntime(e,t,n){const s=`/runtimes/${encodeURIComponent(t)}`,i=await this.client.requestSchema(e,s,Or,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.invalidateFleetResource(e,"runtimes"),i}async checkRuntime(e,t){const n=`/runtimes/${encodeURIComponent(t)}/check`,s=await this.client.requestSchema(e,n,Or,{method:"POST"});return this.invalidateFleetResource(e,"runtimes"),s}async deleteRuntime(e,t){const n=await this.client.requestSchema(e,`/runtimes/${encodeURIComponent(t)}`,Ur,{method:"DELETE"});return this.invalidateFleetResource(e,"runtimes"),n}deleteLocalFolder(e,t){return this.client.requestSchema(e,`/local-folders/${encodeURIComponent(t)}`,Ur,{method:"DELETE"})}listModels(e,t={}){return this.client.requestSchema(e,"/models",d.z.array(Xi),t)}async createModel(e,t){const n=await this.client.requestSchema(e,"/models",Xi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)});return this.invalidateFleetResource(e,"models"),n}async deployModel(e,t,n){const s=await this.client.requestSchema(e,`/models/${encodeURIComponent(t)}/deploy`,Xi,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.invalidateFleetResource(e,"models"),s}async updateModel(e,t,n){const s=await this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,Xi,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.invalidateFleetResource(e,"models"),s}async deleteModel(e,t){const n=await this.client.requestSchema(e,`/models/${encodeURIComponent(t)}`,Ur,{method:"DELETE"});return this.invalidateFleetResource(e,"models"),n}discoverModels(e,t){return this.client.requestSchema(e,"/models/discover",d.z.object({models:d.z.array(d.z.object({id:d.z.string(),ownedBy:d.z.string().optional()}).strict()),latencyMs:d.z.number().nonnegative()}).strict(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}testModel(e,t){return this.client.requestSchema(e,"/models/test",d.z.object({success:d.z.literal(!0),latencyMs:d.z.number().nonnegative()}).strict(),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)})}async assignInstanceModels(e,t,n){const s=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/model-assignment`,d.z.object({assignment:Zi,instance:Zr}).strict(),{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.upsertInstanceSnapshot(e,s.instance),s}async listFleetModels(e,t={}){return await this.refreshFleetModels(e,t,!0),this.readFleetModels(e)}async listFleetRuntimes(e,t={}){return await this.refreshFleetRuntimes(e,t,!0),this.readFleetRuntimes(e)}readFleetModels(e){const t=this.readFleetSnapshots(e,"models",this.modelSnapshots);return{...t,items:t.items.map(({nodeId:e,item:t})=>({nodeId:e,model:t}))}}readFleetRuntimes(e){const t=this.readFleetSnapshots(e,"runtimes",this.runtimeSnapshots);return{...t,items:t.items.map(({item:e})=>e)}}readFleetInstances(e){const t=this.readFleetSnapshots(e,"instances",this.instanceSnapshots);return{...t,items:t.items.map(({item:e})=>e)}}refreshFleetModels(e,t={},n=!1){return this.refreshFleetSnapshots(e,"models","/models",t,this.modelSnapshots,async(e,t)=>({items:await this.listModels(e,t),nodeErrors:[]}),n)}refreshFleetRuntimes(e,t={},n=!1){return this.refreshFleetSnapshots(e,"runtimes","/runtimes",t,this.runtimeSnapshots,async(e,t)=>({items:await this.listRuntimes(e,t),nodeErrors:[]}),n)}refreshFleetInstances(e,t={},n=!1){return this.refreshFleetSnapshots(e,"instances","/instances",t,this.instanceSnapshots,(e,t)=>this.loadInstancesWithDiagnostics(e,t),n)}listInstances(e,t={}){return this.listInstancesWithDiagnostics(e,t).then(e=>e.items)}async listInstancesWithDiagnostics(e,t={}){const n=await this.loadInstancesWithDiagnostics(e,t);return this.setTargetedSnapshot(e,"instances",this.instanceSnapshots,n),n}async loadInstancesWithDiagnostics(e,t={}){return this.client.requestSchema(e,"/instances",d.z.array(d.z.unknown()),t).then(t=>t.reduce((t,n)=>{const s=this.normalizeInstance(e,n);return s.instance&&t.items.push(s.instance),s.error&&t.nodeErrors.push(s.error),t},{items:[],nodeErrors:[]}))}instanceFromSnapshot(e,t){for(const n of e){const e=this.instanceSnapshots.get(n.id);if(!e||e.connectionKey!==this.fleetConnectionKey(n))continue;const s=e.items.find(e=>e.id===t);if(s)return s}}async createInstance(e,t){const n=await this.client.requestSchema(e,"/instances",Zr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(t)});return this.upsertInstanceSnapshot(e,n),n}async updateInstance(e,t,n){const s=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}`,Zr,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.upsertInstanceSnapshot(e,s),s}async deleteInstance(e,t,n){const s=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/delete`,oi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.removeInstanceSnapshot(e,t),s}listEnvironmentTemplates(e,t={}){return this.client.requestSchema(e,"/environment-templates",d.z.array(hi),t)}getEnvironmentTemplate(e,t,n={}){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,hi,n)}createEnvironmentTemplate(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/environment-templates`,hi,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}deleteEnvironmentTemplate(e,t){return this.client.requestSchema(e,`/environment-templates/${encodeURIComponent(t)}`,d.z.object({deleted:d.z.boolean(),templateId:hi.shape.id}).strict(),{method:"DELETE"})}async startInstance(e,t,n={}){const s=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/start`,Zr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.upsertInstanceSnapshot(e,s),s}async retryInstanceImageProvisioning(e,t){const n=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/image-provisioning/retry`,Zr,{method:"POST"});return this.upsertInstanceSnapshot(e,n),n}async stopInstance(e,t){const n=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/stop`,Zr,{method:"POST"});return this.upsertInstanceSnapshot(e,n),n}async restartInstance(e,t,n={}){const s=await this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/restart`,Zr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)});return this.upsertInstanceSnapshot(e,s),s}instanceResourceMetrics(e,t){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/metrics`,_r)}proxyRawInstance(e,t,n){return this.client.requestSchema(e,`/instances/${encodeURIComponent(t)}/proxy/raw`,Kr,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)})}async listFleetInstances(e,t={}){return await this.refreshFleetInstances(e,t,!0),this.readFleetInstances(e)}readFleetSnapshots(e,t,n){this.reconcileFleetConnections(e,t,n);const s={items:[],nodeErrors:[],nodeStates:[]};for(const i of e){const e=n.get(i.id);if(!e){s.nodeStates.push({nodeId:i.id,resource:t,phase:"uninitialized",revision:this.fleetRevisions.get(`${t}:${i.id}`)});continue}s.items.push(...e.items.map(e=>({nodeId:i.id,item:e})));const r=this.publicFleetState(i.id,t,e);s.nodeStates.push(r),e.error&&s.nodeErrors.push(e.error)}return s}async refreshFleetSnapshots(e,t,n,s,i,r,o){this.reconcileFleetConnections(e,t,i),await Promise.all(e.map(e=>this.refreshFleetNode(e,t,n,s,i,r,o)))}refreshFleetNode(e,t,n,s,i,r,o){if(this.disposed)return Promise.resolve();const a=`${t}:${e.id}`,d=this.fleetRefreshes.get(a);if(d)return d;if(!o&&this.fleetRetryTimers.has(a))return Promise.resolve();o&&this.clearFleetRetry(a);const c=this.fleetConnectionKey(e),l=i.get(e.id),p=l?.connectionKey===c&&"ready"===l.phase&&void 0!==l.updatedAt&&Date.now()-Date.parse(l.updatedAt)<this.fleetSnapshotFreshMs;if(!o&&p)return Promise.resolve();const u=l?.connectionKey===c&&Boolean(l.error)&&("error"===l.phase||"stale"===l.phase),h=this.nextFleetRevision(e.id,t),m={connectionKey:c,items:l?.connectionKey===c?[...l.items]:[],phase:u?l.phase:l?.connectionKey===c&&l.updatedAt?"stale":"loading",revision:h,updatedAt:l?.connectionKey===c?l.updatedAt:void 0,error:u?l.error:void 0};i.set(e.id,m),u||this.emitFleetState(e.id,t,m);const g=(async()=>{try{this.requireFleetNodeReady(e,n);const o=await this.withFleetDeadline(e,n,s,t=>r(e,t));if(i.get(e.id)?.revision!==h)return;const d=o.nodeErrors[0],l={connectionKey:c,items:[...o.items],phase:d?"stale":"ready",revision:h,updatedAt:(new Date).toISOString(),error:d};if(i.set(e.id,l),d)return this.sameFleetState(m,l)||this.emitFleetState(e.id,t,l),void this.scheduleFleetRetry(a,()=>this.refreshFleetNode(e,t,n,{},i,r,!0));this.resetFleetRetry(a),this.emitFleetState(e.id,t,l)}catch(s){if(i.get(e.id)?.revision!==h)return;const o=function(e,t,n,s){const i=s&&"object"==typeof s?s:{};return{nodeId:e.id,route:"string"==typeof i.route?i.route:t,method:"GET",code:"string"==typeof i.code?i.code:"NODE_AGENT_REQUEST_FAILED",message:s instanceof Error?s.message:String(s),statusCode:"number"==typeof i.statusCode?i.statusCode:void 0,issues:Array.isArray(i.issues)?i.issues:void 0}}(e,n,0,s),d={...m,phase:m.updatedAt?"stale":"error",error:o};i.set(e.id,d),this.sameFleetState(m,d)||this.emitFleetState(e.id,t,d),this.scheduleFleetRetry(a,()=>this.refreshFleetNode(e,t,n,{},i,r,!0))}})().finally(()=>{this.fleetRefreshes.get(a)===g&&this.fleetRefreshes.delete(a)});return this.fleetRefreshes.set(a,g),g}reconcileFleetConnections(e,t,n){for(const s of e){const e=n.get(s.id);e&&e.connectionKey!==this.fleetConnectionKey(s)&&(n.delete(s.id),this.resetFleetRetry(`${t}:${s.id}`))}}invalidateFleetResource(e,t){const n="instances"===t?this.instanceSnapshots:"runtimes"===t?this.runtimeSnapshots:this.modelSnapshots;n.get(e.id)&&(this.resetFleetRetry(`${t}:${e.id}`),n.delete(e.id),this.onFleetStateChanged?.({nodeId:e.id,resource:t,phase:"uninitialized",revision:this.nextFleetRevision(e.id,t)}))}publicFleetState(e,t,n){const s=n.error?{nodeId:n.error.nodeId,route:n.error.route,method:n.error.method,code:n.error.code,message:n.error.message,...void 0!==n.error.statusCode?{statusCode:n.error.statusCode}:{},...n.error.issues?{issues:n.error.issues.map(e=>({path:e.path.map(e=>"symbol"==typeof e?String(e):e),message:e.message}))}:{}}:void 0;return{nodeId:e,resource:t,phase:n.phase,revision:n.revision,...n.updatedAt?{updatedAt:n.updatedAt}:{},...s?{error:s}:{}}}emitFleetState(e,t,n){this.onFleetStateChanged?.(this.publicFleetState(e,t,n))}sameFleetState(e,t){const n=e=>({phase:e.phase,items:e.items,error:e.error&&{code:e.error.code,message:e.error.message,statusCode:e.error.statusCode,route:e.error.route,method:e.error.method,issues:e.error.issues}});return JSON.stringify(n(e))===JSON.stringify(n(t))}scheduleFleetRetry(e,t){if(this.disposed||this.fleetRetryTimers.has(e))return;const n=(this.fleetRetryAttempts.get(e)||0)+1;this.fleetRetryAttempts.set(e,n);const s=Math.min(this.fleetRetryMaxMs,this.fleetRetryBaseMs*2**Math.min(n-1,10)),i=setTimeout(()=>{this.fleetRetryTimers.delete(e),this.disposed||t()},s);i.unref?.(),this.fleetRetryTimers.set(e,i)}clearFleetRetry(e){const t=this.fleetRetryTimers.get(e);t&&clearTimeout(t),this.fleetRetryTimers.delete(e)}resetFleetRetry(e){this.clearFleetRetry(e),this.fleetRetryAttempts.delete(e)}setTargetedSnapshot(e,t,n,s){const i={connectionKey:this.fleetConnectionKey(e),items:[...s.items],phase:s.nodeErrors.length?"stale":"ready",revision:this.nextFleetRevision(e.id,t),updatedAt:(new Date).toISOString(),error:s.nodeErrors[0]};n.set(e.id,i),this.emitFleetState(e.id,t,i)}nextFleetRevision(e,t){const n=`${t}:${e}`,s=(this.fleetRevisions.get(n)||0)+1;return this.fleetRevisions.set(n,s),s}fleetConnectionKey(e){return JSON.stringify([e.id,e.connectionMode,e.controlEndpoint,e.endpoint,e.auth.mode,e.auth.keyId])}upsertInstanceSnapshot(e,t){const n=this.instanceSnapshots.get(e.id),s=this.fleetConnectionKey(e);n&&n.connectionKey===s&&(n.items=[...n.items.filter(e=>e.id!==t.id),t],n.phase="ready",n.revision=this.nextFleetRevision(e.id,"instances"),n.updatedAt=(new Date).toISOString(),n.error=void 0,this.emitFleetState(e.id,"instances",n))}removeInstanceSnapshot(e,t){const n=this.instanceSnapshots.get(e.id);n&&n.connectionKey===this.fleetConnectionKey(e)&&(n.items=n.items.filter(e=>e.id!==t),n.phase="ready",n.revision=this.nextFleetRevision(e.id,"instances"),n.updatedAt=(new Date).toISOString(),n.error=void 0,this.emitFleetState(e.id,"instances",n))}requireFleetNodeReady(e,t){const n=e.connectionPhase,s="reverse-wss"!==e.connectionMode&&"control-plane-proxy"!==e.connectionMode;if(!n||"healthy"===n||s)return;const i=new Error(`Node agent ${e.id} is ${n}; serving its latest fleet snapshot.`);throw Object.assign(i,{code:"NODE_AGENT_CONNECTION_PENDING",nodeId:e.id,route:t}),i}async withFleetDeadline(e,t,n,s){const i=new AbortController,r=Object.assign(new Error(`Node agent ${e.id} did not return ${t} before the fleet aggregation deadline.`),{code:"NODE_AGENT_FLEET_TIMEOUT",nodeId:e.id,route:t}),o=new Promise((e,t)=>{const n=()=>t(i.signal.reason||r);i.signal.aborted?n():i.signal.addEventListener("abort",n,{once:!0})}),a=()=>i.abort(n.signal?.reason);n.signal?.aborted?a():n.signal?.addEventListener("abort",a,{once:!0});const d=setTimeout(()=>i.abort(r),this.fleetRequestTimeoutMs);d.unref?.();try{return await Promise.race([s({...n,signal:i.signal}),o])}finally{clearTimeout(d),n.signal?.removeEventListener("abort",a)}}normalizeInstance(e,t){const n=(s=t,Zr.safeParse(function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=new Set(Object.keys(Zr.shape)),s={};for(const[e,i]of Object.entries(t))n.has(e)&&(s[e]=i);if(t.capabilities&&"object"==typeof t.capabilities&&!Array.isArray(t.capabilities)){const e={...t.capabilities};Object.prototype.hasOwnProperty.call(e,"apps")&&delete e.apps,s.capabilities=Ps(e)}else s.capabilities=Ps(void 0);s.appInventory=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e;Object.keys(t).some(e=>!["observedAt","items","issues"].includes(e));const n={observedAt:t.observedAt,items:Array.isArray(t.items)?t.items.map(e=>{e&&"object"==typeof e&&!Array.isArray(e)&&Object.keys(e).some(e=>!["id","name","kind","source","availability","capabilities","diagnosticCode"].includes(e));const t=io(e,["id","name","kind","source","availability","diagnosticCode"]);return!t||"object"!=typeof t||Array.isArray(t)?t:{...t,capabilities:io(e.capabilities,["automation","supportsCwdSelection"])}}):t.items,issues:Array.isArray(t.issues)?t.issues.map(e=>io(e,["code","message"])):t.issues},s=ui.safeParse(n);return s.success?s.data:void 0}(t.appInventory,"string"==typeof t.id&&t.id),s.source=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=t.type,s=Gi.options.find(e=>e.shape.type.value===n);if(!s)return e;const i="local-folder"===n?["type","localFolderId","path","ownerNodeId"]:"git-template"===n?["type","url","templateId","ref","auth","clone"]:["type","repositoryId","url","provider","ref","auth","clone"],r=io(t,i);if("local-folder"!==n){const e=no(Fi,io(t.ref,["type","name","commit"])),n=no(Ui,io(t.auth,["type","secretId"])),s=no(Hi,io(t.clone,["depth","submodules","lfs","subdirectory"]));e?r.ref=e:delete r.ref,n?r.auth=n:delete r.auth,s?r.clone=s:delete r.clone}const o=no(s,r);return o?(Object.keys(t).some(e=>!i.includes(e)),o):r}(t.source,"string"==typeof t.id&&t.id),s.sourceSnapshot=t.sourceSnapshot&&"object"==typeof t.sourceSnapshot&&!Array.isArray(t.sourceSnapshot)?t.sourceSnapshot:{},s.build=no(Ni,t.build,0,0,"string"==typeof t.id&&t.id),s.aiSessions=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=Array.isArray(t.sessions)?t.sessions.flatMap((e,t)=>{const n=no(ht,e);return n?[n]:[]}):[],s={runningCount:"number"==typeof t.runningCount&&Number.isInteger(t.runningCount)&&t.runningCount>=0?t.runningCount:0,waitingCount:"number"==typeof t.waitingCount&&Number.isInteger(t.waitingCount)&&t.waitingCount>=0?t.waitingCount:0,staleCount:"number"==typeof t.staleCount&&Number.isInteger(t.staleCount)&&t.staleCount>=0?t.staleCount:0,sessions:n,updatedAt:Ms.safeParse(t.updatedAt).success?t.updatedAt:(new Date).toISOString()};return Object.keys(t).some(e=>!["runningCount","waitingCount","staleCount","sessions","updatedAt"].includes(e)),mt.parse(s)}(t.aiSessions,"string"==typeof t.id&&t.id),s.triggers=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e;Object.keys(t).some(e=>!["enabledCount","runningCount","errorCount","configs","recentRuns"].includes(e));const n=(e,t,n)=>Array.isArray(e)?e.flatMap((e,n)=>{const s=no(t,e);return s?[s]:[]}):[],s=Array.isArray(t.configs)?t.configs.flatMap((e,t)=>{if(!e||"object"!=typeof e||Array.isArray(e))return[];const s=e;Object.keys(s).some(e=>!["configHash","config","deployments","runtime"].includes(e));const i=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=io(t,["configHash","name","description","createdAt","updatedAt"]);if(t.source&&"object"==typeof t.source&&!Array.isArray(t.source)){const e=t.source,s="schedule"===e.type?"interval"===e.scheduleKind?["type","scheduleKind","intervalMs"]:"daily"===e.scheduleKind?["type","scheduleKind","timeOfDay","timezone"]:["type","scheduleKind","weekdays","timeOfDay","timezone"]:"file-change"===e.type?["type","roots","globs","ignore","debounceMs"]:["type","agent","statuses","phases"];n.source=io(e,s)}return n.action=io(t.action,["promptTemplate"]),n.policy=io(t.policy,["cooldownMs","maxConcurrentRuns","whenBusy"]),no(On,n)}(s.config);return"string"==typeof s.configHash&&i?[{configHash:s.configHash,config:i,deployments:n(s.deployments,Pn),runtime:n(s.runtime,jn)}]:[]}):[];return{enabledCount:"number"==typeof t.enabledCount&&Number.isInteger(t.enabledCount)&&t.enabledCount>=0?t.enabledCount:0,runningCount:"number"==typeof t.runningCount&&Number.isInteger(t.runningCount)&&t.runningCount>=0?t.runningCount:0,errorCount:"number"==typeof t.errorCount&&Number.isInteger(t.errorCount)&&t.errorCount>=0?t.errorCount:0,configs:s,recentRuns:n(t.recentRuns,Dn)}}(t.triggers,"string"==typeof t.id&&t.id),s.apps=no(Zr.shape.apps.unwrap(),io(t.apps,["runningCount","problemCount","updatedAt","revision"]),0,0,"string"==typeof t.id&&t.id)||{runningCount:0,problemCount:0},s.config=no(Zr.shape.config.unwrap(),io(t.config,["autoImportAgentConfigs","defaultCodexPermissionMode","aiSessionHistoryLimit","aiSessionAttachmentRetentionDays"]),0,0,"string"==typeof t.id&&t.id)||{autoImportAgentConfigs:!0,defaultCodexPermissionMode:"ask",aiSessionHistoryLimit:50,aiSessionAttachmentRetentionDays:30},s.modelSelection=no(Js.unwrap(),io(t.modelSelection,["codexModelHash","claudeModelHash"]),0,0,"string"==typeof t.id&&t.id)||{},s.imageSnapshot=function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=Er(n),{reference:i,...r}=s,o=n.requestedReference??i;let a;try{a="string"==typeof o?Gs(o):void 0}catch{}const d={img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"},c="string"==typeof n.id?n.id:"string"==typeof t?t:void 0,l="market"===n.origin||c&&d[c]?"market":"custom";return void 0!==n.image||n.reference,{...r,id:c&&d[c]?d[c]:c,origin:l,repository:a?.repository??n.repository,tag:a?.tag??n.tag,requestedReference:a?.reference??o,resolvedDigest:n.resolvedDigest,resolvedReference:n.resolvedReference,downloadSizeBytes:n.downloadSizeBytes,market:"market"===l?io(n.market,["catalogId","catalogRevision","publisher","version"])??{catalogId:"task_handoff_embedded",catalogRevision:"legacy",publisher:"task-handoff"}:void 0}}(t.imageSnapshot,t.imageId,"string"==typeof t.id&&t.id);const i="string"==typeof t.imageId?{img_default:"market_taskhandoff_browser",img_codex:"market_taskhandoff_codex",img_ai:"market_taskhandoff_ai"}[t.imageId]||t.imageId:void 0,r=io(t.imageSelection,["imageId","tag"]);s.imageSelection=r||(i?{imageId:i,tag:s.imageSnapshot?.tag}:void 0),s.imageProvisioning=no(Sr,io(t.imageProvisioning,["phase","requestedReference","generation","error","startedAt","updatedAt"]),0,0,"string"==typeof t.id&&t.id),s.runtimeVersion=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n=e=>{if("string"!=typeof e)return;const t=e.trim();return t&&t.length<=80?t:void 0},s=n(t.desiredVersion);if(!s)return;const i=new Set(ji.shape.phase.options),r="string"==typeof t.phase?t.phase:"pending",o=i.has(r)?r:{idle:"pending",queued:"pending",checking:"pending",downloading:"installing",updating:"installing",completed:"matched",succeeded:"matched",ready:"matched",error:"failed"}[r]||"pending";let a;if(t.error&&"object"==typeof t.error&&!Array.isArray(t.error)){const e=t.error,s="string"==typeof e.message?e.message.trim().slice(0,4096):"";if(s){const t=new Set(Pi.shape.code.options),i="string"==typeof e.code&&t.has(e.code)?e.code:"INSTANCE_RUNTIME_INSTALL_FAILED";e.code;const r=n(e.expectedVersion),o=n(e.actualVersion);a={code:i,message:s,...r?{expectedVersion:r}:{},...o?{actualVersion:o}:{},retryable:!0===e.retryable}}}"string"==typeof t.error&&t.error.trim()&&(a={code:"INSTANCE_RUNTIME_INSTALL_FAILED",message:t.error.trim().slice(0,4096),expectedVersion:s,...n(t.actualVersion)?{actualVersion:n(t.actualVersion)}:{},retryable:!1});const d=n(t.actualVersion),c=Ms.safeParse(t.lastAttemptAt),l=Ms.safeParse(t.matchedAt);return void 0!==t.lastAttemptAt&&c.success,void 0!==t.matchedAt&&l.success,{desiredVersion:s,...d?{actualVersion:d}:{},phase:o,attempt:"number"==typeof t.attempt&&Number.isInteger(t.attempt)&&t.attempt>=0?t.attempt:0,...c.success?{lastAttemptAt:c.data}:{},...l.success?{matchedAt:l.data}:{},...a?{error:a}:{}}}(t.runtimeVersion,"string"==typeof t.id&&t.id),s.workspace=no(Xr,t.workspace,0,0,"string"==typeof t.id&&t.id)||{status:"unknown"},s.environmentSource=no(Qs,t.environmentSource,0,0,"string"==typeof t.id&&t.id),s.environmentTemplateOrigin=no(ni,t.environmentTemplateOrigin,0,0,"string"==typeof t.id&&t.id),s.runtime=no(Zr.shape.runtime.unwrap(),t.runtime,0,0,"string"==typeof t.id&&t.id)||{labels:{}},s.target=no(Jr,io(t.target??t.endpoints,["strategy","web","api","vnc","tty","logs","status"]),0,0,"string"==typeof t.id&&t.id)||{strategy:"direct-port",status:"unknown"},s.access=no(Qr,io(t.access,["strategy","web","api","ws","status"]),0,0,"string"==typeof t.id&&t.id)||{strategy:"control-plane-proxy",status:"unknown"};for(const[e,t]of Object.entries(Zr.shape))Object.prototype.hasOwnProperty.call(s,e)&&!t.safeParse(s[e]).success&&t.safeParse(void 0).success&&delete s[e];return s}(s)));var s;if(n.success)return n.data.protocolVersion&&n.data.protocolVersion!==ks?(this.client.logger?.warn?.({nodeId:e.id,instanceId:n.data.id,expectedProtocolVersion:ks,actualProtocolVersion:n.data.protocolVersion,errorCode:"PROTOCOL_VERSION_MISMATCH"},"node instance protocol version mismatch"),{instance:n.data}):{instance:n.data};const i=t&&"object"==typeof t?t:{},r="string"==typeof i.id?i.id:void 0;return this.client.logger?.warn?.({nodeId:e.id,instanceId:r,errorCode:"NODE_INSTANCE_PAYLOAD_INVALID",issues:n.error.issues.map(e=>({path:e.path.join("."),message:e.message}))},"node instance payload invalid"),{error:{nodeId:e.id,route:"/instances",method:"GET",code:"NODE_INSTANCE_PAYLOAD_INVALID",message:r?`Node instance ${r} payload is invalid.`:"Node instance payload is invalid.",statusCode:502,issues:n.error.issues}}}}function gd(e){return e.readyState===(e.OPEN??1)}function yd(e){const t=Buffer.isBuffer(e)?e.toString("utf8"):"string"==typeof e?e:"";if(Buffer.byteLength(t,"utf8")<=123)return t;let n="";for(const e of t){const t=`${n}${e}`;if(Buffer.byteLength(t,"utf8")>123)break;n=t}return n}function fd(e){if("number"==typeof e&&Number.isInteger(e))return e>=3e3&&e<=4999||e>=1e3&&e<=1014&&1004!==e&&1005!==e&&1006!==e?e:void 0}function Id(e,t,n){e.close(fd(t),yd(n)||void 0)}function bd(e,t,n,s){if(gd(e))for(const e of t.splice(0))if(s(e),!n(e))return}function vd(e,t,n={}){const s=n.pendingFrameLimit??256,i=n.maxFrameBytes??8388608,r=n.maxTotalBytes??1073741824,o=n.maxBufferedBytes??16777216;let a=!1,d=gd(t);const c=[],l=[];let p,u=0,h=0,m=0;const g=e=>Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8"),y=(s,o)=>{const a=g(o);return m+=a,n.onFrame?.(s,a),!(a>i||m>r)||(Id(e,1009,"WebSocket bridge traffic limit exceeded."),Id(t,1009,"WebSocket bridge traffic limit exceeded."),!1)},f=()=>{p&&(clearTimeout(p),p=void 0)},I=(n,s)=>{const i=s.bytes;if((n.bufferedAmount??0)+i>o)return Id(e,1013,"WebSocket bridge consumer is too slow."),Id(t,1013,"WebSocket bridge consumer is too slow."),!1;try{return function(e,t){e.send(t.data,{binary:t.isBinary})}(n,s),!0}catch{return Id(e,1011,"WebSocket bridge send failed."),Id(t,1011,"WebSocket bridge send failed."),!1}},b=(n,i,r)=>{if(i.length>=s)return Id(e,1011,"WebSocket bridge pending frame limit exceeded."),void Id(t,1011,"WebSocket bridge pending frame limit exceeded.");const a="upstream"===n?u:h;if((("upstream"===n?t:e).bufferedAmount??0)+a+r.bytes>o)return Id(e,1013,"WebSocket bridge consumer is too slow."),void Id(t,1013,"WebSocket bridge consumer is too slow.");i.push(r),"upstream"===n?u+=r.bytes:h+=r.bytes};return n.upstreamOpenTimeoutMs&&!d&&(p=setTimeout(()=>{d||a||(Id(e,1011,"Upstream websocket did not open."),Id(t))},n.upstreamOpenTimeoutMs)),e.on("open",()=>bd(e,l,t=>I(e,t),e=>{h-=e.bytes})),t.on("open",()=>{f(),d=!0,n.onUpstreamOpen?.(),bd(t,c,e=>I(t,e),e=>{u-=e.bytes})}),e.on("message",(e,n=!1)=>{if(!y("client-to-upstream",e))return;const s={data:e,isBinary:Boolean(n),bytes:g(e)};gd(t)?I(t,s):b("upstream",c,s)}),t.on("message",(t,n=!1)=>{if(!y("upstream-to-client",t))return;const s={data:t,isBinary:Boolean(n),bytes:g(t)};gd(e)?I(e,s):b("client",l,s)}),t.on("close",(t,s)=>{f(),n.onUpstreamClose?.(t,s),(d||a||!n.onUpstreamCloseBeforeOpen?.())&&Id(e,t,s)}),t.on("error",t=>{n.onUpstreamError?.(t),(d||a||!n.onUpstreamErrorBeforeOpen?.(t))&&Id(e)}),e.on("close",(e,s)=>{f(),a=!0,n.onClientClose?.(e,s),Id(t,e,s)}),e.on("error",e=>{f(),a=!0,n.onClientError?.(e),Id(t,1011,"WebSocket bridge client failed.")}),{close:(n,s)=>{f(),Id(t,n,s),Id(e,n,s)}}}const Sd="TASK_HANDOFF_NODE_AGENT_V1",wd=6e4,Ad="/api/node-tunnel";function zd(e,t){if("paired-hmac"===e.auth.mode&&e.auth.secret){if(!e.auth.keyId){const t=new Error(`Node ${e.id} paired-HMAC auth is missing keyId.`);throw Object.assign(t,{statusCode:500,code:"NODE_AGENT_REMOTE_KEY_ID_MISSING"}),t}return function(e){const t=e.timestamp||(new Date).toISOString(),n=e.nonce||s.randomBytes(18).toString("base64url"),i=kd(e.body||""),r=Td(e.secret,{keyId:e.keyId,method:e.method,pathWithQuery:e.pathWithQuery,timestamp:t,nonce:n,bodySha256:i});return{"x-taskhandoff-node-id":e.nodeId,"x-taskhandoff-key-id":e.keyId,"x-taskhandoff-timestamp":t,"x-taskhandoff-nonce":n,"x-taskhandoff-body-sha256":i,"x-taskhandoff-signature":r}}({nodeId:e.id,keyId:e.auth.keyId,secret:e.auth.secret,method:t.method,pathWithQuery:t.pathWithQuery,body:t.body})}const n="local-ipc"!==e.connectionMode&&"local-loopback"!==e.connectionMode||"local-static-key"!==e.auth.mode?void 0:e.auth.secret;return n?{authorization:`Bearer ${n}`}:{}}function kd(e=""){return s.createHash("sha256").update(e).digest("hex")}function Td(e,t){return s.createHmac("sha256",e).update(function(e){return[Sd,e.keyId,e.method.toUpperCase(),e.pathWithQuery,e.timestamp,e.nonce,e.bodySha256].join("\n")}(t)).digest("hex")}function Cd(e){if(e.startsWith("ipc://"))return decodeURIComponent(e.slice(6))}function Ed(e,t=process.platform){if(!function(e,t=process.platform){if("win32"===t)return e.startsWith("\\\\.\\pipe\\");const s=n.statSync(e),i=process.getuid?.();return void 0===i||s.uid===i}(e,t)){const e=new Error("Local node agent IPC socket is not owned by the current user.");throw Object.assign(e,{statusCode:403,code:"NODE_AGENT_IPC_OWNER_INVALID"}),e}}function xd(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function Nd(e,t){const n=AbortSignal.timeout(t);return e?AbortSignal.any([e,n]):n}async function Rd(e,t,n,s={}){const i=Cd(t);return i?(Ed(i),async function(e,t,n={}){const s=n.method||"GET",i="string"==typeof n.body||n.body instanceof Buffer?n.body:void 0===n.body||null===n.body?void 0:String(n.body),r=new Headers(n.headers||{});return void 0===i||r.has("content-length")||r.set("content-length",String(Buffer.byteLength(i))),new Promise((o,a)=>{const d=u.request({socketPath:e,method:s,path:`/api/node-agent${t}`,headers:Object.fromEntries(r.entries())},e=>{const t=e.statusCode||500;o(new Response("HEAD"!==s&&204!==t&&205!==t&&304!==t?m.Readable.toWeb(e):null,{status:t,headers:e.headers}))});d.on("error",a);const c=()=>d.destroy(new DOMException("The operation was aborted.","AbortError"));n.signal?.aborted?c():n.signal?.addEventListener("abort",c,{once:!0}),d.once("close",()=>n.signal?.removeEventListener("abort",c)),void 0!==i&&d.write(i),d.end()})}(i,n,s)):e(`${t.replace(/\/$/,"")}/api/node-agent${n}`,s)}function Od(e){const t=e.controlEndpoint||e.endpoint;if(!t){const e=new Error("Node agent direct HTTP mode requires an endpoint.");throw Object.assign(e,{statusCode:400,code:"NODE_AGENT_ENDPOINT_REQUIRED"}),e}return t}function _d(e,t,n,s){const i=Od(e),r=Cd(i),o=`/api/node-agent${t}`;if(r)return Ed(r),function(e,t,n,s={}){const i=`/api/node-agent${t}`,r={createConnection:()=>h.connect(e),headers:{host:"task-handoff-node-agent.local",...s}};return n&&(Array.isArray(n)?n.length>0:n.trim().length>0)?new p.WebSocket(`ws://task-handoff-node-agent.local${i}`,n,r):new p.WebSocket(`ws://task-handoff-node-agent.local${i}`,r)}(r,t,n,s);const a=new URL(o,i.replace(/\/$/,""));return a.protocol="https:"===a.protocol?"wss:":"ws:",n?new p.WebSocket(a.toString(),n,{headers:s}):new p.WebSocket(a.toString(),{headers:s})}function Pd(e,t,n){const s=new Headers(n),i=zd(e,t);for(const[e,t]of Object.entries(i))"authorization"===e&&s.has(e)||s.set(e,t);return Object.fromEntries(s.entries())}function jd(e=fetch,t={}){const n=t.openWebSocket||_d,s=xd(t.requestTimeoutMs,3e4),i=xd(t.streamHeaderTimeoutMs,3e4),r=xd(t.websocketOpenTimeoutMs,1e4);return{request:async(t,n,i={})=>{const r=Od(t),o=i.method||"GET",a="string"==typeof i.body||i.body instanceof Buffer?i.body:void 0===i.body||null===i.body?void 0:String(i.body),d=Pd(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},i.headers);return Rd(e,r,n,{...i,body:a,headers:d,signal:Nd(i.signal,s)})},requestStream:async(t,n,s={})=>{const r=Od(t),o=s.method||"GET",a="string"==typeof s.body||s.body instanceof Buffer?s.body:void 0===s.body||null===s.body?void 0:String(s.body),d=Pd(t,{method:o,pathWithQuery:`/api/node-agent${n}`,body:a||""},s.headers),c=new AbortController,l=s.signal?AbortSignal.any([s.signal,c.signal]):c.signal;return async function(t,i,o){const c=setTimeout(()=>o.abort(Object.assign(new Error("Node agent response header timed out."),{code:"NODE_AGENT_RESPONSE_HEADER_TIMEOUT"})),i);c.unref?.();try{return await Rd(e,r,n,{...s,body:a,headers:d,signal:l})}finally{clearTimeout(c)}}(0,i,c)},proxyWebSocket(e,t,s,i,o={}){const a=Pd(e,{method:"GET",pathWithQuery:`/api/node-agent${s}`},o),d=n(e,s,i,a);let c,l=!1;return d.on("open",()=>{if(!l||d.readyState!==(d.OPEN??1))return;const e=c;c=void 0,l=!1,d.send(e)}),vd(t,d,{upstreamOpenTimeoutMs:r,onUpstreamError:()=>t.close(1011,"Instance websocket proxy failed."),onUpstreamErrorBeforeOpen:()=>!0}),{send:e=>{d.readyState!==(d.OPEN??1)?(c=e,l=!0):d.send(e)},ping:()=>{const e=d.ping;if(!e)throw new Error("Direct node-agent websocket does not support ping.");e.call(d)},onPong:e=>d.on("pong",e)}}}}class Dd{direct;tunnel;proxy;constructor(e){this.direct=e.direct,this.tunnel=e.tunnel,this.proxy=e.proxy}setTunnel(e){this.tunnel=e}setProxy(e){this.proxy=e}resolve(e){if(!1===e.connectionEnabled){const e=new Error("Node agent connection is disabled locally.");throw Object.assign(e,{statusCode:409,code:"NODE_AGENT_CONNECTION_DISABLED"}),e}if("control-plane-proxy"===e.connectionMode){if(!this.proxy){const e=new Error("Control-plane proxy transport is not available.");throw Object.assign(e,{statusCode:503,code:"CONTROL_PLANE_PROXY_TRANSPORT_UNAVAILABLE"}),e}return this.proxy}if("reverse-wss"!==e.connectionMode)return this.direct;if(!this.tunnel){const e=new Error("Reverse node agent transport is not available.");throw Object.assign(e,{statusCode:503,code:"NODE_AGENT_REVERSE_TRANSPORT_UNAVAILABLE"}),e}return this.tunnel}}function Md(e,t,n,s){const i=new Error(e,void 0===s?void 0:{cause:s});return Object.assign(i,{code:t,statusCode:n,retryable:n>=500}),i}function Ld(e,t){if("control-plane-proxy"!==e.connectionPath.kind)throw Md("Control-plane proxy transport requires a proxy connection path.","CONTROL_PLANE_PROXY_CONFIGURATION_INVALID",400);const n=t(e);if(!n)throw Md("Control-plane proxy credential is missing.","CONTROL_PLANE_PROXY_CREDENTIAL_REQUIRED",503);if(n.nodeId!==e.id||n.proxyBindingId!==e.connectionPath.proxyBindingId||n.targetNodeId!==e.connectionPath.targetNodeId)throw Md("Control-plane proxy credential does not match the node connection identity.","CONTROL_PLANE_PROXY_CREDENTIAL_MISMATCH",409);return n}function qd(e,t){const n=new Headers(t);n.set(ts,Wn),n.set(ns,e.sourceControlPlaneId),n.set(ss,e.bindingKeyId),n.set(is,e.credential);const i=Yn.safeParse(n.get("x-request-id"));return n.set("x-request-id",i.success?i.data:`proxy_request_${s.randomUUID().replace(/-/g,"")}`),Object.fromEntries(n.entries())}function $d(e){const t=Xn.safeParse(e);if(t.success)return t.data;const n=Md("Control-plane proxy route is invalid.",rs.RouteInvalid,400);throw Object.assign(n,{issues:t.error.issues}),n}function Bd(e,t,n){return t?new p.WebSocket(e,t,{headers:n}):new p.WebSocket(e,{headers:n})}class Fd{credentialForNode;fetchImpl;openWebSocket;constructor(e){this.credentialForNode=e.credentialForNode,this.fetchImpl=e.fetchImpl||fetch,this.openWebSocket=e.openWebSocket||Bd}async fetch(e,t,n={}){const s=Ld(e,this.credentialForNode),i=function(e,t){const n=new URL($d(t),"https://node-agent.invalid"),s=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/http${n.pathname}`,e.proxyOrigin);return s.search=n.search,s}(s,t);try{return await this.fetchImpl(i,{...n,headers:qd(s,n.headers)})}catch(e){if(function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(e))throw e;throw Md(`Trusted control-plane proxy ${s.proxyOrigin} is unavailable.`,"CONTROL_PLANE_PROXY_UNAVAILABLE",503,e)}}request(e,t,n={}){return this.fetch(e,t,n)}requestStream(e,t,n={}){return this.fetch(e,t,n)}proxyWebSocket(e,t,n,s,i={}){const r=Ld(e,this.credentialForNode),o=this.openWebSocket(function(e,t){const n=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/websocket`,e.proxyOrigin);return n.protocol="wss:",n.searchParams.set("route",$d(t)),n}(r,n).toString(),s,qd(r,i));let a,d=!1;return o.on("open",()=>{if(!d||o.readyState!==(o.OPEN??1))return;const e=a;a=void 0,d=!1,o.send(e)}),vd(t,o,{onUpstreamError:()=>t.close(1011,"Control-plane proxy websocket failed."),onUpstreamErrorBeforeOpen:()=>!0}),{send:e=>{o.readyState!==(o.OPEN??1)?(a=e,d=!0):o.send(e)},ping:()=>{const e=o.ping;if(!e)throw new Error("Control-plane proxy websocket does not support ping.");e.call(o)},onPong:e=>o.on("pong",e)}}}const Ud=new Set(Object.keys(As.shape)),Hd=new Set(Object.keys(zs.shape));function Wd(e,t,n){if(!e||"object"!=typeof e||Array.isArray(e))return e;const s=e,i=Object.keys(s).filter(e=>!t.has(e));return i.length&&n?.(i),Object.fromEntries([...t].filter(e=>e in s).map(e=>[e,s[e]]))}function Gd(e){const{credential:t,...n}=e;return n}class Vd{pendingClaims;nodeCredentials;identity;constructor(e,t){this.pendingClaims=new Do(e.pendingClaimsDir,{schema:As,sanitize:e=>function(e){return Wd(e,Ud,e=>t?.("unknown stored pending proxy claim fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.nodeCredentials=new Do(e.nodeCredentialsDir,{schema:zs,sanitize:e=>function(e){return Wd(e,Hd,e=>t?.("unknown stored proxy node credential fields were ignored",{fields:e}))}(e),logger:t,directoryMode:448,fileMode:384}),this.identity=new Mo(e.identityPath,()=>({controlPlaneId:Po("control_plane")}),{schema:d.z.object({controlPlaneId:d.z.string().trim().min(1).max(160)}).strip(),logger:t,directoryMode:448,fileMode:384})}init(e=Date.now()){return this.pendingClaims.init(),this.nodeCredentials.init(),this.identity.init(),this.gcPendingClaims(e)}controlPlaneId(){return this.identity.get().controlPlaneId}pendingClaimByClaimId(e){return this.pendingClaims.list().find(t=>t.claimId===e)}pendingClaimByReference(e){return this.pendingClaims.get(e)||this.pendingClaimByClaimId(e)}putPendingClaim(e){const t=this.pendingClaimByClaimId(e.claimId);if(!t)return this.pendingClaims.put(e);if(t.proxyOrigin!==e.proxyOrigin||t.requestedName!==e.requestedName||t.sourceControlPlaneId!==e.sourceControlPlaneId||t.targetNodeId!==e.targetNodeId||t.bindingKeyId!==e.bindingKeyId||t.credential!==e.credential){const e=new Error("Pending proxy claim identity conflicts with an existing claim.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",statusCode:409}),e}return t}publicPendingClaims(){return this.pendingClaims.list().map(Gd)}nodeCredential(e){return this.nodeCredentials.list().find(t=>t.nodeId===e)}putNodeCredential(e){const t=this.nodeCredential(e.nodeId);if(t&&(t.proxyOrigin!==e.proxyOrigin||t.proxyBindingId!==e.proxyBindingId||t.targetNodeId!==e.targetNodeId||t.sourceControlPlaneId!==e.sourceControlPlaneId||t.bindingKeyId!==e.bindingKeyId||t.credential!==e.credential)){const e=new Error("Proxy node credential conflicts with the existing node identity.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_NODE_IDENTITY_CONFLICT",statusCode:409}),e}return t||this.nodeCredentials.put(e)}deleteNodeCredential(e){const t=this.nodeCredential(e);return!!t&&this.nodeCredentials.delete(t.id)}gcNodeCredentials(e){const t=[];for(const n of this.nodeCredentials.list())e(n)||(this.nodeCredentials.delete(n.id),t.push(n.id));return t}promotePendingClaim(e,t){const n=this.pendingClaimByClaimId(e);if(!n)return;if(n.proxyOrigin!==t.proxyOrigin||n.sourceControlPlaneId!==t.sourceControlPlaneId||void 0!==n.targetNodeId&&n.targetNodeId!==t.targetNodeId||n.bindingKeyId!==t.bindingKeyId||n.credential!==t.credential){const e=new Error("Proxy node credential does not match the pending claim identity.");throw Object.assign(e,{code:"CONTROL_PLANE_PROXY_BINDING_IDENTITY_CONFLICT",statusCode:409}),e}const s=this.putNodeCredential(t);return this.pendingClaims.delete(n.id),s}markCompensationRequired(e){const t=this.pendingClaimByClaimId(e);if(t)return this.pendingClaims.patch(t.id,{status:"compensation-required"})}cancelPendingClaim(e,t){const n=this.pendingClaimByClaimId(e);return n?t?(this.pendingClaims.patch(n.id,{status:"compensation-required"}),{deleted:!1,compensationRequired:!0}):{deleted:this.pendingClaims.delete(n.id),compensationRequired:!1}:{deleted:!1,compensationRequired:!1}}completePendingClaimCompensation(e){const t=this.pendingClaimByClaimId(e);return!(!t||"compensation-required"!==t.status)&&this.pendingClaims.delete(t.id)}forceDeletePendingClaim(e){const t=this.pendingClaimByReference(e);return!!t&&this.pendingClaims.delete(t.id)}gcPendingClaims(e=Date.now()){const t=[];for(const n of this.pendingClaims.list()){if("compensation-required"===n.status)continue;const s=Date.parse(n.expiresAt);!Number.isFinite(s)||s>e||(this.pendingClaims.delete(n.id),t.push(n.id))}return t}}const Kd=d.z.string().trim().min(1).max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:-]*$/),Jd=d.z.string().datetime(),Yd=d.z.object({sessionReadAgents:d.z.array(d.z.string().trim().min(1).max(120)).max(100).default([]),turnReadAgents:d.z.array(d.z.string().trim().min(1).max(120)).max(100).default([]),liveItemAgents:d.z.array(d.z.string().trim().min(1).max(120)).max(100).default([])}).passthrough();const Qd=d.z.object({metadataAgents:d.z.array(d.z.string().trim().min(1).max(120)).max(100).default([]),contentAgents:d.z.array(d.z.string().trim().min(1).max(120)).max(100).default([]),uploadAgents:d.z.array(d.z.string().trim().min(1).max(120)).max(100).default([]),retentionSettings:d.z.boolean().default(!1)}).passthrough(),Xd=d.z.object({aiSessionTimeline:Yd.default(function(){return{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}),aiSessionConversationAttachments:Qd.optional()}).passthrough(),Zd=d.z.enum(["connecting","handshaking","healthy","reconnecting","suspect","offline"]),ec=d.z.enum(["start","stop","restart","retry-image"]);d.z.object({instanceId:Kd,revision:d.z.number().int().nonnegative(),updatedAt:Jd,status:d.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]),health:d.z.enum(["unknown","ok","degraded","failed"]),connectionStatus:d.z.enum(["unknown","online","offline","endpoint-unreachable"]),ready:d.z.boolean(),lastHeartbeatAt:Jd.optional()}).strip();const tc=d.z.object({code:d.z.string().trim().min(1).max(120),message:d.z.string().trim().min(1).max(2048)}).strict(),nc=d.z.enum(["instances","runtimes","models"]),sc=d.z.enum(["uninitialized","loading","ready","stale","error"]),ic=d.z.object({nodeId:Kd,resource:nc,phase:sc,revision:d.z.number().int().nonnegative().optional(),updatedAt:Jd.optional(),error:d.z.object({nodeId:Kd,route:d.z.string().trim().min(1).max(500),method:d.z.string().trim().min(1).max(20),code:d.z.string().trim().min(1).max(120),message:d.z.string().trim().min(1).max(4096),statusCode:d.z.number().int().optional(),issues:d.z.array(d.z.object({path:d.z.array(d.z.union([d.z.string(),d.z.number()])).optional(),message:d.z.string()}).passthrough()).optional()}).passthrough().optional()}).strict();d.z.object({nodeStates:d.z.array(ic).default([])}).passthrough();const rc=d.z.object({id:Kd,name:d.z.string().trim().min(1).max(160),status:d.z.enum(["unknown","online","offline","degraded"]),health:d.z.enum(["unknown","ok","degraded","failed"]),connectionMode:d.z.enum(["local-ipc","local-loopback","direct-http","reverse-wss","control-plane-proxy"]),connectionPhase:Zd.optional(),lastSeenAt:Jd.optional(),observedAt:Jd,capabilities:d.z.array(d.z.string().trim().min(1).max(120)).max(256),error:tc.optional()}).strict();d.z.array(rc);const oc=d.z.object({id:d.z.string().trim().min(1).max(120),name:d.z.string().trim().min(1).max(120),kind:d.z.enum(["tty","gui","web"]),supportsCwdSelection:d.z.boolean()}).strict(),ac=d.z.object({id:Kd,name:d.z.string().trim().min(1).max(160),nodeId:Kd,status:d.z.enum(["created","provisioning","starting","registering","registered","running","stopping","stopped","deleting","failed","unhealthy"]),health:d.z.enum(["unknown","ok","degraded","failed"]),connectionStatus:d.z.enum(["unknown","online","offline","endpoint-unreachable"]),ready:d.z.boolean(),capabilities:Xd.default({aiSessionTimeline:{sessionReadAgents:[],turnReadAgents:[],liveItemAgents:[]}}),config:d.z.object({defaultCodexPermissionMode:we.default("ask")}).strict().default({defaultCodexPermissionMode:"ask"}),lastHeartbeatAt:Jd.optional(),heartbeatAgeMs:d.z.number().int().nonnegative().optional(),observedAt:Jd,runtime:d.z.object({id:Kd,name:d.z.string().trim().min(1).max(160).optional(),type:d.z.enum(["docker","kubernetes","local"]).optional()}).strict(),workspace:d.z.object({status:d.z.enum(["unknown","pending","ready","failed"]),path:d.z.string().trim().max(4096).optional()}).strict(),protocol:d.z.object({version:d.z.string().optional(),compatible:d.z.boolean(),warning:d.z.string().trim().min(1).max(500).optional()}).strict(),aiSessions:yt,availableActions:d.z.array(ec).max(4).default([]),availableApps:d.z.array(oc).max(256).default([]),availableAgents:d.z.array(oc).max(256),error:tc.optional()}).strict();function dc(e){if(!e||"object"!=typeof e)return;const t=e,n=Ni.safeParse(t.build),s=Zs.safeParse(t.platform),i=ei.safeParse(t.arch),r=Pr.safeParse(t.capabilities);return{..."boolean"==typeof t.ok?{ok:t.ok}:{},..."string"==typeof t.role?{role:t.role}:{},..."string"==typeof t.nodeId?{nodeId:t.nodeId}:{},..."string"==typeof t.protocolVersion?{protocolVersion:t.protocolVersion}:{},...s.success?{platform:s.data}:{},...i.success?{arch:i.data}:{},...r.success?{capabilities:r.data}:{},...n.success?{build:n.data}:{},..."string"==typeof t.serverTime?{serverTime:t.serverTime}:{}}}function cc(e){const{agent:t,...n}=e.capabilities,{secret:s,...i}=e.auth,r=i.pairing?{...i.pairing,joinToken:void 0}:void 0,o=dc(t);return{...e,auth:r?{...i,pairing:r}:i,capabilities:o?{...n,agent:o}:n}}function lc(e){return"local-folder"===e.type?{mode:"local-bind",path:"/workspace",readOnly:!1}:{mode:"git-clone",path:"/workspace",readOnly:!1}}function pc(e){return function(e){const{registrationToken:t,target:n,agentStatus:s,targetStatus:i,uiAccessStatus:r,...o}=e;return o}(function(e){const t=`/instances/${encodeURIComponent(e.id)}`,n={strategy:"control-plane-proxy",web:`${t}/`,api:`${t}/api`,ws:`${t}/api`,status:"online"===e.connectionStatus||"online"===e.agentStatus?"reachable":"endpoint-unreachable"};return{...e,access:n}}(e))}function uc(e){const{key:t,...n}=e;return{...n,keyPreview:(s=e.key,s.length<=8?"set":`${s.slice(0,4)}...${s.slice(-4)}`),keySet:!0};var s}function hc(e){return e?e instanceof Headers?Object.fromEntries(e.entries()):Array.isArray(e)?Object.fromEntries(e.map(([e,t])=>[e,t])):Object.fromEntries(Object.entries(e).map(([e,t])=>[e,String(t)])):{}}function mc(e){const t=String(e||"").split(":");if(3===t.length&&"ai"===t[1]&&t[0]&&t[2])return{instanceId:t[0],aiSessionId:t[2]}}function gc(e){return e instanceof Error?e.message:String(e)}function yc(e,t){const n=new Error(t);throw Object.assign(n,{statusCode:404,code:e}),n}d.z.array(ac);const fc=d.z.object({proxyOrigin:Qn,inviteToken:d.z.string().trim().min(24).max(512),name:d.z.string().trim().min(1).max(160).optional()}).strict(),Ic=d.z.object({data:d.z.object({binding:hs,closed:d.z.object({abortedRequests:d.z.number().int().nonnegative(),closedSockets:d.z.number().int().nonnegative()}).strict()}).strict()}).strict();class bc{claimOperations=new Map;options;constructor(e){this.options=e}listPendingClaims(){return this.options.privateStore.publicPendingClaims()}async claimNode(e){const t=fc.parse(e),n=Eo(),s=Po("proxy_claim"),i={id:s,claimId:s,proxyOrigin:t.proxyOrigin,...t.name?{requestedName:t.name}:{},sourceControlPlaneId:this.options.privateStore.controlPlaneId(),bindingKeyId:Po("proxy_key"),credential:jo(),status:"pending",createdAt:n,updatedAt:n,expiresAt:new Date(Date.now()+864e5).toISOString()};return this.options.privateStore.putPendingClaim(i),this.withClaimLock(i.claimId,()=>this.completeClaim(i,t.inviteToken))}async resumeClaim(e){const t=this.options.privateStore.pendingClaimByReference(e);return t||yc("CONTROL_PLANE_PROXY_CLAIM_NOT_FOUND",`Proxy claim ${e} was not found.`),this.withClaimLock(t.claimId,async()=>{const t=this.options.privateStore.pendingClaimByReference(e);return t||yc("CONTROL_PLANE_PROXY_CLAIM_NOT_FOUND",`Proxy claim ${e} was not found.`),this.completeClaim(t)})}async cancelClaim(e,t=!1){const n=this.options.privateStore.pendingClaimByReference(e);return n?this.withClaimLock(n.claimId,async()=>{const n=this.options.privateStore.pendingClaimByReference(e);if(!n)return{deleted:!1,compensationRequired:!1,remoteRevoke:"not-required"};if(t)return{deleted:this.options.privateStore.forceDeletePendingClaim(e),compensationRequired:!1,remoteRevoke:"not-required",forced:!0,orphanRisk:!0};if("pending"===n.status)return{...this.options.privateStore.cancelPendingClaim(n.claimId,!1),remoteRevoke:"not-required"};let s;try{s=await this.requestClaim(n)}catch(e){throw this.compensationError(n,"Trusted control-plane proxy is unavailable; claim cancellation requires retry.",e,503,"CONTROL_PLANE_PROXY_COMPENSATION_REQUIRED",!0,{forceDeleteAllowed:!0,forceDeleteReason:"proxy-unavailable"})}const i=await this.responsePayload(s);if(!s.ok){const e=i?.error?.code;if(e===rs.InviteInvalid||e===rs.BindingRevoked||e===rs.BindingUnknown)return{deleted:this.options.privateStore.completePendingClaimCompensation(n.claimId),compensationRequired:!1,remoteRevoke:e===rs.InviteInvalid?"not-created":"already-revoked"};throw this.compensationError(n,i?.error?.message||`Proxy claim recovery failed with HTTP ${s.status}.`,void 0,s.status,e,i?.error?.retryable)}const r=oa(ws,i?.data);this.requireClaimResultIdentity(n,r);const o=this.compensationCredential(n,r);let a;try{a=await this.revokeBinding(o)}catch(e){throw this.compensationError(n,"Trusted control-plane proxy is unavailable; binding revocation requires retry.",e,503,"CONTROL_PLANE_PROXY_COMPENSATION_REQUIRED",!0,{forceDeleteAllowed:!0,forceDeleteReason:"proxy-unavailable"})}const d=await this.responsePayload(a);if(!a.ok&&d?.error?.code!==rs.BindingRevoked&&d?.error?.code!==rs.BindingUnknown)throw this.compensationError(n,d?.error?.message||`Proxy binding revoke failed with HTTP ${a.status}.`,void 0,a.status,d?.error?.code,d?.error?.retryable);if(a.ok)try{this.requireRevocationReceipt(d,o)}catch(e){throw this.compensationError(n,"Proxy binding revocation returned an invalid receipt; compensation requires retry.",e,502,rs.TransportFailed,!0)}return{deleted:this.options.privateStore.completePendingClaimCompensation(n.claimId),compensationRequired:!1,remoteRevoke:a.ok?"revoked":"already-revoked"}}):{deleted:!1,compensationRequired:!1,remoteRevoke:"not-required"}}applyTargetSnapshot(e,t){const n=this.requireProxyNodeIdentity(e,t.binding.id,t.binding.targetNodeId);return this.putTargetState(n,t.target,{reachability:"reachable",bindingStatus:t.binding.status,bindingRevision:t.binding.revision,streamId:t.streamId,revision:t.revision,observedAt:t.observedAt})}applyTargetEvent(e,t){const n=this.requireProxyNodeIdentity(e,void 0,t.targetNodeId),s=n.proxyState;if(!s?.streamId||s.streamId!==t.streamId||void 0===s.revision||t.revision!==s.revision+1){const e=new Error("Proxy target event does not continue the authoritative snapshot cursor.");throw Object.assign(e,{code:rs.SnapshotRequired,statusCode:409,retryable:!0}),e}return this.putTargetState(n,t.target,{...s,reachability:"reachable",bindingStatus:"revoked"===s.bindingStatus?"revoked":"active",revision:t.revision,observedAt:t.event.createdAt})}markUnavailable(e,t){const n=this.requireProxyNodeIdentity(e),s=Eo();return this.options.nodes.put(Rr.parse({...n,status:"degraded",health:"degraded",proxyState:{...n.proxyState,reachability:"unreachable",bindingStatus:n.proxyState?.bindingStatus??"unknown",lastError:t,updatedAt:s},updatedAt:s}))}markBindingRevoked(e,t){const n=this.requireProxyNodeIdentity(e),s=Eo();return this.options.nodes.put(Rr.parse({...n,status:"degraded",health:"degraded",proxyState:{...n.proxyState,reachability:"reachable",bindingStatus:"revoked",lastError:t,updatedAt:s},updatedAt:s}))}assertIdentityPatch(e,t){const n=t.connectionMode??e.connectionMode,s=t.connectionPath??e.connectionPath,i=t.auth??e.auth,r="control-plane-proxy"===e.connectionMode||"control-plane-proxy"===e.connectionPath.kind||"proxy-binding"===e.auth.mode,o="control-plane-proxy"===n||"control-plane-proxy"===s.kind||"proxy-binding"===i.mode,a=n!==e.connectionMode||JSON.stringify(s)!==JSON.stringify(e.connectionPath)||JSON.stringify(i)!==JSON.stringify(e.auth);if((r||o)&&a){const e=new Error("Proxy node connection identity can only be changed through the control-plane proxy lifecycle API.");throw Object.assign(e,{statusCode:409,code:"CONTROL_PLANE_PROXY_IDENTITY_IMMUTABLE",retryable:!1}),e}}async deleteNode(e,t=!1){if("control-plane-proxy"!==e.connectionMode)return{deleted:this.options.deleteNode(e.id),revoke:{mode:"not-proxied",orphanRisk:!1}};const n=this.options.privateStore.nodeCredential(e.id);if(!n){if(!t){const e=new Error("Proxy node credential is missing; remote binding cannot be revoked.");throw Object.assign(e,{statusCode:409,code:"CONTROL_PLANE_PROXY_CREDENTIAL_REQUIRED",retryable:!1,details:{forceDeleteAllowed:!0,forceDeleteReason:"credential-missing"}}),e}return this.forceDeleteNode(e.id)}let s;try{s=await this.revokeBinding(n)}catch(n){if(t)return this.forceDeleteNode(e.id);const s=new Error("Trusted control-plane proxy is unavailable; the binding was not revoked.",{cause:n});throw Object.assign(s,{statusCode:503,code:"CONTROL_PLANE_PROXY_REVOKE_UNAVAILABLE",retryable:!0,details:{forceDeleteAllowed:!0,forceDeleteReason:"proxy-unavailable"}}),s}const i=await this.responsePayload(s);if(!s.ok){if(i?.error?.code===rs.BindingRevoked||i?.error?.code===rs.BindingUnknown){const t=i.error.details?.bindingId;if(t===n.proxyBindingId)return this.finishRevokedNodeDelete(e.id)}const t=new Error(i?.error?.message||`Proxy binding revoke failed with HTTP ${s.status}.`);throw Object.assign(t,{statusCode:s.status,code:i?.error?.code||"CONTROL_PLANE_PROXY_REVOKE_FAILED",retryable:i?.error?.retryable??s.status>=500,details:{...(r=i?.error?.details,r&&"object"==typeof r&&!Array.isArray(r)?r:{}),forceDeleteAllowed:!1}}),t}var r;try{this.requireRevocationReceipt(i,n)}catch(e){if(e&&"object"==typeof e){const t=e;t.details={...t.details||{},forceDeleteAllowed:!1}}throw e}return this.finishRevokedNodeDelete(e.id)}async completeClaim(e,t){let n;this.options.privateStore.markCompensationRequired(e.claimId);try{n=await this.requestClaim(e,t)}catch(t){const n=new Error(`Trusted control-plane proxy ${e.proxyOrigin} is unavailable.`,{cause:t});throw Object.assign(n,{statusCode:503,code:"CONTROL_PLANE_PROXY_UNAVAILABLE",retryable:!0,claimId:e.claimId}),n}const s=await this.responsePayload(n);if(!n.ok){const t=s?.error?.retryable??n.status>=500;t||this.options.privateStore.completePendingClaimCompensation(e.claimId);const i=new Error(s?.error?.message||`Proxy claim failed with HTTP ${n.status}.`);throw Object.assign(i,{statusCode:n.status,code:s?.error?.code||"CONTROL_PLANE_PROXY_CLAIM_FAILED",retryable:t,details:s?.error?.details,claimId:e.claimId}),i}const i=oa(ws,s?.data);this.requireClaimResultIdentity(e,i);const r=this.options.nodes.get(i.target.id),o="control-plane-proxy"===r?.connectionMode&&"control-plane-proxy"===r.connectionPath.kind&&r.connectionPath.proxyBindingId===i.binding.id&&r.connectionPath.targetNodeId===i.target.id;if(r&&!o){this.options.privateStore.markCompensationRequired(e.claimId);const t=new Error(`Node ${i.target.id} already exists with another connection identity.`);throw Object.assign(t,{statusCode:409,code:"CONTROL_PLANE_PROXY_NODE_IDENTITY_CONFLICT",claimId:e.claimId}),t}const a={id:`proxy_credential_${i.target.id}`,nodeId:i.target.id,proxyOrigin:e.proxyOrigin,proxyBindingId:i.binding.id,targetNodeId:i.target.id,sourceControlPlaneId:e.sourceControlPlaneId,bindingKeyId:e.bindingKeyId,credential:e.credential,createdAt:e.createdAt,updatedAt:Eo()},d=r||Rr.parse({id:i.target.id,name:e.requestedName||i.target.name,connectionMode:"control-plane-proxy",connectionPath:{kind:"control-plane-proxy",proxyId:new URL(e.proxyOrigin).host,proxyBindingId:i.binding.id,targetNodeId:i.target.id},connectionEnabled:!0,auth:{mode:"proxy-binding"},status:i.target.status,health:i.target.health,capabilities:i.target.capabilities,proxyState:{reachability:"reachable",bindingStatus:i.binding.status,bindingRevision:i.binding.revision,observedAt:Eo(),target:i.target,updatedAt:Eo()},labels:{},lastSeenAt:i.target.lastSeenAt,createdAt:Eo(),updatedAt:Eo()});r||this.options.nodes.put(d);try{this.options.privateStore.promotePendingClaim(e.claimId,a)}catch(e){throw r||this.options.nodes.delete(d.id),e}return{node:cc(d),binding:i.binding}}requireProxyNodeIdentity(e,t,n){const s=this.options.requireNode(e);if("control-plane-proxy"!==s.connectionMode||"control-plane-proxy"!==s.connectionPath.kind||void 0!==t&&s.connectionPath.proxyBindingId!==t||void 0!==n&&s.connectionPath.targetNodeId!==n){const e=new Error("Proxy state identity does not match the node connection path.");throw Object.assign(e,{code:rs.BindingIdentityConflict,statusCode:409,retryable:!1}),e}return s}putTargetState(e,t,n){const s=Eo();return this.options.nodes.put(Rr.parse({...e,name:t.name,status:t.status,health:t.health,capabilities:t.capabilities,lastSeenAt:t.lastSeenAt,proxyState:{...n,target:t,updatedAt:s},updatedAt:s}))}requestClaim(e,t){return this.options.fetchImpl(new URL("/api/node-proxy/claims",e.proxyOrigin),{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({protocolVersion:Wn,...t?{inviteToken:t}:{},claimId:e.claimId,sourceControlPlaneId:e.sourceControlPlaneId,...e.targetNodeId?{targetNodeId:e.targetNodeId}:{},bindingKeyId:e.bindingKeyId,credential:e.credential})})}revokeBinding(e){return this.options.fetchImpl(new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}`,e.proxyOrigin),{method:"DELETE",headers:qd(e)})}async responsePayload(e){return e.json().catch(()=>{})}requireRevocationReceipt(e,t){const n=ra(Ic,e),s=n.success?n.data.data.binding:void 0;if(!s||s.id!==t.proxyBindingId||s.sourceControlPlaneId!==t.sourceControlPlaneId||s.targetNodeId!==t.targetNodeId||s.bindingKeyId!==t.bindingKeyId||"revoked"!==s.status){const e=new Error("Proxy binding revocation receipt does not match the local binding identity.");throw Object.assign(e,{statusCode:502,code:rs.TransportFailed,retryable:!0,details:{bindingId:t.proxyBindingId}}),e}return s}requireClaimResultIdentity(e,t){if(t.binding.claimId!==e.claimId||t.binding.sourceControlPlaneId!==e.sourceControlPlaneId||t.binding.bindingKeyId!==e.bindingKeyId||t.binding.targetNodeId!==t.target.id||void 0!==e.targetNodeId&&t.binding.targetNodeId!==e.targetNodeId){const t=new Error("Proxy claim response does not match the persisted pending identity.");throw Object.assign(t,{statusCode:409,code:rs.BindingIdentityConflict,retryable:!1,claimId:e.claimId,compensationRequired:!0}),t}}compensationCredential(e,t){return{id:`proxy_compensation_${t.binding.id}`,nodeId:t.target.id,proxyOrigin:e.proxyOrigin,proxyBindingId:t.binding.id,targetNodeId:t.target.id,sourceControlPlaneId:e.sourceControlPlaneId,bindingKeyId:e.bindingKeyId,credential:e.credential,createdAt:e.createdAt,updatedAt:Eo()}}compensationError(e,t,n,s=503,i="CONTROL_PLANE_PROXY_COMPENSATION_REQUIRED",r=!0,o){const a=new Error(t,void 0===n?void 0:{cause:n});return Object.assign(a,{statusCode:s,code:i,retryable:r,claimId:e.claimId,compensationRequired:!0,...o?{details:o}:{}}),a}async withClaimLock(e,t){const n=(this.claimOperations.get(e)??Promise.resolve()).catch(()=>{}).then(t);this.claimOperations.set(e,n);try{return await n}finally{this.claimOperations.get(e)===n&&this.claimOperations.delete(e)}}finishRevokedNodeDelete(e){const t=this.options.deleteNode(e);return this.options.privateStore.deleteNodeCredential(e),{deleted:t,revoke:{mode:"revoked",orphanRisk:!1}}}forceDeleteNode(e){const t=this.options.deleteNode(e);return this.options.privateStore.deleteNodeCredential(e),{deleted:t,revoke:{mode:"forced",orphanRisk:!0}}}}const vc=d.z.object({id:Ji.shape.id.optional(),name:Ji.shape.name,source:Gi,defaultImageSelection:Ji.shape.defaultImageSelection,defaultNodeId:Ji.shape.defaultNodeId,defaultRuntimeId:Ji.shape.defaultRuntimeId,workspacePolicy:Vi.optional(),labels:Ji.shape.labels.optional()}).strict(),Sc=vc.omit({id:!0}).partial().strict();function wc(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"/"!==e&&"\\"!==e}const Ac=d.z.string().refine(wc,"Mention trigger must be one printable non-alphanumeric character other than / or \\.");function zc(e){return 1===Array.from(e).length&&!/[\p{L}\p{N}\s]/u.test(e)&&"\\"!==e}const kc=d.z.string().refine(zc,"Command trigger must be one printable non-alphanumeric character other than \\."),Tc=d.z.object({publicBaseUrl:d.z.string().trim().max(2048).optional(),updateChannel:Oi.default("stable"),mentionTrigger:Ac.default("@"),commandTrigger:kc.default("/"),diagnosticLogs:d.z.boolean().default(!1)}).strict().refine(e=>e.mentionTrigger!==e.commandTrigger,{path:["commandTrigger"],message:"Command and mention triggers must be different."}),Cc=d.z.object({publicBaseUrl:d.z.string().trim().max(2048).optional(),updateChannel:Oi.optional(),mentionTrigger:Ac.optional(),commandTrigger:kc.optional(),diagnosticLogs:d.z.boolean().optional()}).strict(),Ec=d.z.object({id:fr.shape.id.optional(),name:fr.shape.name,description:fr.shape.description,cover:fr.shape.cover,reference:fr.shape.reference,pullPolicy:fr.shape.pullPolicy.optional(),capabilities:d.z.array(d.z.string().trim().min(1).max(80)).optional(),optionalApps:d.z.array(d.z.string().trim().min(1).max(120)).optional(),defaultEnv:fr.shape.defaultEnv.optional(),labels:fr.shape.labels.optional()}).strict(),xc=Ec.omit({id:!0}).partial().strict(),Nc=d.z.object({name:oo.shape.name.optional(),channel:oo.shape.channel.optional(),enabled:d.z.boolean().optional(),token:oo.shape.token,defaultChatId:oo.shape.defaultChatId,allowedUserIds:d.z.array(d.z.string().trim().min(1).max(240)).optional(),pollIntervalMs:oo.shape.pollIntervalMs.optional(),settings:oo.shape.settings.optional()}).strict(),Rc=Nc.extend({channel:oo.shape.channel,name:oo.shape.name.optional()}),Oc=On.extend({id:On.shape.configHash}),_c=d.z.object({name:On.shape.name,description:On.shape.description,source:xn,action:Nn,policy:Rn.partial().optional()}).strict(),Pc=_c,jc=d.z.object({instanceIds:d.z.array(Zr.shape.id).min(1),target:_n,enabled:d.z.boolean().optional()}).strict(),Dc=d.z.object({configHash:On.shape.configHash,enabled:d.z.boolean().optional()}).strict(),Mc=d.z.object({mode:d.z.enum(["local-static-key","paired-hmac","proxy-binding"]).default("local-static-key"),keyId:Rr.shape.id.optional(),secret:d.z.string().trim().max(4096).optional(),pairedAt:Rr.shape.createdAt.optional(),pairing:d.z.object({status:d.z.enum(["pending","paired","expired"]).default("pending"),joinToken:d.z.string().trim().max(4096).optional(),expiresAt:Rr.shape.createdAt.optional()}).strict().optional()}).strict(),Lc=d.z.object({autoImportAgentConfigs:d.z.boolean().optional(),defaultCodexPermissionMode:we.optional(),aiSessionHistoryLimit:d.z.number().int().min(1).max(at).optional(),aiSessionAttachmentRetentionDays:d.z.number().int().min(0).max(365).optional()}).strict(),qc=d.z.object({id:Zr.shape.id.optional(),name:Zr.shape.name.optional(),projectId:Zr.shape.projectId,source:Gi.optional(),sourceSnapshot:d.z.record(d.z.string(),d.z.unknown()).optional(),nodeId:Zr.shape.nodeId.optional(),runtimeId:Zr.shape.runtimeId.optional(),environmentSource:Qs.optional(),imageSelection:Zr.shape.imageSelection,config:Lc.optional(),modelSelection:Zr.shape.modelSelection.optional(),start:d.z.boolean().default(!1)}).strict().superRefine((e,t)=>{e.environmentSource&&e.imageSelection&&t.addIssue({code:"custom",path:["environmentSource"],message:"environmentSource and imageSelection are mutually exclusive."})}),$c=d.z.object({name:Zr.shape.name.optional(),config:Lc.optional(),modelSelection:Zr.shape.modelSelection.optional()}).strict(),Bc=d.z.object({name:Yi.shape.name,endpoint:Yi.shape.endpoint,key:Yi.shape.key,model:Yi.shape.model,app:Yi.shape.app,enabled:Yi.shape.enabled.optional(),order:Yi.shape.order.optional(),labels:Yi.shape.labels.optional()}).strict(),Fc=Bc.partial().strict(),Uc=d.z.object({endpoint:Yi.shape.endpoint,key:Yi.shape.key.optional(),existingModelId:Yi.shape.id.optional()}).strict(),Hc=Uc.extend({model:Yi.shape.model,app:Yi.shape.app}).strict(),Wc=d.z.object({id:Rr.shape.id.optional(),name:Rr.shape.name,connectionMode:Rr.shape.connectionMode.optional(),connectionPath:Rr.shape.connectionPath.optional(),connectionEnabled:Rr.shape.connectionEnabled.optional(),auth:Mc.optional(),joinToken:d.z.string().trim().min(1).max(4096).optional(),endpoint:Rr.shape.endpoint,controlEndpoint:Rr.shape.controlEndpoint,containerEndpoint:Rr.shape.containerEndpoint,publicWebBase:Rr.shape.publicWebBase,status:d.z.enum(["unknown","online","offline","degraded"]).optional(),health:d.z.enum(["unknown","ok","degraded","failed"]).optional(),capabilities:Rr.shape.capabilities.optional(),labels:Rr.shape.labels.optional(),lastSeenAt:Rr.shape.lastSeenAt}).strict(),Gc=d.z.object({name:Rr.shape.name.optional(),connectionMode:Rr.shape.connectionMode.unwrap().optional(),connectionPath:Rr.shape.connectionPath.unwrap().optional(),connectionEnabled:Rr.shape.connectionEnabled.unwrap().optional(),auth:Mc.optional(),endpoint:Rr.shape.endpoint,controlEndpoint:Rr.shape.controlEndpoint,containerEndpoint:Rr.shape.containerEndpoint,publicWebBase:Rr.shape.publicWebBase,status:Rr.shape.status.unwrap().optional(),health:Rr.shape.health.unwrap().optional(),capabilities:Rr.shape.capabilities.unwrap().optional(),labels:Rr.shape.labels.unwrap().optional(),lastSeenAt:Rr.shape.lastSeenAt}).strict(),Vc=d.z.object({controlPlaneUrl:d.z.string().trim().url().max(2048),joinToken:d.z.string().trim().min(1).max(4096),controlPlaneName:d.z.string().trim().min(1).max(160).optional(),activate:d.z.boolean().optional()}).strict(),Kc=d.z.object({nodeName:d.z.string().trim().min(1).max(160).optional(),expiresInMs:d.z.number().int().positive().max(36e5).optional()}).strict(),Jc=d.z.object({id:d.z.string().min(1),endpoint:d.z.string().min(1),nodeId:d.z.string().min(1),keyId:d.z.string().min(1),secret:d.z.string().min(1),pairedAt:d.z.string().min(1),createdAt:d.z.string().min(1),updatedAt:d.z.string().min(1)}).strict();class Yc{options;activePendingPairingRevokes=new Set;constructor(e){this.options=e}async syncLocal(){const e={[this.options.localNodeLabel]:"true",[this.options.builtinNodeLabel]:"true"},t=process.env.TASK_HANDOFF_NODE_AGENT_TOKEN?.trim()||void 0,n=process.env.TASK_HANDOFF_NODE_AGENT_CONTROL_ENDPOINT||process.env.TASK_HANDOFF_NODE_AGENT_ENDPOINT||"http://127.0.0.1:8091",s=function(e){return Cd(e)?"local-ipc":"local-loopback"}(n),i=Rr.parse({id:"node_local_probe",name:"Local Node Probe",connectionMode:s,auth:{mode:"local-static-key",secret:t},labels:e,createdAt:Eo(),updatedAt:Eo()}),r=await this.inspect(n,i),o=Eo(),a=this.options.nodes.get(r.nodeId);for(const e of this.options.nodes.list())"true"===e.labels[this.options.localNodeLabel]&&e.id!==r.nodeId&&this.options.nodes.delete(e.id);return this.options.nodes.put(Rr.parse({...a||{},id:r.nodeId,name:a?.name||"Local Node",connectionMode:s,auth:{mode:"local-static-key",secret:t},endpoint:n,controlEndpoint:n,containerEndpoint:process.env.TASK_HANDOFF_NODE_AGENT_CONTAINER_URL,publicWebBase:process.env.TASK_HANDOFF_INSTANCE_PUBLIC_WEB_BASE,status:"online",health:"ok",capabilities:{...a?.capabilities||{},agent:dc(r.data)},labels:{...a?.labels||{},...e},createdAt:a?.createdAt||o,updatedAt:o}))}async create(e){const t=Wc.parse(e),n=Eo(),s=t.connectionMode||"direct-http";let i="auth"in(e&&"object"==typeof e&&!Array.isArray(e)?e:{})?t.auth:{mode:"local-ipc"===s||"local-loopback"===s?"local-static-key":"paired-hmac"};const r="direct-http"===s||"reverse-wss"===s;if(r&&"paired-hmac"!==i.mode)throw Qc("Remote node connections require paired-HMAC authentication.","NODE_AGENT_REMOTE_REQUIRES_PAIRED_HMAC");const o=t.controlEndpoint||t.endpoint;if(!o&&"reverse-wss"!==s)throw Qc("Node agent direct HTTP mode requires an endpoint.","NODE_AGENT_ENDPOINT_REQUIRED");const a=t.joinToken&&o?await this.completePairing(o,t.joinToken):void 0;let d,c=!1;try{if(d=a&&o?this.pendingPairingRevoke(o,a):void 0,d&&(this.activePendingPairingRevokes.add(d.id),this.options.pendingPairingRevokes?.put(d)),a){if(a.invalidResponse||a.unsafePublicIdentifiers)throw Object.assign(new Error("Node agent pairing response reflected secret material in a public identifier."),{statusCode:502,code:"NODE_AGENT_PAIRING_RESPONSE_INVALID"});i={mode:"paired-hmac",keyId:a.keyId,secret:a.secret,pairedAt:a.pairedAt,pairing:{status:"paired"}}}if(r&&!i.secret)throw Qc("Remote node connections require a paired node secret or join token.","NODE_AGENT_REMOTE_SECRET_REQUIRED");if(r&&!i.keyId)throw Qc("Remote node connections require a paired key id.","NODE_AGENT_REMOTE_KEY_ID_REQUIRED");const e=t.id||a?.nodeId||Po("node"),u=Rr.parse({id:e,name:t.name,connectionMode:s,auth:i,labels:t.labels||{},createdAt:n,updatedAt:n}),h="reverse-wss"===s&&(t.id||a?.nodeId)?void 0:await this.inspect(o||"",u),m=t.id||a?.nodeId||h?.nodeId||e;if(!m)throw Qc("Node id is required.","NODE_ID_REQUIRED");if(a&&t.id&&t.id!==a.nodeId)throw Qc(`Paired node id ${a.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(t.id&&h?.nodeId&&h.nodeId!==t.id)throw Qc(`Node agent id ${h.nodeId} does not match requested node id ${t.id}.`,"NODE_AGENT_ID_MISMATCH");if(a&&h?.nodeId&&h.nodeId!==a.nodeId)throw Object.assign(new Error("Node agent health identity did not match the completed pairing."),{statusCode:502,code:"NODE_AGENT_PAIRING_IDENTITY_MISMATCH"});const{joinToken:g,...y}=t,f=Rr.parse({...y,id:m,connectionMode:s,auth:i,endpoint:o,controlEndpoint:o,status:t.status||(h?"online":"unknown"),health:t.health||(h?"ok":"unknown"),capabilities:{...t.capabilities||{},...h?{agent:dc(h.data)}:{}},labels:t.labels||{},createdAt:n,updatedAt:n});if(a&&(l=f,p=a.secret,nl(cc(l),p)))throw Object.assign(new Error("Node agent health response reflected pairing secret material."),{statusCode:502,code:"NODE_AGENT_PAIRING_SECRET_REFLECTED"});c=!0;const I=this.options.nodes.put(f);return this.clearPendingPairingRevoke(d,a),I}catch(e){if(a&&o){const t=this.pairingPersistence(a);if("present"===t.state)return this.clearPendingPairingRevoke(d,a),t.node;if("unknown"===t.state&&c)throw sl(Object.assign(new Error("Node creation persistence outcome is uncertain; pairing compensation is pending."),{statusCode:503,code:"NODE_AGENT_PAIRING_PERSISTENCE_UNCERTAIN",retryable:!0}),a.secret);throw await this.compensatePairing(o,a,e),this.clearPendingPairingRevoke(d,a),sl(e,a.secret)}throw e}finally{d&&this.activePendingPairingRevokes.delete(d.id)}var l,p}async recoverPendingPairingRevokes(){const e=(this.options.pendingPairingRevokes?.list()||[]).filter(e=>!this.activePendingPairingRevokes.has(e.id));await Promise.all(e.map(async e=>{try{const t={nodeId:e.nodeId,keyId:e.keyId,secret:e.secret,pairedAt:e.pairedAt,invalidResponse:!1,unsafePublicIdentifiers:!1},n=this.pairingPersistence(t);if("present"===n.state)return void this.clearPendingPairingRevoke(e,t);if("unknown"===n.state)return;await this.compensatePairing(e.endpoint,t,Object.assign(new Error("Recovering a pending pairing revocation."),{code:"NODE_AGENT_PAIRING_REVOCATION_PENDING"})),this.clearPendingPairingRevoke(e,t)}catch{}}))}pendingPairingRevoke(e,t){if(!this.options.pendingPairingRevokes)return;const n=Eo();return Jc.parse({id:Po("pairing_revoke"),endpoint:e,nodeId:t.nodeId,keyId:t.keyId,secret:t.secret,pairedAt:t.pairedAt,createdAt:n,updatedAt:n})}pairingPersistence(e){let t;try{t=this.options.nodes.get(e.nodeId)}catch{return{state:"unknown"}}return"paired-hmac"===t?.auth.mode&&t.auth.keyId===e.keyId&&t.auth.secret===e.secret?{state:"present",node:t}:{state:"absent"}}clearPendingPairingRevoke(e,t){if(e)try{this.options.pendingPairingRevokes?.delete(e.id)}catch(e){try{this.options.warn({nodeId:t?el(t.nodeId,t.secret):void 0,keyId:t?el(t.keyId,t.secret):void 0,errorCode:"NODE_AGENT_PAIRING_OUTBOX_CLEANUP_FAILED"},"node agent pairing outbox cleanup failed; recovery will retry")}catch{}}}async inspect(e,t){const n="/health",s=t?zd(t,{method:"GET",pathWithQuery:`/api/node-agent${n}`}):{},i=await Rd(this.options.fetchImpl,e,n,{headers:s}),r=await i.json().catch(()=>({}));if(!i.ok)throw this.options.warn(tl({nodeEndpoint:e,statusCode:i.status,errorCode:"NODE_AGENT_HEALTH_FAILED"},t?.auth.secret),"node agent health check failed"),Object.assign(new Error(r.error?.message||`Node agent health check failed with HTTP ${i.status}`),{statusCode:i.status,code:"NODE_AGENT_HEALTH_FAILED"});const o="string"==typeof r.data?.nodeId&&r.data.nodeId.trim()?r.data.nodeId.trim():void 0;if(!o)throw this.options.warn(tl({nodeEndpoint:e,errorCode:"NODE_AGENT_ID_MISSING"},t?.auth.secret),"node agent health response missing node id"),Object.assign(new Error("Node agent health response did not include nodeId."),{statusCode:502,code:"NODE_AGENT_ID_MISSING"});const a=ra(Ni,r.data?.build);return r.data?.protocolVersion!==ks&&this.options.warn(tl({nodeId:o,nodeEndpoint:e,expectedProtocolVersion:ks,actualProtocolVersion:r.data?.protocolVersion,build:a.success?a.data:void 0,errorCode:"PROTOCOL_VERSION_MISMATCH"},t?.auth.secret),"node agent protocol version mismatch"),this.options.info(tl({nodeId:o,nodeEndpoint:e,protocolVersion:r.data.protocolVersion,build:a.success?a.data:void 0},t?.auth.secret),"node agent health check ok"),{nodeId:o,data:r.data||{}}}async completePairing(e,t){const n=await this.options.fetchImpl(`${e.replace(/\/$/,"")}/api/node-agent/pairing/complete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({joinToken:t,controlPlaneName:"Control Plane"})}),s=await n.json().catch(()=>({}));if(!n.ok)throw Object.assign(new Error(s.error?.message||`Node agent pairing failed with status ${n.status}.`),{statusCode:n.status,code:"NODE_AGENT_PAIRING_FAILED"});const i=s.data;if("string"!=typeof i?.nodeId||!i.nodeId.trim()||"string"!=typeof i?.keyId||!i.keyId.trim()||"string"!=typeof i?.secret||!i.secret.trim())throw Object.assign(new Error("Node agent pairing response did not include nodeId, keyId, and secret."),{statusCode:502,code:"NODE_AGENT_PAIRING_RESPONSE_INVALID"});const r=ra(Lr,i),o=i.nodeId.trim(),a=i.keyId.trim(),d=i.secret.trim();return{nodeId:o,keyId:a,secret:d,pairedAt:r.success?r.data.pairedAt:Eo(),invalidResponse:!r.success,unsafePublicIdentifiers:o.includes(d)||a.includes(d)}}async compensatePairing(e,t,n){const s="/pairing/current",i=`/api/node-agent${s}`,r={id:t.nodeId,connectionMode:"direct-http",auth:{mode:"paired-hmac",keyId:t.keyId,secret:t.secret}};try{const o=await Rd(this.options.fetchImpl,e,s,{method:"DELETE",headers:zd(r,{method:"DELETE",pathWithQuery:i}),signal:AbortSignal.timeout(1e4)}),a=await o.json().catch(()=>({}));if(!o.ok)throw Object.assign(new Error(`Node agent pairing revoke failed with HTTP ${o.status}.`),{statusCode:o.status,code:Zc(a.error?.code,t.secret,"NODE_AGENT_PAIRING_REVOKE_FAILED"),retryable:408===o.status||429===o.status||o.status>=500});const d=ra($r,a.data);if(!d.success)throw Object.assign(new Error("Node agent pairing revoke receipt was invalid."),{statusCode:502,code:"NODE_AGENT_PAIRING_REVOKE_RECEIPT_INVALID",retryable:!1});if(d.data.keyId!==t.keyId)throw Object.assign(new Error("Node agent pairing revoke receipt did not match the paired key."),{statusCode:502,code:"NODE_AGENT_PAIRING_REVOKE_RECEIPT_MISMATCH",retryable:!1});try{this.options.info({nodeId:el(t.nodeId,t.secret),keyId:el(t.keyId,t.secret),originalErrorCode:Xc(n,t.secret)},"node agent pairing revoked after node creation failed")}catch{}}catch(e){const s={nodeId:el(t.nodeId,t.secret),keyId:el(t.keyId,t.secret),originalErrorCode:Xc(n,t.secret),compensationErrorCode:Xc(e,t.secret)};try{this.options.warn(s,"node agent pairing compensation failed")}catch{}throw Object.assign(new Error("Node creation failed after pairing, and the remote pairing could not be revoked."),{statusCode:502,code:"NODE_AGENT_PAIRING_COMPENSATION_FAILED",retryable:(o=e,!o||"object"!=typeof o||!("retryable"in o)||"boolean"!=typeof o.retryable||o.retryable),details:s})}var o}}function Qc(e,t){return Object.assign(new Error(e),{statusCode:400,code:t})}function Xc(e,t){return Zc(e&&"object"==typeof e&&"code"in e?e.code:void 0,t,"UNKNOWN_ERROR")}function Zc(e,t,n){return"string"!=typeof e||!/^[A-Z][A-Z0-9_]{0,127}$/.test(e)||e.includes(t)?n:e}function el(e,t){return e.includes(t)?"[redacted]":e}function tl(e,t){if(!t)return e;const n=e=>"string"==typeof e?e.includes(t)?"[redacted]":e:Array.isArray(e)?e.map(n):e&&"object"==typeof e?Object.fromEntries(Object.entries(e).map(([e,s])=>[e.includes(t)?"[redacted-key]":e,n(s)])):e;return n(e)}function nl(e,t){return"string"==typeof e?e.includes(t):Array.isArray(e)?e.some(e=>nl(e,t)):!(!e||"object"!=typeof e)&&Object.entries(e).some(([e,n])=>e.includes(t)||nl(n,t))}function sl(e,t){const n=e instanceof Error&&!e.message.includes(t)?e.message:"Node creation failed after pairing.",s=e&&"object"==typeof e&&"statusCode"in e&&"number"==typeof e.statusCode?e.statusCode:502,i=Object.assign(new Error(n),{statusCode:s,code:Xc(e,t)});return e&&"object"==typeof e&&"retryable"in e&&"boolean"==typeof e.retryable&&Object.assign(i,{retryable:e.retryable}),i}class il{values=new Map;put(e,t,n=Date.now()){this.prune(n),this.values.set(e,t)}take(e,t=Date.now()){this.prune(t);const n=this.values.get(e);return n&&this.values.delete(e),n}peek(e,t=Date.now()){return this.prune(t),this.values.get(e)}delete(e,t=Date.now()){this.prune(t);const n=this.values.get(e);return n&&this.values.delete(e),n}list(e=Date.now()){return this.prune(e),[...this.values.values()]}prune(e=Date.now()){for(const[t,n]of this.values)Date.parse(n.expiresAt)<=e&&this.values.delete(t)}}const rl=d.z.object({joinToken:d.z.string().trim().min(1).max(4096),nodeId:Rr.shape.id,nodeName:Rr.shape.name.optional(),keyId:d.z.string().trim().min(1).max(160),secret:d.z.string().trim().min(1).max(4096),pairedAt:d.z.string().datetime().optional()}).strict();class ol{options;invites=new il;constructor(e){this.options=e}createInvite(e={}){const t=Kc.parse(e&&"object"==typeof e?e:{}),n=jo(),s={id:Po("node_join"),tokenHash:al(n),expiresAt:new Date(Date.now()+(t.expiresInMs||6e5)).toISOString(),...t.nodeName?{nodeName:t.nodeName}:{}};return this.invites.put(s.tokenHash,s),{id:s.id,joinToken:n,expiresAt:s.expiresAt}}complete(e){const t=rl.parse(e),n=al(t.joinToken),s=this.invites.take(n);if(!s)throw Object.assign(new Error("Node join token is invalid or expired."),{statusCode:401,code:"NODE_JOIN_TOKEN_INVALID"});const i=Eo();if(this.options.nodes.get(t.nodeId))throw Object.assign(new Error(`Node ${t.nodeId} already exists in this control-plane.`),{statusCode:409,code:"NODE_JOIN_NODE_ALREADY_EXISTS"});return this.options.nodes.put(Rr.parse({id:t.nodeId,name:t.nodeName||s.nodeName||t.nodeId,connectionMode:"reverse-wss",auth:{mode:"paired-hmac",keyId:t.keyId,secret:t.secret,pairedAt:t.pairedAt||i,pairing:{status:"paired"}},status:"unknown",health:"unknown",capabilities:{},labels:{},createdAt:i,updatedAt:i}))}}function al(e){return s.createHash("sha256").update(e).digest("hex")}function dl(e,t){const n=cl(e);return n.pathname=`${n.pathname.replace(/\/+$/,"")}/${t.replace(/^\/+/,"")}`,n.search="",n.hash="",n.toString()}function cl(e){let t;try{t=new URL(e.trim())}catch{throw hl("MODEL_ENDPOINT_INVALID","The model endpoint must be a valid HTTP or HTTPS URL.",400)}if("http:"!==t.protocol&&"https:"!==t.protocol||t.username||t.password)throw hl("MODEL_ENDPOINT_INVALID","The model endpoint must be an HTTP or HTTPS URL without embedded credentials.",400);return t}async function ll(e,t,n){try{return await e(t,{...n,redirect:"error",signal:AbortSignal.timeout(15e3)})}catch(e){const t=e&&"object"==typeof e&&"name"in e&&"TimeoutError"===e.name;throw hl(t?"MODEL_ENDPOINT_TIMEOUT":"MODEL_ENDPOINT_UNREACHABLE",t?"The model endpoint timed out.":"The model endpoint could not be reached.",t?504:502)}}async function pl(e,t){const n=await e.text();if(n.length>1e6)throw hl(t,"The model endpoint response was too large.",502);try{const e=JSON.parse(n);if(!e||"object"!=typeof e||Array.isArray(e))throw new Error("not an object");return e}catch{throw hl(t,"The model endpoint returned invalid JSON.",502)}}function ul(e,t){return hl(e,401===t||403===t?"The model endpoint rejected the API key.":"The model endpoint rejected the request.",502,t)}function hl(e,t,n,s){return Object.assign(new Error(t),{code:e,statusCode:n,...s?{details:{upstreamStatus:s}}:{}})}function ml(e,t){e.includes(t)||e.push(t)}function gl(e){const t=new Set;return e.filter(e=>!t.has(e.id)&&(t.add(e.id),!0))}class yl{options;constructor(e){this.options=e}list(){return this.listAll().map(uc)}async listFederated(e,t=!1){const n=this.options.listNodes(),s=t?this.options.gateway.readFleetModels(n):await this.options.gateway.listFleetModels(n,{signal:e});t&&this.options.gateway.refreshFleetModels(n);const i=new Map;for(const e of this.listAll())i.set(e.id,{id:e.id,model:uc(e),locations:[{type:"control-plane",name:e.name,enabled:e.enabled,order:e.order}],referenceCount:0});for(const{nodeId:e,model:t}of s.items){const{referenceCount:n,...s}=t,r=i.get(t.id);r?(r.locations.push({type:"node",nodeId:e,name:t.name,enabled:t.enabled,order:t.order,referenceCount:t.referenceCount}),r.referenceCount+=t.referenceCount):i.set(t.id,{id:t.id,model:s,locations:[{type:"node",nodeId:e,name:t.name,enabled:t.enabled,order:t.order,referenceCount:t.referenceCount}],referenceCount:t.referenceCount})}return sr.parse({models:[...i.values()].sort((e,t)=>e.model.order-t.model.order||e.model.name.localeCompare(t.model.name)),nodeDiagnostics:s.nodeErrors.map(e=>({nodeId:e.nodeId,code:e.code,message:e.message})),updatedAt:Eo()})}create(e){const t=Bc.parse(e),n=Eo(),s=ir(t),i=this.options.models.get(s),r=Yi.parse({...t,id:s,enabled:t.enabled??!0,order:t.order??this.nextOrder(),labels:t.labels||{},createdAt:i?.createdAt||n,updatedAt:n});return uc(this.options.models.put(r))}update(e,t){const n=Fc.parse(t),s=this.requireSecret(e),i=Yi.parse({...s,...n,key:n.key?.trim()?n.key:s.key,createdAt:s.createdAt,updatedAt:Eo()}),r=ir(i);return uc(this.options.models.put(Yi.parse({...i,id:r})))}delete(e){return this.requireSecret(e),this.options.models.delete(e)}reorder(e){const t=[...new Set(e)],n=new Map(this.options.models.list().map(e=>[e.id,e]));for(const e of t)n.has(e)||yc("MODEL_NOT_FOUND",`Model ${e} was not found.`);return t.forEach((e,t)=>{const s=n.get(e);this.options.models.put(Yi.parse({...s,order:100*(t+1),updatedAt:Eo()}))}),this.list()}createOnNode(e,t){return this.options.gateway.createModel(this.options.requireNode(e),t)}updateOnNode(e,t,n){return this.options.gateway.updateModel(this.options.requireNode(e),t,n)}deleteOnNode(e,t){return this.options.gateway.deleteModel(this.options.requireNode(e),t)}discover(e){const t=Uc.parse(e);return async function(e,t){const n=function(e){const t=cl(e),n=[],s=t.pathname.split("/").filter(Boolean).at(-1)||"";return ml(n,dl(t.toString(),/^v\d+$/.test(s)?"models":"v1/models")),ml(n,new URL("/v1/models",t.origin).toString()),ml(n,new URL("/models",t.origin).toString()),n}(t.endpoint),s=Date.now();let i;for(const r of n){const n=await ll(e,r,{method:"GET",headers:{accept:"application/json",authorization:`Bearer ${t.key}`}});if(404===n.status||405===n.status){i=n.status;continue}if(!n.ok)throw ul("MODEL_DISCOVERY_FAILED",n.status);const o=await pl(n,"MODEL_DISCOVERY_RESPONSE_INVALID"),a=Array.isArray(o.data)?o.data:void 0;if(!a)throw hl("MODEL_DISCOVERY_RESPONSE_INVALID","The model endpoint returned an invalid model list.",502);return{models:gl(a.flatMap(e=>{if(!e||"object"!=typeof e||Array.isArray(e))return[];const t=e,n="string"==typeof t.id?t.id.trim():"";if(!n)return[];const s="string"==typeof t.owned_by?t.owned_by.trim():"";return[{id:n,...s?{ownedBy:s}:{}}]}).sort((e,t)=>e.id.localeCompare(t.id))),latencyMs:Date.now()-s}}throw hl("MODEL_DISCOVERY_UNSUPPORTED","No compatible model-list endpoint was found for this endpoint.",502,i)}(this.options.fetchImpl,this.resolvePrivateInput(t))}test(e){const t=Hc.parse(e);return async function(e,t){const n=Date.now(),s="codex"===t.app?await ll(e,dl(t.endpoint,"responses"),{method:"POST",headers:{accept:"application/json",authorization:`Bearer ${t.key}`,"content-type":"application/json"},body:JSON.stringify({model:t.model,input:"Reply with OK.",max_output_tokens:32,stream:!1})}):await ll(e,function(e){const t=cl(e),n=t.pathname.split("/").filter(Boolean).at(-1)||"";return dl(t.toString(),/^v\d+$/.test(n)?"messages":"v1/messages")}(t.endpoint),{method:"POST",headers:{accept:"application/json","anthropic-version":"2023-06-01","content-type":"application/json","x-api-key":t.key},body:JSON.stringify({model:t.model,max_tokens:8,messages:[{role:"user",content:"Reply with OK."}]})});if(!s.ok)throw ul("MODEL_TEST_FAILED",s.status);if((await pl(s,"MODEL_TEST_RESPONSE_INVALID")).error)throw hl("MODEL_TEST_RESPONSE_INVALID","The model endpoint returned an error payload.",502);return{success:!0,latencyMs:Date.now()-n}}(this.options.fetchImpl,this.resolvePrivateInput(t))}discoverOnNode(e,t){const n=this.options.requireNode(e);return fl(n),this.options.gateway.discoverModels(n,t)}testOnNode(e,t){const n=this.options.requireNode(e);return fl(n),this.options.gateway.testModel(n,t)}require(e,t=!1){const n=this.requireSecret(e);return t?n:uc(n)}async prepareAssignment(e,t){const n=await this.options.gateway.listModels(e),s={...null===t.codexModelHash?{codexModelHash:null}:t.codexModelHash?.trim()?{codexModelHash:t.codexModelHash.trim()}:{},...null===t.claudeModelHash?{claudeModelHash:null}:t.claudeModelHash?.trim()?{claudeModelHash:t.claudeModelHash.trim()}:{}},i=async(t,s)=>{if(null===s)return;const i=s?this.listAll().find(e=>e.id===s):this.listAll().find(e=>e.enabled&&e.app===t);if(i)return Il(i,t),await this.options.gateway.deployModel(e,i.id,i),i.id;if(!s)return;const r=n.find(e=>e.id===s);return r||yc("MODEL_NOT_FOUND",`Model ${s} was not found on control-plane or node ${e.id}.`),Il(r,t),r.id};return{modelSelection:s,codexModelHash:await i("codex",s.codexModelHash),claudeModelHash:await i("claude",s.claudeModelHash)}}async ensureInstanceAssignment(e){const t=this.options.requireNode(e.nodeId),n=await this.prepareAssignment(t,e.modelSelection);return this.options.gateway.assignInstanceModels(t,e.id,n)}listAll(){return this.options.models.list().map(e=>this.normalize(e)).sort((e,t)=>e.order-t.order||e.createdAt.localeCompare(t.createdAt)||e.id.localeCompare(t.id))}requireSecret(e){const t=this.options.models.get(e);return t||yc("MODEL_NOT_FOUND",`Model ${e} was not found.`),this.normalize(t)}normalize(e){const t=function(e){if(e&&"object"==typeof e&&!Array.isArray(e)){const t={...e};if(!("app"in t)){const e=Array.isArray(t.apps)?t.apps:[];t.app=e.includes("claude")&&!e.includes("codex")?"claude":"codex"}return delete t.apps,Yi.parse(t)}return Yi.parse(e)}(e);return t!==e&&this.options.models.put(t),t}nextOrder(){return this.options.models.list().reduce((e,t)=>Math.max(e,t.order),0)+100}resolvePrivateInput(e){const t=e.key?.trim()||(e.existingModelId?this.requireSecret(e.existingModelId).key:"");if(!t)throw Object.assign(new Error("An API key is required to contact the model endpoint."),{statusCode:400,code:"MODEL_API_KEY_REQUIRED"});return{...e,key:t}}}function fl(e){const t=e.capabilities.agent,n=t&&"object"==typeof t&&!Array.isArray(t)?t.capabilities:void 0;if(!n||"object"!=typeof n||Array.isArray(n)||!0!==n.modelEndpointProbe)throw Object.assign(new Error("This node agent does not support model endpoint discovery or testing."),{statusCode:409,code:"NODE_MODEL_ENDPOINT_PROBE_UNSUPPORTED"})}function Il(e,t){if(e.app!==t)throw Object.assign(new Error(`Model ${e.id} is not a ${t} model.`),{statusCode:400,code:"MODEL_APP_MISMATCH"});if(!e.enabled)throw Object.assign(new Error(`Model ${e.id} is disabled.`),{statusCode:400,code:"MODEL_DISABLED"})}class bl{requireNode;nodeAgentTransport;constructor(e){this.requireNode=e.requireNode,this.nodeAgentTransport=e.nodeAgentTransport}async request(e,t,n={},s){if(!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_UNREACHABLE"}),t}vl(e);const i=this.requireNode(e.nodeId),r=hc(n.headers),o=performance.now(),a=await this.nodeAgentTransport(i).request(i,`/instances/${encodeURIComponent(e.id)}/proxy`,{method:"POST",headers:{"content-type":"application/json",...r[ba]?{[ba]:r[ba]}:{}},body:JSON.stringify({path:`/api/${t.replace(/^\/+/,"")}`,method:n.method||"GET",headers:r,body:(d=n.body,"string"==typeof d?d:null==d?void 0:String(d))})});var d;const c=performance.now()-o,l=Sa(a.headers.get("server-timing"),va("node_transport",c));s?.({traceId:a.headers.get(ba)||void 0,serverTiming:l,nodeTransportMs:c});const p=await a.json().catch(()=>({}));if(!a.ok){const n=function(e){if(!e||"object"!=typeof e||Array.isArray(e))return;const t=e,n="string"==typeof t.code&&t.code.trim()?t.code:void 0,s="string"==typeof t.message&&t.message?t.message:void 0,i=t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?t.details:void 0,r="boolean"==typeof t.retryable?t.retryable:void 0;return n||s?{code:n,message:s,details:i,retryable:r}:void 0}(p.error),s=n?.message||function(e){if(!e||"object"!=typeof e||Array.isArray(e))return"";const t=e.message;return"string"==typeof t?t:""}(p.error)||`Instance request failed with HTTP ${a.status}`,i=500===a.status&&"NODE_AGENT_ERROR"===n?.code,r=new Error(s);throw Object.assign(r,{statusCode:i?502:a.status,code:i?"INSTANCE_PROXY_UPSTREAM_FAILED":n?.code||"INSTANCE_REQUEST_FAILED",...i?{retryable:!0}:"boolean"==typeof n?.retryable?{retryable:n.retryable}:{},...n?.details?{details:n.details}:{},instanceId:e.id,nodeId:e.nodeId,route:t}),r}return p.data??p}async proxyHttp(e,t,n={}){if("online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_UNREACHABLE"}),t}if(!e.target.web){const t=new Error(`Instance ${e.name} web endpoint is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_WEB_UNREACHABLE"}),t}vl(e);const s=this.requireNode(e.nodeId),i=await this.nodeAgentTransport(s).requestStream(s,`/instances/${encodeURIComponent(e.id)}/proxy/stream`,{method:"POST",headers:{"content-type":"application/json"},signal:n.signal,body:JSON.stringify({path:t,method:n.method||"GET",headers:hc(n.headers),...(r=n.body,null==r?{}:"string"==typeof r?{body:r}:Buffer.isBuffer(r)?{bodyBase64:r.toString("base64")}:r instanceof Uint8Array?{bodyBase64:Buffer.from(r).toString("base64")}:{body:String(r)})})});var r;return{status:i.status||502,headers:Object.fromEntries(i.headers.entries()),body:i.body}}proxyWebSocket(e,t,n,s,i={}){if(!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=new Error(`Instance ${e.name} web endpoint is not reachable.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_WEB_UNREACHABLE"}),t}vl(e);const r=this.requireNode(e.nodeId),o=n.startsWith("/")?n.slice(1):n;this.nodeAgentTransport(r).proxyWebSocket(r,t,`/instances/${encodeURIComponent(e.id)}/proxy/ws/${o}`,s,i)}async reportHeartbeat(e,t){if(!e.registrationToken)return;const n=this.requireNode(e.nodeId),s=`/instances/${encodeURIComponent(e.id)}/heartbeat`,i={method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e.registrationToken}`},body:JSON.stringify(t)},r=await this.nodeAgentTransport(n).request(n,s,i),o=await r.json().catch(()=>({}));if(!r.ok){const e=new Error(o.error?.message||`Instance heartbeat sync failed with HTTP ${r.status}`);throw Object.assign(e,{statusCode:r.status,code:"INSTANCE_HEARTBEAT_SYNC_FAILED"}),e}}}function vl(e){if(po(e))return;const t=new Error(`Instance ${e.name} is not ready.`);throw Object.assign(t,{statusCode:409,code:"INSTANCE_NOT_READY",runtimePhase:e.runtimeVersion?.phase}),t}class Sl{read(e){const t=new Map(e.projects.map(e=>[e.id,e])),n=new Map(e.images.map(e=>[e.id,e])),s=new Map(e.nodes.map(e=>[e.id,e])),i=new Map(e.runtimes.map(e=>[`${e.nodeId}:${e.id}`,e])),r=Date.now();return{items:e.instances.map(e=>function(e){const t=e.instance.lastHeartbeatAt?e.currentTime-Date.parse(e.instance.lastHeartbeatAt):void 0,n=void 0!==t&&t>3e4?"offline":e.instance.connectionStatus,s=pc(e.instance);return{...s,aiSessions:ft(s.aiSessions),connectionStatus:n,heartbeatAgeMs:t,project:e.project,image:e.image,node:e.node?cc(e.node):void 0,runtime:e.runtime,protocolCompatible:!e.instance.protocolVersion||e.instance.protocolVersion===ks}}({instance:e,currentTime:r,project:e.projectId?t.get(e.projectId):void 0,image:e.imageSnapshot||(e.imageSelection?n.get(e.imageSelection.imageId):void 0),node:s.get(e.nodeId),runtime:i.get(`${e.nodeId}:${e.runtimeId}`)})),nodeErrors:e.nodeErrors||[],nodeStates:e.nodeStates||[]}}}class wl{options;constructor(e){this.options=e}async create(e){const t=qc.parse(e),n=t.projectId?this.options.requireProject(t.projectId):void 0,s=t.runtimeId||n?.defaultRuntimeId||"runtime_local_docker",i=t.nodeId||n?.defaultNodeId||this.options.defaultNodeId();if(!i)throw zl("At least one node connection is required before creating an instance.",400,"NODE_REQUIRED");const r=this.options.requireNode(i),o=await this.options.requireRuntime(r.id,s),a=o.capabilities.requiresImage??"local"!==o.type,d=t.environmentSource||(t.imageSelection?{type:"image",imageSelection:t.imageSelection}:void 0)||(a&&n?.defaultImageSelection?{type:"image",imageSelection:n.defaultImageSelection}:void 0);if("template"===d?.type&&"docker"!==o.type)throw zl(`Runtime ${o.name} does not support environment templates.`,409,"ENVIRONMENT_TEMPLATE_RUNTIME_UNSUPPORTED");const c="image"===d?.type?d.imageSelection:void 0,l=c?this.options.resolveImageSelection(c):void 0,p="template"===d?.type?await this.options.gateway.getEnvironmentTemplate(r,d.environmentTemplateId):void 0;if(p&&"ready"!==p.status)throw zl(`Environment template ${p.id} is ${p.status}.`,409,"ENVIRONMENT_TEMPLATE_NOT_READY");if(p&&p.nodeId!==r.id)throw zl(`Environment template ${p.id} belongs to node ${p.nodeId}.`,409,"ENVIRONMENT_TEMPLATE_NODE_MISMATCH");if(a&&!l&&!p)throw zl(`Runtime ${o.name} requires an image.`,400,"RUNTIME_IMAGE_REQUIRED");const u=await this.resolveSource({node:r,runtime:o,project:n,source:t.source,sourceSnapshot:t.sourceSnapshot,imageOption:l}),h=await this.options.prepareModels(r,t.modelSelection||{}),m=l?function(e){const t=Eo();return{id:e.id,origin:e.origin,name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover,repository:e.repository,tag:e.tag,requestedReference:e.reference,resolvedDigest:e.digest,resolvedReference:e.digest?`${e.repository}@${e.digest}`:void 0,downloadSizeBytes:e.downloadSizeBytes,pullPolicy:"if-not-present",capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,market:e.market,createdAt:t,updatedAt:t}}(l):void 0,g=await this.options.gateway.createInstance(r,{id:t.id,name:t.name,runtimeId:s,...d?{environmentSource:d}:{},...l&&m?{image:m}:{},projectId:n?.id,source:u.value,sourceSnapshot:u.snapshot,config:t.config,modelSelection:{}});let y=g;try{y=(await this.options.gateway.assignInstanceModels(r,g.id,h)).instance}catch(e){throw await this.options.gateway.deleteInstance(r,g.id,{deleteVolumes:!0}).catch(()=>{}),e}let f={status:"not-requested"};if(t.start)try{y=await this.options.gateway.startInstance(r,y.id),f={status:"started"}}catch(e){f={status:"failed",error:Al(e,"INSTANCE_START_FAILED")},y=await this.options.gateway.listInstances(r).then(e=>e.find(e=>e.id===y.id)||y).catch(()=>y)}return{...pc(y),registrationToken:y.registrationToken,startOutcome:f}}async resolveSource(e){let t=e.source||e.project?.source,n=e.sourceSnapshot||(e.project?e.project:{});if(!t)throw zl("Instance source is required.",400,"INSTANCE_SOURCE_REQUIRED");if("local"===e.runtime.type&&"local-folder"!==t.type)throw zl("Localhost runtime currently supports local folder sources only.",400,"LOCAL_RUNTIME_REQUIRES_LOCAL_FOLDER");if("local-folder"!==t.type)return{value:t,snapshot:n};if(t.ownerNodeId&&t.ownerNodeId!==e.node.id)throw zl(`Local folder ${t.path} belongs to node ${t.ownerNodeId}, not ${e.node.id}.`,400,"LOCAL_FOLDER_REQUIRES_OWNER_NODE");const s=t.localFolderId?await this.options.requireLocalFolder(e.node,t.localFolderId):await this.options.gateway.createLocalFolder(e.node,{name:"string"==typeof n.name?n.name:"Local folder",path:t.path,defaultImageSelection:e.imageOption?{imageId:e.imageOption.id,tag:e.imageOption.tag}:void 0});return t={...t,localFolderId:s.id,ownerNodeId:s.nodeId,path:s.path},n=s,{value:t,snapshot:n}}}function Al(e,t){const n=e&&"object"==typeof e?e:{};return{code:"string"==typeof n.code&&n.code.trim()?n.code:t,message:"string"==typeof n.message&&n.message.trim()?n.message:String(e)}}function zl(e,t,n){return Object.assign(new Error(e),{statusCode:t,code:n})}class kl{triggers;listInstances;listMutationInstances;requireInstance;instanceRequest;constructor(e){this.triggers=e.triggers,this.listInstances=e.listInstances,this.listMutationInstances=e.listMutationInstances??(async()=>({items:await e.listInstances(),partialFailures:[]})),this.requireInstance=e.requireInstance,this.instanceRequest=e.instanceRequest}async listTriggers(){const e=await this.listInstances(),t=new Map;for(const e of this.triggers.list())t.set(e.configHash,{configHash:e.configHash,config:Cl(e),deploymentCount:0,enabledCount:0,runningCount:0,errorCount:0,ownedByControlPlane:!0,controlPlaneDeploymentCount:0,deployments:[],recentRuns:[]});for(const n of e){const e=n.triggers;for(const s of e?.configs||[]){const i=t.get(s.configHash)||{configHash:s.configHash,config:s.config,deploymentCount:0,enabledCount:0,runningCount:0,errorCount:0,ownedByControlPlane:!1,controlPlaneDeploymentCount:0,deployments:[],recentRuns:[]},r=(s.deployments||[]).map(e=>({instanceId:n.id,instanceName:n.name,deployment:e,runtime:(s.runtime||[]).find(t=>t.deploymentId?t.deploymentId===e.deploymentId:t.configHash===e.configHash)}));i.deploymentCount+=r.length,i.enabledCount+=r.filter(e=>Boolean(e.deployment.enabled)).length,i.controlPlaneDeploymentCount+=r.filter(e=>"control-plane"===e.deployment.origin).length,i.runningCount+=(s.runtime||[]).filter(e=>"running"===e.status).length,i.errorCount+=(s.runtime||[]).filter(e=>"error"===e.status).length,i.deployments.push(...r),i.recentRuns.push(...(e.recentRuns||[]).filter(e=>e.configHash===s.configHash).map(e=>({...e,instanceId:n.id,instanceName:n.name}))),t.set(s.configHash,i)}}return $n.parse({updatedAt:(new Date).toISOString(),triggers:[...t.values()].sort((e,t)=>String(e.config.name||e.configHash).localeCompare(String(t.config.name||t.configHash)))})}createTrigger(e){const t=_c.parse(e||{}),n=Eo(),s={maxConcurrentRuns:t.policy?.maxConcurrentRuns??1,whenBusy:t.policy?.whenBusy??"skip",cooldownMs:t.policy?.cooldownMs},i=Bn({source:t.source,action:t.action,policy:s}),r=Oc.parse({id:i,configHash:i,name:t.name,description:t.description,source:t.source,action:t.action,policy:s,createdAt:n,updatedAt:n});return this.triggers.put(r)}async updateTrigger(e,t){const n=this.requireTrigger(e),s=Pc.parse(t||{}),i=Eo(),r={maxConcurrentRuns:s.policy?.maxConcurrentRuns??1,whenBusy:s.policy?.whenBusy??"skip",cooldownMs:s.policy?.cooldownMs},o=Bn({source:s.source,action:s.action,policy:r});if(o!==e&&this.triggers.get(o)){const e=new Error(`Trigger ${o} already exists.`);throw Object.assign(e,{statusCode:409,code:"TRIGGER_ALREADY_EXISTS"}),e}const a=Oc.parse({id:o,configHash:o,name:s.name,description:s.description,source:s.source,action:s.action,policy:r,createdAt:n.createdAt,updatedAt:i}),d=await this.listMutationInstances(),c=await Tl(d.items,8,async t=>{const n=[],s=[],i=t.triggers?.configs?.find(t=>t.configHash===e),r=(i?.deployments||[]).filter(e=>"control-plane"===e.origin);if(o===e){if(r.length)try{const s=await this.instanceRequest(t,`/triggers/${encodeURIComponent(e)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({name:a.name,description:a.description??null})});n.push({instanceId:t.id,data:s})}catch(e){s.push(El(t,e))}return{results:n,partialFailures:s}}for(const i of r){const r="ai-session"===i.target.type?xl(i.target.aiSessionId,o):i.deploymentId;try{const s=await this.instanceRequest(t,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:a.name,description:a.description,source:a.source,action:a.action,policy:a.policy,deployment:{deploymentId:r,origin:"control-plane",enabled:i.enabled,target:i.target,localName:i.localName}})}),o=i.deploymentId||i.configHash;await this.instanceRequest(t,`/triggers/${encodeURIComponent(e)}/deployments/${encodeURIComponent(o)}`,{method:"DELETE"}),n.push({instanceId:t.id,deploymentId:r,data:s})}catch(e){s.push(El(t,e))}}return{results:n,partialFailures:s}}),l=c.flatMap(e=>e.results),p=[...d.partialFailures,...c.flatMap(e=>e.partialFailures)];return this.triggers.put(a),o!==e&&this.triggers.delete(e),{previousConfigHash:e,trigger:a,results:l,partialFailures:p}}async deleteTrigger(e){const t=await this.listMutationInstances(),n=this.triggers.delete(e),s=await Tl(t.items,8,async t=>{const n=[],s=[],i=t.triggers?.configs?.find(t=>t.configHash===e);if(!i)return{results:n,partialFailures:s};const r=(i.deployments||[]).filter(e=>"control-plane"===e.origin);if(!r.length)return{results:n,partialFailures:s};const o=i.deployments.every(e=>"control-plane"===e.origin);for(const i of r)try{const r=i.deploymentId?`/triggers/${encodeURIComponent(e)}/deployments/${encodeURIComponent(i.deploymentId)}`:o?`/triggers/${encodeURIComponent(e)}`:void 0;if(!r){n.push({instanceId:t.id,configHash:e,deploymentId:i.deploymentId,deleted:!1,skipped:"missing-deployment-id"}),s.push({scope:"instance",nodeId:t.nodeId,instanceId:t.id,code:"TRIGGER_DEPLOYMENT_ID_MISSING",message:`Trigger deployment on instance ${t.name} has no deletable deployment id.`});continue}const a=await this.instanceRequest(t,r,{method:"DELETE"});if(n.push({instanceId:t.id,configHash:e,deploymentId:i.deploymentId,deleted:!0,data:a}),!i.deploymentId)break}catch(r){s.push(El(t,r)),n.push({instanceId:t.id,configHash:e,deploymentId:i.deploymentId,deleted:!1,error:r instanceof Error?r.message:String(r)})}return{results:n,partialFailures:s}}),i=s.flatMap(e=>e.results),r=[...t.partialFailures,...s.flatMap(e=>e.partialFailures)];return n||i.length||yc("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),{configHash:e,deletedTemplate:n,results:i,partialFailures:r}}async applyTrigger(e,t){const n=this.requireTrigger(e),s=jc.parse(t||{});return{configHash:e,results:await Tl(s.instanceIds,8,async e=>{const t=await this.requireInstance(e);return{instanceId:e,data:await this.instanceRequest(t,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:n.name,description:n.description,source:n.source,action:n.action,policy:n.policy,deployment:{origin:"control-plane",enabled:s.enabled??!0,target:s.target}})})}})}}async listInstanceTriggers(e){const t=await this.requireInstance(e);return this.instanceRequest(t,"/triggers")}async bindAiSessionTrigger(e,t,n){const s=Dc.parse(n||{}),i=this.requireTrigger(s.configHash),r=await this.requireInstance(e);return this.instanceRequest(r,"/triggers",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:i.name,description:i.description,source:i.source,action:i.action,policy:i.policy,deployment:{deploymentId:xl(t,s.configHash),origin:"control-plane",enabled:s.enabled??!0,target:{type:"ai-session",aiSessionId:t}}})})}async unbindAiSessionTrigger(e,t,n){const s=await this.requireInstance(e),i=xl(t,n);return this.instanceRequest(s,`/triggers/${encodeURIComponent(n)}/deployments/${encodeURIComponent(i)}`,{method:"DELETE"})}async runInstanceTrigger(e,t,n={}){const s=await this.requireInstance(e);return this.instanceRequest(s,`/triggers/${encodeURIComponent(t)}/run`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n||{})})}requireTrigger(e){const t=this.triggers.get(e);return t||yc("TRIGGER_NOT_FOUND",`Trigger ${e} was not found.`),t}}async function Tl(e,t,n){const s=new Array(e.length);let i,r=0,o=!1;if(await Promise.all(Array.from({length:Math.min(t,e.length)},async()=>{for(;!o&&r<e.length;){const t=r++;try{s[t]=await n(e[t],t)}catch(e){o=!0,i=e}}})),o)throw i;return s}function Cl(e){return{configHash:e.configHash,name:e.name,...void 0!==e.description?{description:e.description}:{},source:e.source,action:e.action,policy:e.policy,createdAt:e.createdAt,updatedAt:e.updatedAt}}function El(e,t){const n=t&&"object"==typeof t?t:void 0,s="string"==typeof n?.code&&n.code?n.code:"TRIGGER_INSTANCE_MUTATION_FAILED",i="string"==typeof n?.message&&n.message?n.message:String(t);return{scope:"instance",nodeId:e.nodeId,instanceId:e.id,code:s.slice(0,160),message:i.slice(0,4e3)}}function xl(e,t){return`ai_${Buffer.from(e).toString("base64url")}_${t}`}class Nl{options;constructor(e){this.options=e}getSettings(){return Tc.parse(this.options.settings.get())}updateSettings(e){const t=Cc.parse(e),n=Tc.parse({...this.getSettings(),...t,..."publicBaseUrl"in t?{publicBaseUrl:t.publicBaseUrl?.trim()||void 0}:{}});return this.options.settings.put(n)}seedDefaults(){}listProjects(){return this.options.projects.list().map(e=>this.normalizeProjectRecord(e))}getProject(e){const t=this.options.projects.get(e);return t?this.normalizeProjectRecord(t):void 0}createProject(e){const t=vc.parse(e),n=Eo(),s=Gi.parse(t.source);return this.options.projects.put(Ji.parse({...t,id:t.id||Po("proj"),source:s,defaultImageSelection:t.defaultImageSelection||{imageId:"market_taskhandoff_browser"},defaultNodeId:t.defaultNodeId||this.options.defaultNodeId(),defaultRuntimeId:t.defaultRuntimeId||"runtime_local_docker",workspacePolicy:Vi.parse(t.workspacePolicy||lc(s)),labels:t.labels||{},createdAt:n,updatedAt:n}))}updateProject(e,t){const n=Sc.parse(t),s=this.requireProject(e),i=n.source?Gi.parse(n.source):s.source;return this.options.projects.put(Ji.parse({...s,...n,id:e,source:i,workspacePolicy:n.workspacePolicy?Vi.parse(n.workspacePolicy):s.workspacePolicy,createdAt:s.createdAt,updatedAt:Eo()}))}deleteProject(e){return this.options.projects.delete(e)}requireProject(e){const t=this.getProject(e);return t||yc("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}listImages(){return this.options.images.list()}getMarketCatalog(){return{catalog:this.options.market.getCatalog(),status:this.options.market.getStatus()}}listImageOptions(e){return[...this.options.market.getCatalog().items.map(t=>this.marketImageOption(t,void 0,e,!0)),...this.listImages().map(e=>this.customImageOption(e))]}resolveImageSelection(e,t){const n=this.options.market.getCatalog().items.find(t=>t.id===e.imageId);if(n)return this.marketImageOption(n,e.tag,t);const s=this.options.images.get(e.imageId);if(s||yc("IMAGE_NOT_FOUND",`Image ${e.imageId} was not found.`),e.tag&&e.tag!==s.tag)throw Object.assign(new Error(`Custom image ${s.id} cannot override its stored tag.`),{statusCode:400,code:"CUSTOM_IMAGE_TAG_OVERRIDE"});return this.customImageOption(s)}createImage(e){const t=Ec.parse(e),n=Eo(),s=Gs(t.reference);return this.options.images.put(fr.parse({...t,id:t.id||Po("img"),origin:"custom",reference:s.reference,repository:s.repository,tag:s.tag,pullPolicy:t.pullPolicy||"if-not-present",capabilities:t.capabilities||[],optionalApps:t.optionalApps||[],defaultEnv:t.defaultEnv||{},labels:t.labels||{},createdAt:n,updatedAt:n}))}updateImage(e,t){const n=xc.parse(t),s=this.requireImage(e),i=Gs(n.reference||s.reference);return this.options.images.put(fr.parse({...s,...n,id:e,origin:"custom",reference:i.reference,repository:i.repository,tag:i.tag,createdAt:s.createdAt,updatedAt:Eo()}))}deleteImage(e){return this.options.images.delete(e)}requireImage(e){if(this.options.market.getCatalog().items.some(t=>t.id===e))throw Object.assign(new Error(`Market image ${e} is read-only.`),{statusCode:403,code:"MARKET_IMAGE_READ_ONLY"});const t=this.options.images.get(e);return t||yc("IMAGE_NOT_FOUND",`Image ${e} was not found.`),t}normalizeProjectRecord(e){const t=function(e){if(e&&"object"==typeof e&&!Array.isArray(e)){const t={...ci(e)};return"defaultRuntimeId"in t||(t.defaultRuntimeId="runtime_local_docker"),Ji.parse(t)}return Ji.parse(e)}(e);return t!==e&&this.options.projects.put(t),t}customImageOption(e){return br.parse({id:e.id,origin:"custom",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||dr,repository:e.repository,tag:e.tag,availableTags:e.tag?[{name:e.tag,reference:e.reference,status:"active"}]:[],reference:e.reference,capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,readOnly:!1})}marketImageOption(e,t,n,s=!1){if("yanked"===e.status&&!s)throw Object.assign(new Error(`Market image ${e.id} is no longer selectable.`),{statusCode:409,code:"MARKET_IMAGE_YANKED"});const i=t||e.defaultTag,r=e.tags.find(e=>e.name===i);if(!r)throw Object.assign(new Error(`Market image ${e.id} does not provide tag ${i}.`),{statusCode:400,code:"MARKET_IMAGE_TAG_NOT_FOUND"});if("yanked"===r.status&&!s)throw Object.assign(new Error(`Market image tag ${e.id}:${i} is no longer selectable.`),{statusCode:409,code:"MARKET_IMAGE_TAG_YANKED"});const o=r.platforms.find(e=>!(n?.os&&e.os!==n.os||n?.architecture&&e.architecture!==n.architecture)),a=this.options.market.getCatalog();return br.parse({id:e.id,origin:"market",name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:e.cover||dr,repository:e.repository,tag:r.name,availableTags:e.tags.map(e=>({name:e.name,version:e.version,reference:e.reference,manifestDigest:e.manifestDigest,status:e.status})),reference:r.reference,digest:o?.digest||r.manifestDigest,downloadSizeBytes:o?.downloadSizeBytes,unpackedSizeBytes:o?.unpackedSizeBytes,capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:e.defaultEnv,labels:e.labels,readOnly:!0,lifecycleStatus:"yanked"===r.status||"yanked"===e.status?"yanked":"deprecated"===r.status||"deprecated"===e.status?"deprecated":"active",market:{catalogId:a.catalogId,catalogRevision:a.revision,publisher:e.publisher,version:r.version}})}}function Rl(e){const t=Gs(e.reference),n=t.tag||"latest";return{id:e.id,publisher:"task-handoff",slug:e.slug,name:e.name,description:e.description,localizedDescriptions:e.localizedDescriptions,cover:dr,repository:t.repository,defaultTag:n,tags:[{name:n,reference:t.reference,platforms:[],status:"active"}],capabilities:e.capabilities,optionalApps:e.optionalApps,defaultEnv:{},labels:{"task-handoff.image.kind":"controlled-instance","task-handoff.image.profile":e.slug},status:"active"}}function Ol(){const e=(t=process.env.TASK_HANDOFF_BUILT_AT)&&!Number.isNaN(Date.parse(t))?new Date(t).toISOString():(new Date).toISOString();var t;return gr.parse({protocolVersion:"2026-07-29",catalogId:"task_handoff_embedded",revision:process.env.TASK_HANDOFF_VERSION||"0.0.1",source:"embedded",generatedAt:e,items:[Rl({id:"market_taskhandoff_codex",slug:"codex",name:"TaskHandoff Codex",description:"Minimal Codex runtime with terminal and Codex.",localizedDescriptions:{"zh-CN":"最小 Codex 运行环境,包含终端和 Codex。"},reference:process.env.TASK_HANDOFF_CONTROLLED_CODEX_IMAGE||"huadream/task-handoff-controlled-codex:latest",capabilities:["terminal","codex"],optionalApps:["terminal-tty"]}),Rl({id:"market_taskhandoff_ai",slug:"ai",name:"TaskHandoff Codex + Claude",description:"AI development runtime with Codex, Claude, and terminal.",localizedDescriptions:{"zh-CN":"AI 开发运行环境,包含 Codex、Claude 和终端。"},reference:process.env.TASK_HANDOFF_CONTROLLED_AI_IMAGE||"huadream/task-handoff-controlled-ai:latest",capabilities:["terminal","codex","claude"],optionalApps:["terminal-tty"]}),Rl({id:"market_taskhandoff_webcap",slug:"webcap",name:"TaskHandoff WebCap",description:"Browser automation runtime with WebCap, Codex, Claude, Chromium, and VNC.",localizedDescriptions:{"zh-CN":"浏览器自动化运行环境,包含 WebCap、Codex、Claude、Chromium 和 VNC。"},reference:process.env.TASK_HANDOFF_CONTROLLED_WEB_CAP_IMAGE||"huadream/task-handoff-controlled-webcap:latest",capabilities:["browser","terminal","gui-terminal","web-cap","codex","claude"],optionalApps:["chromium","terminal-tty","gui-terminal"]}),Rl({id:"market_taskhandoff_browser",slug:"browser",name:"TaskHandoff Browser",description:"Full runtime with Codex, Claude, Chromium, VNC, and code-server.",localizedDescriptions:{"zh-CN":"完整运行环境,包含 Codex、Claude、Chromium、VNC 和 code-server。"},reference:process.env.TASK_HANDOFF_CONTROLLED_BROWSER_IMAGE||"huadream/task-handoff-controlled-browser:latest",capabilities:["browser","terminal","gui-terminal","vscode-web","codex","claude"],optionalApps:["chromium","terminal-tty","gui-terminal","vscode-web"]})]})}class _l{async loadCatalog(){return Ol()}}class Pl{snapshot;status;constructor(e=Ol()){this.snapshot=gr.parse(e),this.status=yr.parse({source:this.snapshot.source,state:"ready",revision:this.snapshot.revision,updatedAt:this.snapshot.generatedAt})}getCatalog(){return this.snapshot}getStatus(){return this.status}acceptCandidate(e){const t=gr.safeParse(e);return t.success?(this.snapshot=t.data,this.status=yr.parse({source:t.data.source,state:"ready",revision:t.data.revision,updatedAt:(new Date).toISOString()}),{accepted:!0,snapshot:t.data}):(this.status=yr.parse({...this.status,state:"failed",updatedAt:(new Date).toISOString(),error:t.error.message}),{accepted:!1,error:t.error})}recordRefreshFailure(e){return this.status=yr.parse({...this.status,state:this.snapshot?"stale":"failed",updatedAt:(new Date).toISOString(),error:e instanceof Error?e.message:String(e)}),this.snapshot}async refresh(e){try{const t=await e.loadCatalog();return this.acceptCandidate(t)}catch(e){return this.recordRefreshFailure(e),{accepted:!1,error:e}}}}class jl{records=new Map;options;constructor(e){this.options=e}create(e){const t=s.randomBytes(this.options.tokenBytes).toString("base64url"),n={...e,token:t,expiresAt:new Date(Date.now()+(e.ttlMs||this.options.ttlMs)).toISOString()};return this.records.set(t,n),n}resolve(e,t){const n=this.records.get(e);if(!n)throw this.invalidError();if(n.expiresAt<=(new Date).toISOString())throw this.records.delete(e),this.invalidError();if(t&&!t(n))throw this.invalidError();return n}revoke(e,t){const n=this.resolve(e,t);return this.records.delete(e),n}invalidError(){const e=new Error(this.options.invalidMessage);return Object.assign(e,{statusCode:this.options.invalidStatusCode||400,code:this.options.invalidCode}),e}}class Dl{requireInstance;listAppSessions;tokens=new jl({invalidMessage:"App access link is invalid or expired.",invalidCode:"APP_ACCESS_TOKEN_INVALID",invalidStatusCode:401,tokenBytes:24,ttlMs:9e5});constructor(e){this.requireInstance=e.requireInstance,this.listAppSessions=e.listAppSessions}createToken(e){return this.tokens.create({instanceId:e.instanceId,sessionId:e.sessionId,mode:e.mode,ttlMs:e.ttlMs})}async createSessionToken(e){await this.requireInstance(e.instanceId);const t=await this.requireSession(e.instanceId,e.sessionId),n=Qt(t);if("vnc"!==n){const e=new Error("This app session does not expose a VNC view.");throw Object.assign(e,{statusCode:409,code:"APP_SESSION_ACCESS_UNAVAILABLE"}),e}if("running"!==t.status){const e=new Error("The app session is not running.");throw Object.assign(e,{statusCode:409,code:"APP_SESSION_NOT_RUNNING"}),e}return this.createToken({...e,mode:n})}resolveToken(e,t){return this.tokens.resolve(e,e=>!t||e.mode===t)}revokeToken(e,t){this.tokens.revoke(e,e=>e.instanceId===t.instanceId&&e.sessionId===t.sessionId)}async proxyTarget(e,t,n=""){const s=this.resolveToken(e,t),i=await this.requireInstance(s.instanceId),r=await this.requireSession(s.instanceId,s.sessionId);return{access:s,instance:i,session:r,path:Ml(t,s.sessionId,r,n)}}async requireSession(e,t){const n=await this.listAppSessions(),s=n.instances.find(t=>t.instanceId===e)?.appSessions.sessions.find(e=>ql(e.id)===t);if(s)return s;const i=new Error("App session was not found.");throw Object.assign(i,{statusCode:404,code:"APP_SESSION_NOT_FOUND"}),i}}function Ml(e,t,n,s=""){return"tty"===e?`/api/apps/sessions/${encodeURIComponent(t)}/tty`:"vnc"===e?s?function(e,t){const n=`/${t.replace(/^\/+/,"")}`,s=n.split("?",1)[0]||"/",i=encodeURIComponent(e);if(!["/api/novnc/",`/api/apps/sessions/${i}/web/`,`/api/apps/sessions/${i}/vnc`,`/api/apps/sessions/${i}/novnc/`].some(e=>s===e.replace(/\/$/,"")||s.startsWith(e))){const e=new Error("App access token cannot be used for this path.");throw Object.assign(e,{statusCode:403,code:"APP_ACCESS_PATH_FORBIDDEN"}),e}return n}(t,s):ql(Ll(n.vnc).noVncPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`:ql(Ll(n.web).webPath)||`/api/apps/sessions/${encodeURIComponent(t)}/web/`}function Ll(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function ql(e){return"string"==typeof e&&e.trim()?e.trim():void 0}const $l={allow:"a",deny:"d",skip:"s"};function Bl(e){return s.createHash("sha256").update(e).digest("base64url").slice(0,Math.ceil(16))}class Fl{tokens=new jl({invalidMessage:"Chat action expired.",invalidCode:"CHAT_ACTION_TOKEN_INVALID",tokenBytes:9,ttlMs:6e5});create(e){return this.tokens.create({type:e.type,instanceId:"instanceId"in e?e.instanceId:void 0,appId:"appId"in e?e.appId:void 0,routeId:"routeId"in e?e.routeId:void 0,decision:"decision"in e?e.decision:void 0,ttlMs:e.ttlMs})}resolve(e,t){return this.tokens.resolve(e,e=>!t||e.type===t)}pendingDecisionCallbackData(e,t){return`task_handoff:cp_p:v1:${$l[t]}:${Bl(e)}`}}function Ul(e){const{token:t,...n}=e;return{...n,settings:Wl(e.settings),tokenSet:Boolean(e.token)}}function Hl(e,t){if(!t)return e;const n={...e};for(const[e,s]of Object.entries(t))void 0!==s&&""!==s&&(n[e]=s);return n}function Wl(e){const t={...e};return"string"==typeof t.clientSecret&&t.clientSecret&&(delete t.clientSecret,t.clientSecretSet=!0),"string"==typeof t.appSecret&&t.appSecret&&(delete t.appSecret,t.appSecretSet=!0),t}class Gl{chatBridges;chatSessions;constructor(e){this.chatBridges=e.chatBridges,this.chatSessions=e.chatSessions}list(){return this.chatBridges.list().map(Ul)}require(e){const t=this.chatBridges.get(e);return t||yc("CHAT_BRIDGE_NOT_FOUND",`Chat bridge ${e} was not found.`),t}create(e){const t=Rc.parse(e),n=Eo(),s=oo.parse({...t,id:Po(`chat_${t.channel}`),name:t.name||(i=t.channel,r=this.chatBridges.list().filter(e=>e.channel===t.channel).length+1,`${"telegram"===i?"Telegram":"wechat"===i?"WeChat":"dingding"===i?"DingDing":"lark"===i?"Lark":"Web"} ${r}`),enabled:t.enabled??!1,allowedUserIds:t.allowedUserIds||[],pollIntervalMs:t.pollIntervalMs||3e3,settings:Hl({},t.settings),createdAt:n,updatedAt:n});var i,r;return this.chatBridges.put(s),Ul(s)}update(e,t){const n=Nc.parse(t),s=this.require(e),i=Hl(s.settings,n.settings),r=oo.parse({...s,...n,id:e,channel:s.channel,name:n.name||s.name,settings:i,updatedAt:Eo()});return this.chatBridges.put(r),Ul(r)}delete(e){const t=this.chatBridges.delete(e);if(t)for(const t of this.chatSessions.list())t.bridgeId===e&&this.chatSessions.delete(t.id);return t}}class Vl{chatSessions;constructor(e){this.chatSessions=e.chatSessions}list(){return this.chatSessions.list()}require(e){const t=this.chatSessions.get(e);return t||yc("CHAT_SESSION_NOT_FOUND",`Chat session ${e} was not found.`),t}upsert(e){const t=Eo(),n=(s=e.channel,i=e.chatSessionId,`${e.bridgeId||s}:${i.replace(/[^a-zA-Z0-9_.:-]/g,"_")}`);var s,i;const r=this.chatSessions.get(n),o=ao.parse({...r||{},...e,id:n,channel:e.channel,bridgeId:e.bridgeId,chatSessionId:e.chatSessionId,lastUsedAt:t,createdAt:r?.createdAt||t,updatedAt:t});return this.chatSessions.put(o),o}}function Kl(e){return{inline_keyboard:e.map(e=>e.map(e=>({text:e.text,...e.url?{url:e.url}:{callback_data:e.callbackData||""}})))}}function Jl(e,t=40){return Kl(e.slice(0,t).map(e=>[e]))}function Yl(e){return Buffer.from(e,"utf8").toString("base64url")}function Ql(e){const t=Zl(e).inline_keyboard,n=Array.isArray(t)?t:[],s=[];for(const e of n)if(Array.isArray(e))for(const t of e){const e=Zl(t),n=String(e.callback_data||""),i=String(e.text||"").trim();i&&n&&s.push({text:i,id:`th_cb_${Yl(n)}`})}return s.slice(0,40)}function Xl(e,t){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function Zl(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function ep(e){return(e.aiSessions?.sessions||[]).filter(t=>function(e,t){const n=(e.apps?.sessions||[]).filter(op);if(t.appSessionId&&n.some(e=>e.id===t.appSessionId))return!0;const s=new Set(t.appBindingKeys||[]);return Boolean(s.size&&n.some(e=>function(e){return[...Kt(e).bindings.map(Xt),...en(e)].filter(Boolean)}(e).some(e=>s.has(e))))}(e,t))}function tp(e){return"waiting"===e.status?4:"failed"===e.status?3:"running"===e.status?2:"idle"===e.status?1:0}function np(e){return[e.cwd||"",e.agent||"",e.providerSessionId||e.id].join("\0")}function sp(e){const t=e.session.title||e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=t?` - ${Xl(t,18)}`:"";return`${e.instance.name} - ${e.session.agent} ${e.session.status}${n}`}function ip(e,t=(e,t)=>`task_handoff:approval:${e.id}:${t}`){return Jl(e.flatMap(e=>"approval"!==e.kind?[]:[{text:Xl(`Allow ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"allow")},{text:Xl(`Skip ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"skip")},{text:Xl(`Deny ${e.instance?.name||e.instanceId} / ${e.aiSessionId}`,56),callbackData:t(e,"deny")}]))}function rp(e){const t=`${e.project?.name||e.projectId} / ${e.instance?.name||e.instanceId}`,n="approval"===e.kind?`/approve ${e.id} | /deny ${e.id} | /skip ${e.id}`:`/reply ${e.id} <message>`;return`[${t}] ${e.kind} ${e.id}: ${e.result}\n${n}`}function op(e){const t=e&&"object"==typeof e&&!Array.isArray(e)?e:{};return Yt("string"==typeof t.status?t.status:void 0)}class ap{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleAiSessionsCommand(e){const t=await this.targets.aiSessionChoices(e),n=t.find(e=>e.active),s=t.map(e=>function(e){const t=e.session.userPrompt||e.session.summary||e.session.lastMessage||"",n=e.active?"* ":"",s=e.session.phase&&"unknown"!==e.session.phase?`/${e.session.phase}`:"";return`${n}${e.index+1}. ${e.projectName} / ${e.instance.name} - ${e.session.agent} - ${e.session.status}${s} - ${e.session.id}${t?` - ${t}`:""}`}(e));return{accepted:!0,routed:!1,binding:e,instances:t.map(e=>e.instance),reply:t.length?["Select AI session",`Current ${n?`${n.projectName} / ${n.instance.name} / ${n.session.id}`:await this.targets.renderChatTarget(e)}, total ${t.length}`,"",...s].join("\n"):"No AI sessions found.",replyMarkup:t.length?Jl(t.map(e=>({text:`${e.active?"✓ ":""}${sp(e)}`,callbackData:`task_handoff:cp_session:${e.index}`}))):void 0}}async handleAiSessionCommand(e,t){const n=String(t[0]||"").trim();if(!n)return this.handleAiSessionsCommand(e);const s=await this.targets.findAiSession(n);if(!s)return{accepted:!1,routed:!1,binding:e,reply:`AI session ${n} was not found. Try /sessions.`};const i=s.instance.projectId?this.deps.getProject(s.instance.projectId):void 0;return{accepted:!0,routed:!1,binding:this.deps.upsertChatSession({...e,activeProjectId:i?.id||e.activeProjectId,activeInstanceId:s.instance.id,activeAiSessionId:s.session.id}),instance:s.instance,aiSession:s.session,reply:`Active AI session: ${s.instance.name} / ${s.session.agent} ${s.session.id}`}}async handleAiSessionIndexAction(e,t){const n=(await this.targets.aiSessionChoices(e)).find(e=>e.index===t);if(!n)return{accepted:!1,routed:!1,binding:e,reply:"AI session was not found. Use /session to refresh the list.",replyMarkup:void 0};const s=this.deps.upsertChatSession({...e,activeProjectId:n.projectId||e.activeProjectId,activeInstanceId:n.instance.id,activeAiSessionId:n.session.id}),i=await this.handleAiSessionsCommand(s);return{...i,accepted:!0,binding:s,instance:n.instance,aiSession:n.session,message:`selected ${n.session.id}`,reply:[`Current chat is bound to AI session ${n.session.id}`,"",i.reply].join("\n")}}async handleAiSessionInterruptCommand(e){if(!e.activeInstanceId||!e.activeAiSessionId)return{accepted:!1,routed:!1,binding:e,reply:"No active AI session is selected. Use /sessions and /session <id> first."};const t=await this.deps.requireControlledInstance(e.activeInstanceId,!0),n=await this.deps.interruptAiSession(t.id,e.activeAiSessionId);return{accepted:!0,routed:!0,binding:e,instance:pc(t),aiSession:n,reply:`Interrupt sent to ${t.name} / ${e.activeAiSessionId}.`}}}function dp(e){return e.providerTurnId||e.turnId||""}function cp(e){return Yt(hp(e.status))}function lp(e,t){const n=hp(t.appId)||"App",s=hp(t.title).trim();if(s&&s!==n)return s;const i=function(e,t){for(const n of e.appInventory?.items||[])if(n.id===t)return n.name;return""}(e,n);return i||n}function pp(e){const t=function(e){return"online"!==e.connectionStatus?[]:(e.appInventory?.items||[]).filter(e=>"available"===e.availability)}(e),n=new Map;for(const e of t){const t=mp(e);t&&!n.has(t.id)&&n.set(t.id,t)}return[...n.values()]}function up(e,t,n,s){const i=hp(t.id)&&function(e,t){const n=Qt(e);if(!n)return;return`/apps/access/${n}?token=${encodeURIComponent(t(n))}`}(t,s)||`/instances/${encodeURIComponent(e.id)}/`,r=function(e,t){const n=hp(t);if(n&&new RegExp("^https?://","i").test(n))return new URL(e,n.endsWith("/")?n:n+"/").toString()}(i,n);return{text:r||i,url:r}}function hp(e){return"string"==typeof e&&e.trim()?e.trim():void 0}function mp(e){if("string"==typeof e&&e.trim())return{id:e,label:gp(e)};const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e),n=hp(t.id).trim();return n?{id:n,label:hp(t.name).trim()||gp(n)}:void 0}function gp(e){return{"terminal-tty":"Terminal","gui-terminal":"GUI Terminal",chromium:"Chromium",browser:"Browser","vscode-web":"VS Code"}[e]||e.replace(/[-_]+/g," ").replace(/\b\w/g,e=>e.toUpperCase())}class yp{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleInstancesCommand(e){const t=await this.targets.instancesForBinding(e);return{accepted:!0,routed:!1,binding:e,instances:t,reply:(n=t.length,0===n?"No controlled instances are registered yet.":`Instances: ${n}. Tap an instance to create an app.`),replyMarkup:t.length?Jl(t.map(e=>{return{text:Xl(e.name||e.id,56),callbackData:(t=this.deps.createChatActionToken({type:"instance-app-menu",instanceId:e.id}).token,`task_handoff:cp_i:${t}`)};var t})):void 0};var n}async handleInstanceAppMenuAction(e,t){const n=(await this.targets.instancesForBinding(e)).find(e=>e.id===t);if(!n)return{accepted:!1,routed:!1,binding:e,reply:"Instance not found."};const s=pp(n);return{accepted:!0,routed:!1,binding:e,instance:n,message:`Select an app for ${n.name}.`,reply:s.length?`New app for ${n.name}`:`No launchable apps for ${n.name}.`,replyMarkup:s.length?Jl(s.map(e=>{return{text:Xl(e.label,56),callbackData:(t=this.deps.createChatActionToken({type:"launch-app",instanceId:n.id,appId:e.id}).token,`task_handoff:cp_a:${t}`)};var t})):void 0}}async handleLaunchAppAction(e,t,n){const s=(await this.targets.instancesForBinding(e)).find(e=>e.id===t);if(!s)return{accepted:!1,routed:!1,binding:e,reply:"Instance not found."};const i=pp(s).find(e=>e.id===n);return i?{accepted:!0,routed:!1,binding:e,instance:s,session:await this.deps.launchAppSession(s.id,i.id),message:`${i.label} launched`,reply:`Launched ${i.label} on ${s.name}.`}:{accepted:!1,routed:!1,binding:e,reply:`App ${n} is not launchable for ${s.name}.`}}async handleAppsCommand(e){const t=await this.deps.boardAsync(),n=new Map(t.map(e=>[e.id,e])),s=(await this.deps.listAppSessions()).instances.flatMap(e=>{const t=n.get(e.instanceId);return t?e.appSessions.sessions.filter(cp).filter(e=>Boolean(hp(e.id))).map(e=>({instance:t,session:e,link:up(t,e,this.deps.controlPlanePublicBaseUrl(),n=>this.deps.createAppAccessToken({instanceId:t.id,sessionId:hp(e.id)||"",mode:n}).token)})):[]}),i=s.filter(e=>e.link.url).map(e=>({text:Xl(`${e.instance.name} · ${lp(e.instance,e.session)}`,56),url:e.link.url}));return{accepted:!0,routed:!1,binding:e,instances:t,reply:(r=s.length,o=i.length,0===r?"No app sessions found.":0===o?`App sessions: ${r}. Set the control plane public URL in Settings > Appearance to open them from chat.`:`App sessions: ${r}. Tap a button to open.`),replyMarkup:i.length?Jl(i):void 0};var r,o}}class fp{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async forwardChatMessage(e,t){const n=t.target?.instanceId||e.activeInstanceId||"",s=t.target?.aiSessionId||e.activeAiSessionId,i=await this.deps.requireControlledInstance(n,!0),r=i.projectId?this.deps.requireProject(i.projectId):void 0;if("online"!==i.connectionStatus){const e=new Error(`Instance ${i.name} is not reachable.`);throw Object.assign(e,{statusCode:409,code:"CHAT_TARGET_UNREACHABLE"}),e}if(s){const n=await this.trySendAiSessionMessage(e,i.id,s,t.message.text,t.message.attachments,!t.target);return n.ok?this.sentResult(e,r,i,s,n.aiSession):this.failedSendResult(n.binding,r,i,n.reply)}const o=await this.targets.defaultAiSessionIdForInstance(i.id);if(o){const n=this.deps.upsertChatSession({...e,activeAiSessionId:o}),s=await this.trySendAiSessionMessage(n,i.id,o,t.message.text,t.message.attachments);return s.ok?this.sentResult(n,r,i,o,s.aiSession):this.failedSendResult(s.binding,r,i,s.reply)}return{accepted:!1,routed:!1,binding:e,project:r||void 0,instance:pc(i),reply:`No active AI session is selected for ${i.name}. Use /sessions and /session <id> first.`}}async trySendAiSessionMessage(e,t,n,s,i=[],r=!0){try{return{ok:!0,binding:e,aiSession:await this.deps.sendAiSessionMessage(t,n,s||"请查看附件。",void 0,i)}}catch(t){return function(e){return"AI_SESSION_NOT_FOUND"===(e&&"object"==typeof e?e:{}).code}(t)?{ok:!1,binding:r?this.deps.upsertChatSession({...e,activeAiSessionId:void 0}):e,reply:`The selected AI session ${n} no longer exists. Use /session to choose an active AI session.`}:{ok:!1,binding:e,reply:`Failed to send to AI session ${n}: ${gc(t)}`}}}failedSendResult(e,t,n,s){return{accepted:!1,routed:!1,binding:e,project:t||void 0,instance:pc(n),reply:s}}sentResult(e,t,n,s,i){return{accepted:!0,routed:!0,binding:e,project:t||void 0,instance:pc(n),aiSession:i,instanceId:n.id,aiSessionId:s,turnId:(r=i,r.turnId||r.providerTurnId||r.session.activeTurnId||""),providerTurnId:dp(i),reply:`Sent to ${t?.name||n.sourceSnapshot.name||"Source"} / ${n.name} / ${s}.`};var r}}class Ip{deps;constructor(e){this.deps=e}async handlePendingCommand(e){const t=await this.deps.listPendingRoutes(),n=e.activeInstanceId?t.filter(t=>t.instanceId===e.activeInstanceId):t;return{accepted:!0,routed:!1,binding:e,pending:n,reply:n.length?n.map(rp).join("\n"):"No pending routes.",replyMarkup:n.length?ip(n,(e,t)=>this.deps.pendingDecisionCallbackData(e.id,t)):void 0}}async handlePendingDecisionCommand(e,t,n){const s=mc(t[0]);return s?s.aiSessionId?{accepted:!0,routed:!0,binding:e,pending:s,aiSession:await this.deps.resolveAiSessionApproval(s.instanceId,s.aiSessionId,n),reply:`${n} sent for ${s.instanceId}:${s.aiSessionId}.`}:{accepted:!1,routed:!1,binding:e,pending:s,reply:"Only AI session pending routes are supported here."}:{accepted:!1,routed:!1,binding:e,reply:`Usage: /${"allow"===n?"approve":n} <instance-id:pending-id>`}}async handlePendingReplyCommand(e,t){const n=mc(t[0]),s=t.slice(1).join(" ").trim();return n&&s?n.aiSessionId?{accepted:!0,routed:!0,binding:e,pending:n,aiSession:await this.deps.sendAiSessionMessage(n.instanceId,n.aiSessionId,s),reply:`Reply sent for ${n.instanceId}:${n.aiSessionId}.`}:{accepted:!1,routed:!1,binding:e,pending:n,reply:"Only AI session pending routes are supported here."}:{accepted:!1,routed:!1,binding:e,reply:"Usage: /reply <instance-id:pending-id> <message>"}}}class bp{deps;targets;constructor(e,t){this.deps=e,this.targets=t}async handleUseCommand(e,t){if(0===t.length)return{accepted:!0,routed:!1,binding:e,instances:await this.targets.instancesForBinding(e),reply:await this.targets.renderUseHelp(e)};if(t.length>=2){const n=this.targets.resolveProject(t[0]),s=await this.targets.resolveInstance(t[1],n.id),i=this.deps.upsertChatSession({...e,activeProjectId:n.id,activeInstanceId:s.id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(s.id)});return{accepted:!0,routed:!1,binding:i,reply:await this.targets.renderTargetSelected(i)}}const n=t[0],s=await this.targets.findInstance(n);if(s){const t=s.projectId?this.deps.requireProject(s.projectId):void 0,n=this.deps.upsertChatSession({...e,activeProjectId:t?.id,activeInstanceId:s.id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(s.id)});return{accepted:!0,routed:!1,binding:n,reply:await this.targets.renderTargetSelected(n)}}const i=this.targets.resolveProject(n),r=(await this.deps.boardAsync()).filter(e=>e.projectId===i.id),o=r.filter(e=>"running"===e.status&&"online"===e.connectionStatus);if(1===o.length){const t=this.deps.upsertChatSession({...e,activeProjectId:i.id,activeInstanceId:o[0].id,activeAiSessionId:await this.targets.defaultAiSessionIdForInstance(o[0].id)});return{accepted:!0,routed:!1,binding:t,reply:await this.targets.renderTargetSelected(t)}}return{accepted:!0,routed:!1,binding:this.deps.upsertChatSession({...e,activeProjectId:i.id,activeInstanceId:void 0,activeAiSessionId:void 0}),instances:r,reply:`${i.name} selected. Choose an instance with /use ${i.id} <instance-id-or-name>.\n${this.targets.renderInstanceLines(r)}`}}async handleProjectCommand(e,t){if(0===t.length)return{accepted:!1,routed:!1,binding:e,reply:"Usage: /project <project-id-or-name>"};const n=this.targets.resolveProject(t[0]),s=e.activeInstanceId?await this.deps.requireControlledInstance(e.activeInstanceId).catch(()=>{}):void 0,i=this.deps.upsertChatSession({...e,activeProjectId:n.id,activeInstanceId:s?.projectId===n.id?s.id:void 0,activeAiSessionId:s?.projectId===n.id?e.activeAiSessionId:void 0});return{accepted:!0,routed:!1,binding:i,reply:`Active project: ${n.name}${i.activeInstanceId?"":". Choose an instance with /use."}`}}}class vp{deps;constructor(e){this.deps=e}async instancesForBinding(e){const t=await this.deps.boardAsync();return e.activeProjectId?t.filter(t=>t.projectId===e.activeProjectId):t}async fullInstancesForBinding(e){const t=await this.deps.listNodeInstances();return e.activeProjectId?t.filter(t=>t.projectId===e.activeProjectId):t}async renderUseHelp(e){return`Active target: ${await this.renderChatTarget(e)}\nUse /instances to list targets, then /use <instance-id-or-name>. Use /sessions to choose an AI session when there is more than one.`}async renderChatStatus(e){const t=e.activeInstanceId?(await this.deps.boardAsync()).find(t=>t.id===e.activeInstanceId):void 0;return t?`Active target: ${await this.renderChatTarget(e)}\nStatus: ${t.status}, connection: ${t.connectionStatus}`:`Active target: ${await this.renderChatTarget(e)}`}async renderChatHelp(e){return["TaskHandoff chat commands:","/help - show this help","/status or /target - show the active project, instance, and AI session","/instances - list controlled instances","/apps - list app sessions","/use <instance-id-or-name> - choose an active instance","/use <project-id-or-name> <instance-id-or-name> - choose a project and instance","/project <project-id-or-name> - narrow instance selection to a project","/sessions - list all AI sessions","/session <ai-session-id> - choose an active AI session","/pending - list waiting approvals","/approve <instance-id:pending-id>, /deny <...>, /skip <...> - answer approvals","/reply <instance-id:pending-id> <message> - reply to a waiting session","/cancel - interrupt the active AI session","","Send normal text after selecting a target; if there is only one AI session, it is selected automatically.",`Current target: ${await this.renderChatTarget(e)}`].join("\n")}renderInstanceLines(e){return e.map(e=>`${e.name} (${e.id}) - ${e.status}/${e.connectionStatus}`).join("\n")}async renderChatTarget(e){const t=e.activeProjectId?this.deps.getProject(e.activeProjectId):void 0,n=e.activeInstanceId?await this.deps.requireControlledInstance(e.activeInstanceId).catch(()=>{}):void 0,s=e.activeAiSessionId||"none";return`${t?.name||e.activeProjectId||"none"} / ${n?.name||e.activeInstanceId||"none"} / ${s}`}async renderTargetSelected(e){const t=await this.renderChatTarget(e);return e.activeAiSessionId?`Active target: ${t}`:`Active target: ${t}\nNo AI session selected yet. Use /sessions and /session <id>, or send a message once exactly one session is available.`}async defaultAiSessionIdForInstance(e){const t=await this.aiSessionSnapshotForInstance(e),n=(await this.deps.boardAsync()).find(t=>t.id===e),s=(await this.deps.listAppSessions()).instances.find(t=>t.instanceId===e),i=n?{...n,apps:{...n.apps,sessions:s?.appSessions.sessions||[]}}:void 0,r=t&&n?ep({...i,aiSessions:t}):t?.sessions||[];return 1===r.length?r[0].id:void 0}async aiSessionChoices(e){return(await this.boardInstancesForBinding({},{refresh:!0})).flatMap(t=>ep(t).map(n=>({index:0,projectId:t.projectId,projectName:t.project?.name||("string"==typeof t.sourceSnapshot.name?t.sourceSnapshot.name:"Source"),instance:t,session:n,active:e.activeInstanceId===t.id&&e.activeAiSessionId===n.id}))).sort((e,t)=>{const n=tp(t.session)-tp(e.session);return n||(String(e.instance.name||"").localeCompare(String(t.instance.name||""))||e.instance.id.localeCompare(t.instance.id)||np(e.session).localeCompare(np(t.session)))}).map((e,t)=>({...e,index:t}))}async boardInstancesForBinding(e,t={}){const n=await this.deps.boardAsync(),s=await this.deps.listAiSessions(t),i=await this.deps.listAppSessions(t),r=new Map(s.instances.map(e=>[e.instanceId,e.aiSessions])),o=new Map(i.instances.map(e=>[e.instanceId,e.appSessions])),a=n.map(e=>{return{...e,apps:{...e.apps,sessions:o.get(e.id)?.sessions||[]},aiSessions:r.get(e.id)||(t=e.aiSessions.updatedAt,{runningCount:0,waitingCount:0,staleCount:0,sessions:[],updatedAt:t})};var t});return e.activeProjectId?a.filter(t=>t.projectId===e.activeProjectId):a}async findAiSession(e){const t=await this.boardInstancesForBinding({},{refresh:!0});for(const n of t){const t=(n.aiSessions?.sessions||[]).find(t=>t.id===e||t.providerSessionId===e);if(t)return{instance:n,session:t}}}async aiSessionSnapshotForInstance(e){const t=await this.deps.listAiSessions();return t.instances.find(t=>t.instanceId===e)?.aiSessions}resolveProject(e){const t=this.deps.getProject(e)||this.deps.listProjects().find(t=>t.name===e);return t||yc("PROJECT_NOT_FOUND",`Project ${e} was not found.`),t}async resolveInstance(e,t){const n=await this.findInstance(e,t);return n||yc("CONTROLLED_INSTANCE_NOT_FOUND",`Controlled instance ${e} was not found.`),n}async findInstance(e,t){return(await this.deps.listNodeInstances()).find(n=>!(n.id!==e&&n.name!==e||t&&n.projectId!==t))}}class Sp{deps;targets;sender;appCommands;pendingCommands;aiSessionCommands;targetCommands;constructor(e){this.deps=e,this.targets=new vp(e),this.sender=new fp(e,this.targets),this.appCommands=new yp(e,this.targets),this.pendingCommands=new Ip(e),this.aiSessionCommands=new ap(e,this.targets),this.targetCommands=new bp(e,this.targets)}async handleChatGatewayMessage(e){const t=co.parse(e),n=this.deps.upsertChatSession({channel:t.source.channel,bridgeId:t.source.bridgeId,chatSessionId:t.source.chatSessionId,userId:t.source.userId}),s=t.message.text.trim();return s.startsWith("/")?this.handleChatCommand(n,s):s||t.message.attachments.length?n.activeInstanceId?this.sender.forwardChatMessage(n,t):{accepted:!1,routed:!1,binding:n,reply:await this.targets.renderUseHelp(n)}:{accepted:!1,routed:!1,binding:n,reply:""}}async handleChatGatewayAction(e){const t=this.deps.upsertChatSession({channel:e.source.channel,bridgeId:e.source.bridgeId,chatSessionId:e.source.chatSessionId,userId:e.source.userId});return"ai-session"===e.action.type?this.aiSessionCommands.handleAiSessionIndexAction(t,e.action.index):"instance-app-menu"===e.action.type?this.appCommands.handleInstanceAppMenuAction(t,e.action.instanceId):"launch-app"===e.action.type?this.appCommands.handleLaunchAppAction(t,e.action.instanceId,e.action.appId):"pending-decision"===e.action.type?this.pendingCommands.handlePendingDecisionCommand(t,[e.action.routeId],e.action.decision):{accepted:!1,routed:!1,binding:t,reply:"Unknown action."}}async handleChatCommand(e,t){const[n="",...s]=t.split(/\s+/),i=n.replace(/@[\w_]+$/,"");switch(i.toLowerCase()){case"/help":case"/start":return{accepted:!0,routed:!1,binding:e,reply:await this.targets.renderChatHelp(e)};case"/sessions":return this.aiSessionCommands.handleAiSessionsCommand(e);case"/session":return this.aiSessionCommands.handleAiSessionCommand(e,s);case"/cancel":case"/interrupt":return this.aiSessionCommands.handleAiSessionInterruptCommand(e);case"/pending":return this.pendingCommands.handlePendingCommand(e);case"/approve":return this.pendingCommands.handlePendingDecisionCommand(e,s,"allow");case"/deny":return this.pendingCommands.handlePendingDecisionCommand(e,s,"deny");case"/skip":return this.pendingCommands.handlePendingDecisionCommand(e,s,"skip");case"/reply":return this.pendingCommands.handlePendingReplyCommand(e,s);case"/instances":return this.appCommands.handleInstancesCommand(e);case"/apps":return this.appCommands.handleAppsCommand(e);case"/use":return this.targetCommands.handleUseCommand(e,s);case"/project":return this.targetCommands.handleProjectCommand(e,s);case"/status":case"/target":return{accepted:!0,routed:!1,binding:e,instance:e.activeInstanceId?(await this.deps.boardAsync()).find(t=>t.id===e.activeInstanceId):void 0,reply:await this.targets.renderChatStatus(e)};default:return{accepted:!1,routed:!1,binding:e,reply:`Unknown command: ${i||n}. Try /help.`}}}}const wp=d.z.object({id:d.z.string().trim().min(1),preferences:ma,createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime()}).strict();function Ap(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e,n=t.preferences&&"object"==typeof t.preferences&&!Array.isArray(t.preferences)?t.preferences:{};return{id:t.id,preferences:{import:"string"==typeof n.import&&n.import.trim()?n.import:".",export:"string"==typeof n.export&&n.export.trim()?n.export:"."},createdAt:t.createdAt,updatedAt:t.updatedAt}}function zp(){return ma.parse({})}function kp(e){return/^[a-z]:[\\/]/i.test(e)||/^[\\/]{2}[^\\/]+[\\/]+[^\\/]+/.test(e)}function Tp(e){return kp(e)?t.win32:t.posix}class Cp{retiredRoot;legacyControlledInstancesDir;legacyNodeRuntimesDir;legacyNodeJoinInvitesDir;paths;options;constructor(e,n={}){this.paths=e,this.options=n,this.retiredRoot=t.join(e.dataDir,"retired-persistence"),this.legacyControlledInstancesDir=t.join(e.dataDir,"controlled-instances"),this.legacyNodeRuntimesDir=t.join(e.dataDir,"node-runtimes"),this.legacyNodeJoinInvitesDir=t.join(e.dataDir,"node-join-invites")}run(){return this.removePersistedInvites(),this.retireLegacyProjection("controlled-instances",this.legacyControlledInstancesDir,!0),this.retireLegacyProjection("node-runtimes",this.legacyNodeRuntimesDir,!1),function(e){if(!n.existsSync(e.trashRoot))return[];const t=e.nowMs??Date.now(),s=e.retentionMs??uo,i=[];for(const r of n.readdirSync(e.trashRoot,{withFileTypes:!0})){const o=ho(e.trashRoot,r.name);try{const e=Number(r.name.split("-",1)[0]);if(!Number.isFinite(e)||e+s>t)continue;const a=n.lstatSync(o);a.isSymbolicLink()?n.unlinkSync(o):a.isDirectory()?n.rmSync(o,{recursive:!0,force:!0}):n.unlinkSync(o),i.push(o)}catch(t){e.logger?.("retired persistence entry cleanup failed",{path:o,error:t instanceof Error?t.message:String(t)})}}return i}({trashRoot:this.retiredRoot,retentionMs:this.options.retentionMs??uo,nowMs:this.now(),logger:this.options.logger})}removePersistedInvites(){n.existsSync(this.legacyNodeJoinInvitesDir)&&n.rmSync(this.legacyNodeJoinInvitesDir,{recursive:!0,force:!0})}retireLegacyProjection(e,s,i){if(!n.existsSync(s))return;const r=n.lstatSync(s);if(!r.isDirectory()||r.isSymbolicLink())return n.rmSync(s,{force:!0}),void this.options.logger?.("invalid legacy persistence path was removed",{store:e});n.readdirSync(s).length?(i&&this.redactLegacyInstanceCredentials(s),function(e){const t=ho(e.sourceRoot,e.entryName);if(!n.existsSync(t))return;const s=n.lstatSync(t);if(!s.isDirectory()||s.isSymbolicLink())throw new Error(`Retention source must be a real directory: ${t}`);mo(e.trashRoot);const i=e.nowMs??Date.now();let r=0,o=`${i}-${e.entryName}`;for(;n.existsSync(ho(e.trashRoot,o));)r+=1,o=`${i}-${r}-${e.entryName}`;const a=ho(e.trashRoot,o);n.renameSync(t,a)}({sourceRoot:this.paths.dataDir,entryName:t.basename(s),trashRoot:this.retiredRoot,nowMs:this.now()}),this.options.logger?.("legacy control-plane persistence was retired",{store:e})):n.rmdirSync(s)}redactLegacyInstanceCredentials(e){for(const s of n.readdirSync(e,{withFileTypes:!0})){if(!s.isFile()||s.isSymbolicLink())continue;const i=t.join(e,s.name);try{const e=JSON.parse(n.readFileSync(i,"utf8"));delete e.registrationToken,l.sync(i,`${JSON.stringify(e,null,2)}\n`,{encoding:"utf8",mode:384}),n.chmodSync(i,384)}catch(e){n.rmSync(i,{force:!0}),this.options.logger?.("unreadable legacy instance record was removed",{filePath:i,error:e instanceof Error?e.message:String(e)})}}mo(e)}now(){return this.options.now?.()??Date.now()}}const Ep="task-handoff.control-plane.local",xp="task-handoff.control-plane.builtin";function Np(e){return"true"===e.labels[Ep]}function Rp(e){return"true"===e.labels[xp]}class Op{projects;models;modelService;images;nodes;pendingPairingRevokes;chatSessions;chatBridges;triggers;nodeJoinService;configSyncPreferences;settings;paths;fetchImpl;dockerCommandRunner;logger;diagnosticLogsState;nodeConnectionRuntime;appAccessService;persistenceMaintenance;chatActionTokenService=new Fl;nodeAgentTransportResolver;proxyPrivateStore;proxyLifecycle;nodeConnectionManager;nodeAgentGateway;controlledInstanceGateway;aiSessionActionService;controlledInstanceCreator;instanceBoardReader=new Sl;controlPlaneTriggerService;catalogService;marketCatalogService;chatBridgeService;chatSessionService;chatSessionRuntime;aiSessionSnapshotProvider;appSessionSnapshotProvider;constructor(e,n={}){this.paths=e,this.fetchImpl=n.fetchImpl||fetch,this.dockerCommandRunner=n.dockerCommandRunner,this.nodeConnectionRuntime=n.nodeConnectionRuntime,this.persistenceMaintenance=new Cp(e,{logger:(e,t)=>this.logWarn(t,e)});const s=e=>({schema:e,logger:(e,t)=>this.logWarn(t,e)});this.proxyPrivateStore=new Vd(function(e){const n=t.resolve(e,"control-plane-proxy");return{pendingClaimsDir:t.join(n,"pending-claims"),nodeCredentialsDir:t.join(n,"node-credentials"),identityPath:t.join(n,"identity.json")}}(e.dataDir),(e,t)=>this.logWarn(t,e)),this.nodeAgentTransportResolver=new Dd({direct:jd(this.fetchImpl),tunnel:n.nodeAgentTransport,proxy:new Fd({credentialForNode:e=>this.proxyPrivateStore.nodeCredential(e.id),fetchImpl:this.fetchImpl})});const i=(r=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(r||"").trim().toLowerCase()));var r;this.diagnosticLogsState=i,this.settings=new Mo(e.settingsPath,()=>Tc.parse({diagnosticLogs:i}),{...s(Tc),sanitize:e=>function(e,t={}){if(!e||"object"!=typeof e||Array.isArray(e))return{};const n={...e};return"string"==typeof n.mentionTrigger&&wc(n.mentionTrigger)||(n.mentionTrigger="@"),"string"==typeof n.commandTrigger&&zc(n.commandTrigger)&&n.commandTrigger!==n.mentionTrigger||(n.commandTrigger="/"),"boolean"!=typeof n.diagnosticLogs&&(n.diagnosticLogs=t.diagnosticLogs??!1),n}(e,{diagnosticLogs:i})}),this.logger=n.logger?{info:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.info?.(e,t)},warn:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.warn?.(e,t)},error:(e,t)=>{this.diagnosticLogsEnabled()&&n.logger?.error?.(e,t)}}:void 0;const o=new hd({request:(e,t,n)=>this.nodeAgentFetch(e,t,n),logger:this.logger});this.nodeAgentGateway=new md(o,{onFleetStateChanged:n.onFleetStateChanged}),this.controlledInstanceGateway=new bl({requireNode:e=>this.requireNode(e),nodeAgentTransport:e=>this.nodeAgentTransportResolver.resolve(e)}),this.aiSessionActionService=new rd({requireInstance:e=>this.requireControlledInstance(e,!0),request:(e,t,n,s)=>this.instanceRequest(e,t,n,s),requireRuntime:(e,t)=>this.requireNodeRuntimeOnNode(e,t),refreshSnapshots:()=>Promise.all([this.listAppSessions({refresh:!0}),this.listAiSessions({refresh:!0})]),warn:(e,t)=>this.logWarn(e,t)}),this.projects=new Do(e.projectsDir,{...s(Ji),sanitize:ci}),this.models=new Do(e.modelsDir,s(Yi)),this.modelService=new yl({models:this.models,gateway:this.nodeAgentGateway,listNodes:()=>this.listNodes(),requireNode:e=>this.requireNode(e),fetchImpl:this.fetchImpl}),this.images=new Do(e.imagesDir,{...s(fr),sanitize:e=>Er(e,e=>this.logWarn(e,"legacy image profile field was migrated"))}),this.nodes=new Do(e.nodesDir,{...s(Rr),sanitize:e=>function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=new Set(["id","name","connectionMode","connectionPath","connectionEnabled","auth","endpoint","controlEndpoint","containerEndpoint","publicWebBase","status","health","capabilities","proxyState","appInventory","labels","lastSeenAt","createdAt","updatedAt"]);for(const e of Object.keys(n))s.has(e)||t?.({field:e});const i=n.auth&&"object"==typeof n.auth&&!Array.isArray(n.auth)?io(n.auth,["mode","keyId","secret","pairedAt","pairing"]):n.auth;i&&"object"==typeof i&&"pairing"in i&&(i.pairing=io(i.pairing,["status","joinToken","expiresAt"]));const r=n.connectionPath&&"object"==typeof n.connectionPath&&!Array.isArray(n.connectionPath)?"control-plane-proxy"===n.connectionPath.kind?io(n.connectionPath,["kind","proxyId","proxyBindingId","targetNodeId"]):io(n.connectionPath,["kind"]):{kind:"direct"},o=n.proxyState&&"object"==typeof n.proxyState&&!Array.isArray(n.proxyState)?io(n.proxyState,["reachability","bindingStatus","bindingRevision","streamId","revision","observedAt","target","lastError","updatedAt"]):n.proxyState;if(o&&"object"==typeof o){const e=o;e.target=io(e.target,["id","name","status","health","lastSeenAt","capabilities"]),e.lastError=io(e.lastError,["code","message","retryable","details"])}return{...Object.fromEntries(Object.entries(n).filter(([e])=>s.has(e))),auth:i,connectionPath:r,proxyState:o}}(e,e=>this.logWarn(e,"unknown stored node field was ignored"))}),this.pendingPairingRevokes=new Do(e.pendingPairingRevokesDir,s(Jc)),this.proxyLifecycle=new bc({nodes:this.nodes,privateStore:this.proxyPrivateStore,fetchImpl:this.fetchImpl,requireNode:e=>this.requireNode(e),deleteNode:e=>this.deleteNode(e)}),this.nodeConnectionManager=new Yc({nodes:this.nodes,pendingPairingRevokes:this.pendingPairingRevokes,fetchImpl:this.fetchImpl,localNodeLabel:Ep,builtinNodeLabel:xp,info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.chatSessions=new Do(e.chatSessionsDir,s(ao)),this.chatBridges=new Do(e.chatBridgesDir,s(oo)),this.triggers=new Do(e.triggersDir,s(Oc)),this.nodeJoinService=new ol({nodes:this.nodes}),this.configSyncPreferences=new Do(t.join(e.dataDir,"config-sync-preferences"),{...s(wp),sanitize:Ap}),this.marketCatalogService=new Pl,this.catalogService=new Nl({projects:this.projects,images:this.images,market:this.marketCatalogService,settings:this.settings,defaultNodeId:()=>this.defaultNodeId()}),this.controlledInstanceCreator=new wl({gateway:this.nodeAgentGateway,defaultNodeId:()=>this.defaultNodeId(),requireProject:e=>this.requireProject(e),requireNode:e=>this.requireNode(e),requireRuntime:(e,t)=>this.requireNodeRuntimeOnNode(e,t),requireLocalFolder:(e,t)=>this.requireNodeLocalFolder(e,t),resolveImageSelection:e=>this.catalogService.resolveImageSelection(e),prepareModels:(e,t)=>this.modelService.prepareAssignment(e,t)}),this.controlPlaneTriggerService=new kl({triggers:this.triggers,listInstances:()=>this.listCachedNodeInstances(),listMutationInstances:()=>this.listTriggerMutationInstances(),requireInstance:async e=>this.requireControlledInstance(e,!0),instanceRequest:(e,t,n)=>this.instanceRequest(e,t,n)}),this.appAccessService=new Dl({requireInstance:async e=>this.requireControlledInstance(e,!0),listAppSessions:()=>this.listAppSessions()}),this.chatBridgeService=new Gl({chatBridges:this.chatBridges,chatSessions:this.chatSessions}),this.chatSessionService=new Vl({chatSessions:this.chatSessions}),this.chatSessionRuntime=new Sp({upsertChatSession:e=>this.upsertChatSession(e),boardAsync:()=>this.boardAsync(),listAiSessions:e=>this.listAiSessions(e),listAppSessions:e=>this.listAppSessions(e),listNodeInstances:()=>this.listBootstrapNodeInstances(),listPendingRoutes:()=>this.listPendingRoutes(),pendingDecisionCallbackData:(e,t)=>this.pendingDecisionCallbackData(e,t),createChatActionToken:e=>this.createChatActionToken(e),createAppAccessToken:e=>this.createAppAccessToken(e),controlPlanePublicBaseUrl:()=>this.getSettings().publicBaseUrl||process.env.TASK_HANDOFF_CONTROL_PLANE_URL||process.env.TASK_HANDOFF_PUBLIC_BASE||process.env.TASK_HANDOFF_CONTROL_PLANE_PUBLIC_URL,requireControlledInstance:(e,t)=>this.requireControlledInstance(e,t),requireProject:e=>this.requireProject(e),getProject:e=>this.catalogService.getProject(e),listProjects:()=>this.catalogService.listProjects(),resolveAiSessionApproval:(e,t,n)=>this.resolveAiSessionApproval(e,t,n),sendAiSessionMessage:(e,t,n,s,i)=>this.sendAiSessionMessage(e,t,n,s,i),interruptAiSession:(e,t)=>this.interruptAiSession(e,t),launchAppSession:(e,t,n)=>this.launchAppSession(e,t,n)})}logInfo(e,t){this.logger?.info?.(e,t)}logWarn(e,t){this.logger?.warn?.(e,t)}logError(e,t){this.logger?.error?.(e,t)}setNodeAgentTransport(e){this.nodeAgentTransportResolver.setTunnel(e)}resolveNodeAgentTransport(e){return this.nodeAgentTransportResolver.resolve(e)}setAiSessionSnapshotProvider(e){this.aiSessionSnapshotProvider=e}async listAiSessions(e={}){return this.aiSessionSnapshotProvider?this.aiSessionSnapshotProvider(e):this.bootstrapAiSessionsFromInstances()}setAppSessionSnapshotProvider(e){this.appSessionSnapshotProvider=e}async listAppSessions(e={}){return this.appSessionSnapshotProvider?this.appSessionSnapshotProvider(e):this.bootstrapAppSessionsFromInstances()}init(){this.runPersistenceMaintenance(),this.projects.init(),this.models.init(),this.images.init(),this.nodes.init(),this.pendingPairingRevokes.init(),this.chatSessions.init(),this.chatBridges.init(),this.triggers.init(),this.proxyPrivateStore.init(),this.proxyPrivateStore.gcNodeCredentials(e=>{const t=this.nodes.get(e.nodeId);return"control-plane-proxy"===t?.connectionMode&&"control-plane-proxy"===t.connectionPath.kind&&t.connectionPath.proxyBindingId===e.proxyBindingId&&t.connectionPath.targetNodeId===e.targetNodeId}),this.settings.init();const e=this.settings.put(this.settings.get());this.diagnosticLogsState=e.diagnosticLogs,this.migrateLegacyImageCatalog(),this.seedDefaults(),this.refreshCachedNodeInstances();const t=this.listNodes().map(e=>this.projectNodeConnection(e));this.nodeAgentGateway.refreshFleetRuntimes(t).catch(e=>{this.logWarn({error:gc(e)},"control plane runtime directory warmup failed")}),this.nodeAgentGateway.refreshFleetModels(t).catch(e=>{this.logWarn({error:gc(e)},"control plane model directory warmup failed")})}runPersistenceMaintenance(){try{return this.persistenceMaintenance.run()}catch(e){return this.logWarn({error:e instanceof Error?e.message:String(e)},"control-plane persistence maintenance failed"),[]}}migrateLegacyImageCatalog(){const e=Object.keys(ai),s=[];for(const t of e){const e=this.images.filePath(t);if(n.existsSync(e))try{s.push({id:t,filePath:e,record:JSON.parse(n.readFileSync(e,"utf8"))})}catch(e){return this.writeMarketMigrationState("failed",{code:"LEGACY_IMAGE_BACKUP_READ_FAILED",legacyId:t,error:gc(e)}),void this.logWarn({legacyId:t,error:gc(e)},"legacy embedded image migration was not applied")}}if(!s.length)return;const i=n.readdirSync(this.paths.projectsDir).filter(e=>e.endsWith(".json")).sort().map(e=>t.join(this.paths.projectsDir,e)),r=[];for(const e of i)try{const t=JSON.parse(n.readFileSync(e,"utf8")),s=Ji.parse(ci(t));r.push({filePath:e,raw:t,migrated:s})}catch(t){return this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_VALIDATION_FAILED",filePath:e,error:gc(t)}),void this.logWarn({filePath:e,error:gc(t)},"legacy embedded image migration was not applied")}const o=r.find(({migrated:t})=>{const n=t.defaultImageSelection?.imageId;return!!n&&e.includes(n)});if(o)this.writeMarketMigrationState("failed",{code:"PROJECT_REFERENCE_MIGRATION_INCOMPLETE",filePath:o.filePath});else{n.mkdirSync(this.paths.marketDir,{recursive:!0}),l.sync(this.paths.marketMigrationBackupPath,`${JSON.stringify({version:ks,createdAt:Eo(),images:s.map(({id:e,record:t})=>({id:e,record:t})),projects:r.map(({filePath:e,raw:n})=>({file:t.basename(e),record:n}))},null,2)}\n`,{encoding:"utf8"});for(const{migrated:e}of r)this.projects.put(e);for(const{id:e}of s)this.images.delete(e),this.logWarn({legacyId:e,marketId:ai[e]},"embedded image profile migrated to Market");this.writeMarketMigrationState("complete",{code:"LEGACY_IMAGE_MIGRATION_COMPLETE",migratedImageIds:s.map(({id:e})=>e),backupPath:this.paths.marketMigrationBackupPath})}}writeMarketMigrationState(e,t){n.mkdirSync(this.paths.marketDir,{recursive:!0}),l.sync(this.paths.marketStatePath,`${JSON.stringify({status:e,updatedAt:Eo(),...t},null,2)}\n`,{encoding:"utf8"})}getSettings(){return this.catalogService.getSettings()}diagnosticLogsEnabled(){return this.diagnosticLogsState}updateSettings(e){const t=this.catalogService.updateSettings(e);return this.diagnosticLogsState=t.diagnosticLogs,t}seedDefaults(){return this.catalogService.seedDefaults()}listProjects(){return this.catalogService.listProjects()}defaultNodeId(){return this.nodes.list().find(Np)?.id||this.nodes.list()[0]?.id}async syncLocalNodeConnection(){const e=await this.nodeConnectionManager.syncLocal();return this.nodeConnectionRuntime?.observedReachable(e),this.projectNodeConnection(e)}recoverPendingPairingRevokes(){return this.nodeConnectionManager.recoverPendingPairingRevokes()}listModels(){return this.modelService.list()}listFederatedModels(e,t=!1){return this.modelService.listFederated(e,t)}createModel(e){return this.modelService.create(e)}updateModel(e,t){return this.modelService.update(e,t)}deleteModel(e){return this.modelService.delete(e)}reorderModels(e){return this.modelService.reorder(e)}createNodeModel(e,t){return this.modelService.createOnNode(e,t)}updateNodeModel(e,t,n){return this.modelService.updateOnNode(e,t,n)}deleteNodeModel(e,t){return this.modelService.deleteOnNode(e,t)}discoverModels(e){return this.modelService.discover(e)}testModel(e){return this.modelService.test(e)}discoverNodeModels(e,t){return this.modelService.discoverOnNode(e,t)}testNodeModel(e,t){return this.modelService.testOnNode(e,t)}createProject(e){return this.catalogService.createProject(e)}updateProject(e,t){return this.catalogService.updateProject(e,t)}deleteProject(e){return this.catalogService.deleteProject(e)}listImages(){return this.catalogService.listImages()}getMarketCatalog(){return this.catalogService.getMarketCatalog()}async refreshMarketCatalog(){return await this.marketCatalogService.refresh(new _l),this.getMarketCatalog()}listImageOptions(){return this.catalogService.listImageOptions()}createImage(e){return this.catalogService.createImage(e)}async listNodeDockerImages(e){const t=this.requireNode(e);return this.nodeAgentGateway.listDockerImages(t)}async listNodeImageAvailability(e){const t=this.requireNode(e),n=t.capabilities.agent&&"object"==typeof t.capabilities.agent?t.capabilities.agent:{},s={os:"string"==typeof n.platform?n.platform:void 0,architecture:"string"==typeof n.arch?"x64"===n.arch?"amd64":n.arch:void 0},i=this.catalogService.listImageOptions(s);try{const e=await this.nodeAgentGateway.listDockerImages(t);return i.map(t=>{const n=e.find(e=>e.reference===t.reference||!!t.digest&&e.repoDigests.some(e=>e.endsWith(`@${t.digest}`))||e.repoDigests.includes(t.reference));return Wr.parse({image:t,status:n?"available":"pull-required",localImage:n,localSizeBytes:n?.sizeBytes,downloadSizeBytes:n?void 0:t.downloadSizeBytes,unpackedSizeBytes:n?void 0:t.unpackedSizeBytes})})}catch(e){const t=e instanceof Error?e.message:String(e);return i.map(e=>Wr.parse({image:e,status:"unknown",error:t}))}}async listNodeLocalFolders(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.listLocalFolders(n,{signal:t})}async listNodeFolderTree(e,t={}){const n=this.requireNode(e);return this.nodeAgentGateway.listFolderTree(n,t)}async listNodeFolderPlaces(e){const t=this.requireNode(e);if(n=t.capabilities?.agent&&"object"==typeof t.capabilities.agent?t.capabilities.agent.capabilities:void 0,!0!==Pr.safeParse(n).data?.folderPlaces)return(await this.nodeAgentGateway.listFolderTree(t,{depth:0})).map(e=>Vr.parse({kind:"root",name:e.name,path:e.path}));var n;try{return await this.nodeAgentGateway.listFolderPlaces(t)}catch(e){if(404!==(e&&"object"==typeof e?e.statusCode:void 0))throw e;return(await this.nodeAgentGateway.listFolderTree(t,{depth:0})).map(e=>Vr.parse({kind:"root",name:e.name,path:e.path}))}}async createNodeLocalFolder(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.createLocalFolder(n,t)}async updateNodeLocalFolder(e,t,n){const s=this.requireNode(e);if(i=s.capabilities?.agent&&"object"==typeof s.capabilities.agent?s.capabilities.agent.capabilities:void 0,!0!==Pr.safeParse(i).data?.localFolderNameUpdate){const e=new Error(`Node ${s.id} does not support local folder name updates.`);throw Object.assign(e,{statusCode:409,code:"NODE_LOCAL_FOLDER_NAME_UPDATE_UNSUPPORTED"})}var i;return this.nodeAgentGateway.updateLocalFolder(s,t,n)}async deleteNodeLocalFolder(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteLocalFolder(n,t)}async checkNode(e){const t=this.requireNode(e);try{const e=await this.nodeAgentGateway.health(t),n=e&&"object"==typeof e?e:{},s="string"==typeof n.nodeId&&n.nodeId.trim()?n.nodeId.trim():t.id,i=Rr.parse({...t,id:s,status:"online",health:"ok",capabilities:"object"==typeof e&&e?{...t.capabilities,agent:dc(e)}:t.capabilities,lastSeenAt:Eo(),updatedAt:Eo()});return s!==t.id&&this.nodes.delete(t.id),this.nodes.put(i),this.nodeConnectionRuntime?.observedReachable(i),{id:i.id,status:"online",checkedAt:Eo(),agent:e}}catch(e){const n=Rr.parse({...t,status:"offline",health:"failed",updatedAt:Eo()});return this.nodes.put(n),this.nodeConnectionRuntime?.observedFailure(n,gc(e)),{id:t.id,status:"offline",checkedAt:Eo(),error:e instanceof Error?e.message:String(e)}}}async checkNodeUpdate(e,t){return this.nodeAgentGateway.checkUpdate(this.requireNode(e),t)}async applyNodeUpdate(e,t){return this.nodeAgentGateway.applyUpdate(this.requireNode(e),t)}async listNodeUpdateJobs(e){return this.nodeAgentGateway.listUpdateJobs(this.requireNode(e))}async getLocalNodeExternalListener(e){return this.nodeAgentGateway.getExternalListener(this.requireLocalListenerNode(e))}async updateLocalNodeExternalListener(e,t){return this.nodeAgentGateway.updateExternalListener(this.requireLocalListenerNode(e),t)}async createNodePairingInvite(e,t={}){const n=this.requireNode(e);return this.nodeAgentGateway.createPairingInvite(n,t)}requireLocalListenerNode(e){const t=this.requireNode(e);if(!Rp(t)||!Np(t)){const e=new Error("Node agent TCP listener settings are available only for the built-in local node.");throw Object.assign(e,{statusCode:403,code:"LOCAL_NODE_LISTENER_ONLY"}),e}return t}createNodeJoinInvite(e={}){return this.nodeJoinService.createInvite(e)}completeNodeJoin(e){return this.nodeJoinService.complete(e)}async connectNodeToControlPlane(e,t){const n=this.requireNode(e),s=Vc.parse(t);return this.nodeAgentGateway.createControlPlaneConnection(n,s)}async listNodeControlPlanePairings(e){const t=this.requireNode(e);return this.nodeAgentGateway.listControlPlanePairings(t)}async deleteNodeControlPlanePairing(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteControlPlanePairing(n,t)}async listNodeControlPlaneConnections(e){const t=this.requireNode(e);return this.nodeAgentGateway.listControlPlaneConnections(t)}async deleteNodeControlPlaneConnection(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteControlPlaneConnection(n,t)}updateImage(e,t){return this.catalogService.updateImage(e,t)}async deleteImage(e){this.catalogService.requireImage(e);const t=this.listProjects().find(t=>t.defaultImageSelection?.imageId===e);if(t)throw Object.assign(new Error(`Image ${e} is the default for project ${t.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});const n=this.readCachedNodeInstances(),s=n.nodeStates.filter(e=>"uninitialized"===e.phase||"loading"===e.phase||"stale"===e.phase);if(s.length){this.refreshCachedNodeInstances();const e=new Error("The instance directory is still loading; retry after every node has reported its instance snapshot.");throw Object.assign(e,{statusCode:503,code:"INSTANCE_DIRECTORY_LOADING",nodeIds:s.map(e=>e.nodeId)})}const i=n.items.find(t=>t.imageSelection?.imageId===e);if(i)throw Object.assign(new Error(`Image ${e} is used by instance ${i.name}.`),{statusCode:409,code:"IMAGE_IN_USE"});return this.catalogService.deleteImage(e)}listNodes(){return this.nodes.list()}listPublicNodes(){return this.listNodes().map(e=>cc(this.projectNodeConnection(e)))}projectNodeConnection(e){return this.nodeConnectionRuntime?.project(e)||e}createNode(e){return this.nodeConnectionManager.create(e)}listPendingProxyClaims(){return this.proxyLifecycle.listPendingClaims()}claimProxyNode(e){return this.proxyLifecycle.claimNode(e)}resumeProxyClaim(e){return this.proxyLifecycle.resumeClaim(e)}cancelProxyClaim(e,t=!1){return this.proxyLifecycle.cancelClaim(e,t)}applyProxyTargetSnapshot(e,t){return this.proxyLifecycle.applyTargetSnapshot(e,t)}applyProxyTargetEvent(e,t){return this.proxyLifecycle.applyTargetEvent(e,t)}markProxyUnavailable(e,t){return this.proxyLifecycle.markUnavailable(e,t)}markProxyBindingRevoked(e,t){return this.proxyLifecycle.markBindingRevoked(e,t)}updateNode(e,t){const n=Gc.parse(t),s=this.requireNode(e);this.proxyLifecycle.assertIdentityPatch(s,n);const i=Rr.parse({...s,...n,id:e,createdAt:s.createdAt,updatedAt:Eo()});return this.nodes.put(i)}deleteNode(e){if(Rp(this.requireNode(e))){const e=new Error("The built-in local node connection cannot be deleted.");throw Object.assign(e,{statusCode:400,code:"LOCAL_NODE_CANNOT_BE_DELETED"}),e}return this.nodeAgentGateway.forgetNode(e),this.nodes.delete(e)}dispose(){this.nodeAgentGateway.dispose()}async deleteNodeWithProxyLifecycle(e,t=!1){return this.proxyLifecycle.deleteNode(this.requireNode(e),t)}async listNodeRuntimes(e,t){const n=e?[this.requireNode(e)]:this.listNodes();return e?this.nodeAgentGateway.listRuntimes(n[0],{signal:t}):(await this.nodeAgentGateway.listFleetRuntimes(n,{signal:t})).items}async listNodeRuntimesWithDiagnostics(e,t=!1){const n=this.listNodes().map(e=>this.projectNodeConnection(e));return t?(this.nodeAgentGateway.refreshFleetRuntimes(n).catch(e=>{this.logWarn({error:gc(e)},"control plane runtime directory refresh failed")}),this.nodeAgentGateway.readFleetRuntimes(n)):this.nodeAgentGateway.listFleetRuntimes(n,{signal:e})}async createNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.createRuntime(n,t)}async updateNodeRuntime(e,t,n){const s=this.requireNode(e);return this.nodeAgentGateway.updateRuntime(s,t,n)}async deleteNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.deleteRuntime(n,t)}async checkNodeRuntime(e,t){const n=this.requireNode(e);return this.nodeAgentGateway.checkRuntime(n,t)}async listControlledInstances(){return(await this.listNodeInstancesWithDiagnostics()).items.map(pc)}async listControlledInstancesWithDiagnostics(){const e=await this.listNodeInstancesWithDiagnostics();return{items:e.items.map(pc),nodeErrors:e.nodeErrors,nodeStates:e.nodeStates}}async instanceResourceMetrics(e){const t=await this.requireNodeInstance(e);return this.nodeAgentGateway.instanceResourceMetrics(this.requireNode(t.nodeId),t.id)}async nodeOwnsInstance(e,t){const n=this.requireNode(e),s=this.nodeAgentGateway.readFleetInstances([n]);return!!s.items.some(n=>n.id===t&&n.nodeId===e)||"ready"!==s.nodeStates[0]?.phase&&(await this.nodeAgentGateway.listInstances(n)).some(n=>n.id===t&&n.nodeId===e)}createControlledInstance(e){return this.controlledInstanceCreator.create(e)}async updateControlledInstance(e,t){const n=$c.parse(t),s=await this.requireNodeInstance(e),i=this.requireNode(s.nodeId);void 0!==n.config?.aiSessionHistoryLimit&&function(e,t){const n=e.capabilities.agent,s=n&&"object"==typeof n&&!Array.isArray(n)?n.capabilities:void 0;if(!Boolean(s&&"object"==typeof s&&!Array.isArray(s)&&!0===s.aiSessionHistoryLimit)||!Ps(t.capabilities).features.aiSessionPersistenceSettings)throw Object.assign(new Error("This instance does not support managed AI session history retention settings."),{statusCode:409,code:"AI_SESSION_HISTORY_LIMIT_UNSUPPORTED"})}(i,s),void 0!==n.config?.aiSessionAttachmentRetentionDays&&function(e,t){const n=e.capabilities.agent,s=n&&"object"==typeof n&&!Array.isArray(n)?n.capabilities:void 0;if(!Boolean(s&&"object"==typeof s&&!Array.isArray(s)&&!0===s.aiSessionAttachmentRetention)||!0!==t.capabilities.features.aiSessionConversationAttachments?.retentionSettings)throw Object.assign(new Error("This instance does not support managed AI session attachment retention settings."),{statusCode:409,code:"AI_SESSION_ATTACHMENT_RETENTION_UNSUPPORTED"})}(i,s);const{modelSelection:r,...o}=n;let a=Object.keys(o).length?await this.nodeAgentGateway.updateInstance(i,e,o):s;if(r){const t=await this.modelService.prepareAssignment(i,r);a=(await this.nodeAgentGateway.assignInstanceModels(i,e,t)).instance}return pc(a)}async deleteControlledInstance(e,t){const n=ii.parse(t),s=await this.requireNodeInstance(e),i=this.requireNode(s.nodeId),r=await this.nodeAgentGateway.deleteInstance(i,e,n);return r.completed&&this.configSyncPreferences.delete(e),r}listEnvironmentTemplates(e){return this.nodeAgentGateway.listEnvironmentTemplates(this.requireNode(e))}getEnvironmentTemplate(e,t){return this.nodeAgentGateway.getEnvironmentTemplate(this.requireNode(e),t)}async createEnvironmentTemplate(e,t){const n=await this.requireNodeInstance(e);return this.nodeAgentGateway.createEnvironmentTemplate(this.requireNode(n.nodeId),e,t)}deleteEnvironmentTemplate(e,t){return this.nodeAgentGateway.deleteEnvironmentTemplate(this.requireNode(e),t)}async startControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return await this.modelService.ensureInstanceAssignment(t),pc(await this.nodeAgentGateway.startInstance(n,e))}async stopControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return pc(await this.nodeAgentGateway.stopInstance(n,e))}async restartControlledInstance(e){const t=await this.requireNodeInstance(e),n=this.requireNode(t.nodeId);return await this.modelService.ensureInstanceAssignment(t),pc(await this.nodeAgentGateway.restartInstance(n,e))}async retryControlledInstanceImageProvisioning(e){const t=await this.requireNodeInstance(e);return pc(await this.nodeAgentGateway.retryInstanceImageProvisioning(this.requireNode(t.nodeId),e))}async boardAsync(){return await this.listBootstrapNodeInstances(),(await this.boardWithDiagnostics(void 0,!0)).items}async boardWithDiagnostics(e,t=!1){const[n,s]=await Promise.all([this.listNodeRuntimesWithDiagnostics(e,t),this.listNodeInstancesWithDiagnostics(e,t)]);return this.instanceBoardReader.read({projects:this.listProjects(),images:this.listImageOptions(),nodes:this.nodes.list().map(e=>this.projectNodeConnection(e)),runtimes:n.items,instances:s.items,nodeErrors:[...n.nodeErrors,...s.nodeErrors],nodeStates:[...n.nodeStates,...s.nodeStates]})}async bootstrapAiSessionsFromInstances(){const e=await this.listBootstrapNodeInstances(),t=await Promise.all(e.map(async e=>{if(!po(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus)return{streamId:`bootstrap:${e.id}:ai.sessions`,revision:0,lastEventAt:e.aiSessions.updatedAt,snapshot:e.aiSessions};try{return oa(gt,await this.instanceRequest(e,"/ai-sessions/state"))}catch(t){return this.logWarn({instanceId:e.id,error:gc(t),errorCode:"AI_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live AI sessions"),{streamId:`bootstrap:${e.id}:ai.sessions`,revision:0,lastEventAt:e.aiSessions.updatedAt,snapshot:e.aiSessions}}}));return{updatedAt:(new Date).toISOString(),instances:e.map((e,n)=>({instanceId:e.id,streamId:t[n].streamId,aiSessions:t[n].snapshot,revision:t[n].revision,lastEventAt:t[n].lastEventAt}))}}async bootstrapAppSessionsFromInstances(){const e=await this.listBootstrapNodeInstances(),t=await Promise.all(e.map(async e=>{if(!po(e)||!e.target.web||"online"!==e.connectionStatus&&"online"!==e.agentStatus){const t=rn();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:t.updatedAt,snapshot:t}}try{return oa(qt,await this.instanceRequest(e,"/apps/sessions/state"))}catch(t){this.logWarn({instanceId:e.id,error:gc(t),errorCode:"APP_SESSION_LIVE_REFRESH_FAILED"},"control plane failed to refresh live app sessions");const n=rn();return{streamId:`bootstrap:${e.id}:app.sessions`,revision:0,lastEventAt:n.updatedAt,snapshot:n}}}));return{updatedAt:(new Date).toISOString(),instances:e.map((e,n)=>({instanceId:e.id,streamId:t[n].streamId,appSessions:t[n].snapshot,revision:t[n].revision,lastEventAt:t[n].lastEventAt}))}}async recoverAiSessionDelta(e,t,n){const s=await this.requireControlledInstance(e,!0),i=new URLSearchParams({streamId:t,sinceRevision:String(n)});return oa(kt,await this.instanceRequest(s,`/ai-sessions?${i}`))}async recoverAiSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return oa(gt,await this.instanceRequest(t,"/ai-sessions/state"))}async recoverAppSessionDelta(e,t,n){const s=await this.requireControlledInstance(e,!0),i=new URLSearchParams({streamId:t,sinceRevision:String(n)});return oa(Wt,await this.instanceRequest(s,`/apps/sessions?${i}`))}async recoverAppSessionSnapshot(e){const t=await this.requireControlledInstance(e,!0);return oa(qt,await this.instanceRequest(t,"/apps/sessions/state"))}async listTriggers(){return this.controlPlaneTriggerService.listTriggers()}createTrigger(e){return this.controlPlaneTriggerService.createTrigger(e)}async updateTrigger(e,t){return this.controlPlaneTriggerService.updateTrigger(e,t)}async deleteTrigger(e){return this.controlPlaneTriggerService.deleteTrigger(e)}async applyTrigger(e,t){return this.controlPlaneTriggerService.applyTrigger(e,t)}async listInstanceTriggers(e){return this.controlPlaneTriggerService.listInstanceTriggers(e)}async bindAiSessionTrigger(e,t,n){return this.controlPlaneTriggerService.bindAiSessionTrigger(e,t,n)}async unbindAiSessionTrigger(e,t,n){return this.controlPlaneTriggerService.unbindAiSessionTrigger(e,t,n)}async runInstanceTrigger(e,t,n={}){return this.controlPlaneTriggerService.runInstanceTrigger(e,t,n)}listChatSessions(){return this.chatSessionService.list()}createAppAccessToken(e){return this.appAccessService.createToken(e)}createAppSessionAccessToken(e){return this.appAccessService.createSessionToken(e)}revokeAppSessionAccessToken(e,t){this.appAccessService.revokeToken(e,t)}resolveAppAccessToken(e,t){return this.appAccessService.resolveToken(e,t)}createChatActionToken(e){return this.chatActionTokenService.create(e)}resolveChatActionToken(e,t){return this.chatActionTokenService.resolve(e,t)}pendingDecisionCallbackData(e,t){return this.chatActionTokenService.pendingDecisionCallbackData(e,t)}async appAccessProxyTarget(e,t,n=""){return this.appAccessService.proxyTarget(e,t,n)}listChatBridges(){return this.chatBridgeService.list()}requireChatBridge(e){return this.chatBridgeService.require(e)}createChatBridge(e){return this.chatBridgeService.create(e)}updateChatBridge(e,t){return this.chatBridgeService.update(e,t)}deleteChatBridge(e){return this.chatBridgeService.delete(e)}requireChatSession(e){return this.chatSessionService.require(e)}upsertChatSession(e){return this.chatSessionService.upsert(e)}async handleChatGatewayMessage(e){return this.chatSessionRuntime.handleChatGatewayMessage(e)}async handleChatGatewayAction(e){return this.chatSessionRuntime.handleChatGatewayAction(e)}async handleChatCommand(e,t){return this.chatSessionRuntime.handleChatCommand(e,t)}async listPendingRoutes(){const e=Eo(),t=[],n=await this.listAiSessions(),s=new Map(n.instances.map(e=>[e.instanceId,e.aiSessions])),i=this.readCachedNodeInstances();this.refreshCachedNodeInstances();for(const n of i.items){if("online"!==n.connectionStatus&&"online"!==n.agentStatus||!n.target.web)continue;const i=n.projectId?this.catalogService.getProject(n.projectId):void 0;for(const r of s.get(n.id)?.sessions||[]){if("waiting"!==r.status)continue;const s=lo.parse({id:`${n.id}:ai:${r.id}`,instanceId:n.id,projectId:n.projectId,aiSessionId:r.id,providerSessionId:r.providerSessionId,result:r.summary||r.currentTool?.inputPreview||r.lastMessage||`${r.agent} is waiting for approval`,source:r.agent,kind:"approval",status:"pending",lastSeenAt:e});t.push({...s,project:i,instance:pc(n)})}}return t}async listAiSessionInstanceNames(){return(await this.listBootstrapNodeInstances()).map(e=>({id:e.id,name:e.name}))}resolveAiSessionApproval(e,t,n){return this.aiSessionActionService.resolveApproval(e,t,n)}listAiSessionHistory(e){return this.aiSessionActionService.listHistory(e)}getAiSessionHistoryDetail(e,t){return this.aiSessionActionService.historyDetail(e,t)}getAiSessionTimeline(e,t){return this.aiSessionActionService.timeline(e,t)}getAiSessionTurnTimeline(e,t,n){return this.aiSessionActionService.turnTimeline(e,t,n)}resumeAiSession(e,t){return this.aiSessionActionService.resume(e,t)}async createAiSession(e,t){const n=await this.requireControlledInstance(e,!0),{cwdFolderId:s,...i}=t,r={type:"runtime-path",path:await this.aiSessionRuntimeCwd(n,t.cwdFolderId)};return this.aiSessionActionService.create(e,{...i,cwd:r,...t.cwdFolderId?{cwdFolderId:t.cwdFolderId}:{}})}async inspectAiSessionWorkspace(e,t){const n=await this.requireControlledInstance(e,!0),s={type:"runtime-path",path:await this.aiSessionRuntimeCwd(n,t)};return this.aiSessionActionService.inspectWorkspace(e,s)}forkAiSession(e,t,n){return this.aiSessionActionService.fork(e,t,n)}openAiSessionApp(e,t,n){return this.aiSessionActionService.openApp(e,t,n)}closeAiSession(e,t,n){return this.aiSessionActionService.close(e,t,n)}aiSessionActionDiagnostics(){return this.aiSessionActionService.diagnostics()}async launchAppSession(e,t="terminal-tty",n={}){const s=await this.requireControlledInstance(e,!0);if("online"!==s.connectionStatus&&"online"!==s.agentStatus){const e=new Error(`Instance ${s.name} is still starting. Wait for it to connect before launching apps.`);throw Object.assign(e,{statusCode:409,code:"INSTANCE_NOT_CONNECTED"}),e}const i=await this.resolveAppLaunchOptions(s,n),r=await this.instanceRequest(s,"/apps/sessions",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({appId:t,...i})});return await this.listAppSessions({refresh:!0}),r}async stopAppSession(e,t){const n=await this.requireControlledInstance(e,!0),s=await this.instanceRequest(n,`/apps/sessions/${encodeURIComponent(t)}/stop`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})});return await this.listAppSessions({refresh:!0}),s}async instanceAppManagement(e){const t=await this.requireControlledInstance(e,!0);try{return function(e){try{return oa(Ci,e)}catch(e){if(e instanceof d.z.ZodError){const e=new Error("This controlled instance does not support managed app operations.");throw Object.assign(e,{statusCode:409,code:"INSTANCE_APP_MANAGEMENT_UNSUPPORTED"}),e}throw e}}(await this.instanceRequest(t,"/apps/management"))}catch(e){const t=e&&"object"==typeof e?e:{};if(e instanceof d.z.ZodError||404===t.statusCode){const e=new Error("This controlled instance does not support managed app operations.");throw Object.assign(e,{statusCode:409,code:"INSTANCE_APP_MANAGEMENT_UNSUPPORTED"}),e}throw e}}async requestInstanceAppOperation(e,t,n,s={}){const i=await this.requireControlledInstance(e,!0);return oa(xi,await this.instanceRequest(i,`/apps/${encodeURIComponent(t)}/${n}`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(s)}))}async instanceAppManagementJob(e,t){const n=await this.requireControlledInstance(e,!0);return oa(xi,await this.instanceRequest(n,`/apps/jobs/${encodeURIComponent(t)}`))}async renameAppSession(e,t,n){const s=await this.requireControlledInstance(e,!0),i=await this.instanceRequest(s,`/apps/sessions/${encodeURIComponent(t)}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({title:n})});return await this.listAppSessions({refresh:!0}),i}sendAiSessionMessage(e,t,n,s,i=[],r=[],o,a){return this.aiSessionActionService.sendMessage(e,t,n,s,i,r,o,a)}aiSessionMentionCatalog(e,t){return this.aiSessionActionService.mentionCatalog(e,t)}searchAiSessionMentionFiles(e,t,n){return this.aiSessionActionService.searchMentionFiles(e,t,n)}executeAiSessionCommand(e,t,n){return this.aiSessionActionService.executeCommand(e,t,n)}aiSessionQueue(e,t){return this.aiSessionActionService.queue(e,t)}getAiSessionDetail(e,t){return this.aiSessionActionService.detail(e,t)}steerAiSessionQueuedMessage(e,t,n){return this.aiSessionActionService.steerQueuedMessage(e,t,n)}retryAiSessionQueuedMessage(e,t,n){return this.aiSessionActionService.retryQueuedMessage(e,t,n)}removeAiSessionQueuedMessage(e,t,n){return this.aiSessionActionService.removeQueuedMessage(e,t,n)}editAiSessionQueuedMessage(e,t,n,s){return this.aiSessionActionService.editQueuedMessage(e,t,n,s)}reorderAiSessionQueuedMessages(e,t,n){return this.aiSessionActionService.reorderQueuedMessages(e,t,n)}interruptAiSession(e,t){return this.aiSessionActionService.interrupt(e,t)}async proxyInstanceHttp(e,t,n={}){const s=await this.requireControlledInstance(e,!0);return this.controlledInstanceGateway.proxyHttp(s,t,n)}async proxyInstanceWebSocket(e,t,n,s,i={}){const r=await this.requireControlledInstance(e,!0);this.controlledInstanceGateway.proxyWebSocket(r,t,n,s,i)}async instanceConfigSyncState(e){const t=await this.requireControlledInstance(e,!0),n=d.z.array(ua).parse(await this.instanceRequest(t,"/config-sync/programs"));return ga.parse({programs:n,preferences:this.configSyncPreferences.get(e)?.preferences||zp()})}async listInstanceConfigSyncFolders(e,t={}){const n=await this.requireControlledInstance(e,!0),s=new URLSearchParams;return t.path&&s.set("path",t.path),void 0!==t.depth&&s.set("depth",String(t.depth)),d.z.array(Gr).parse(await this.instanceRequest(n,"/config-sync/folders"+(s.size?`?${s}`:"")))}async syncInstanceConfigs(e,t){const n=ha.parse(t),s=await this.requireControlledInstance(e,!0);if("export"===n.direction&&"local-folder"!==s.source.type){const e=new Error("Exporting instance config is only available for local folder projects.");throw Object.assign(e,{statusCode:400,code:"CONFIG_SYNC_EXPORT_REQUIRES_LOCAL_PROJECT"}),e}const i=function(e){const t=function(e){const t=[];for(const n of e.split("/"))if(n&&"."!==n)if(".."===n){if(!t.length)return"..";t.pop()}else t.push(n);return t.join("/")||"."}(e.trim().replace(/\\/g,"/")||".");if(t.startsWith("/")||".."===t||t.startsWith("../")){const e=new Error("Config sync folder must stay inside the instance workspace.");throw Object.assign(e,{statusCode:400,code:"CONFIG_SYNC_FOLDER_INVALID"}),e}return t||"."}(n.workspaceFolder),r={...n,workspaceFolder:i},o=oa(Ia,await this.instanceRequest(s,"/config-sync",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(r)})),a=Eo(),d=this.configSyncPreferences.get(e);return this.configSyncPreferences.put({id:e,preferences:{...d?.preferences||zp(),[n.direction]:i},createdAt:d?.createdAt||a,updatedAt:a}),o}async instanceRequest(e,t,n={},s){return this.controlledInstanceGateway.request(e,t,n,s)}async reportInstanceHeartbeat(e,t){await this.controlledInstanceGateway.reportHeartbeat(e,t)}async nodeAgentFetch(e,t,n={}){const s="reverse-wss"!==e.connectionMode&&"control-plane-proxy"!==e.connectionMode;try{const i=await this.nodeAgentTransportResolver.resolve(e).request(e,t,n);return s&&this.nodeConnectionRuntime?.observedReachable(e),i}catch(t){throw!s||n.signal?.aborted||function(e){return e instanceof Error&&("AbortError"===e.name||"ABORT_ERR"===e.code)}(t)||this.nodeConnectionRuntime?.observedFailure(e,gc(t)),t}}readCachedNodeInstances(){return this.nodeAgentGateway.readFleetInstances(this.listNodes().map(e=>this.projectNodeConnection(e)))}refreshCachedNodeInstances(){const e=this.listNodes().map(e=>this.projectNodeConnection(e));this.nodeAgentGateway.refreshFleetInstances(e).catch(e=>{this.logWarn({error:gc(e)},"control plane instance directory refresh failed")})}async listCachedNodeInstances(){const e=this.readCachedNodeInstances();return this.refreshCachedNodeInstances(),e.items}async listBootstrapNodeInstances(){const e=this.listNodes().map(e=>this.projectNodeConnection(e));return await this.nodeAgentGateway.refreshFleetInstances(e),this.nodeAgentGateway.readFleetInstances(e).items}async listTriggerMutationInstances(){const e=this.listNodes().map(e=>this.projectNodeConnection(e));await this.nodeAgentGateway.refreshFleetInstances(e);const t=this.nodeAgentGateway.readFleetInstances(e),n=new Set(t.nodeStates.filter(e=>"ready"===e.phase).map(e=>e.nodeId)),s=t.nodeStates.filter(e=>"ready"!==e.phase).map(e=>({scope:"node",nodeId:e.nodeId,code:e.error?.code||"TRIGGER_NODE_DIRECTORY_UNAVAILABLE",message:e.error?.message||`Node ${e.nodeId} instance directory is ${e.phase}; trigger deployment changes were skipped.`}));return{items:t.items.filter(e=>n.has(e.nodeId)),partialFailures:s}}async listNodeInstancesWithDiagnostics(e,t=!1){const n=this.listNodes().map(e=>this.projectNodeConnection(e));return t?(this.nodeAgentGateway.refreshFleetInstances(n).catch(e=>{this.logWarn({error:gc(e)},"control plane instance directory refresh failed")}),this.nodeAgentGateway.readFleetInstances(n)):this.nodeAgentGateway.listFleetInstances(n,{signal:e})}async requireNodeInstance(e){const t=this.listNodes(),n=this.nodeAgentGateway.instanceFromSnapshot(t,e);if(n)return n;const s=(await this.nodeAgentGateway.listFleetInstances(t)).items.find(t=>t.id===e);if(s)return s;yc("CONTROLLED_INSTANCE_NOT_FOUND",`Controlled instance ${e} was not found.`)}async requireNodeRuntimeOnNode(e,t){const n=(await this.listNodeRuntimes(e)).find(e=>e.id===t);return n||yc("NODE_RUNTIME_NOT_FOUND",`Runtime ${t} was not found on node ${e}.`),n}async requireNodeLocalFolder(e,t){return this.nodeAgentGateway.requireLocalFolder(e,t)}async resolveAppLaunchOptions(e,t){const n="string"==typeof t.cwdFolderId?t.cwdFolderId.trim():"",s={...t};return delete s.cwdFolderId,n?{...s,cwd:await this.runtimeCwdForFolderId(e,n)}:s}async runtimeCwdForFolderId(e,t){const n=this.requireNode(e.nodeId),s=await this.requireNodeLocalFolder(n,t);if(s.nodeId!==e.nodeId){const t=new Error(`Local folder ${s.id} belongs to node ${s.nodeId}, not ${e.nodeId}.`);throw Object.assign(t,{statusCode:400,code:"LOCAL_FOLDER_REQUIRES_INSTANCE_NODE"}),t}const i=await this.requireNodeRuntimeOnNode(e.nodeId,e.runtimeId);return this.appLaunchCwdForFolder(e,s,i)}async aiSessionRuntimeCwd(e,t){return t?this.runtimeCwdForFolderId(e,t):e.runtime.workspacePath||e.workspace.path||lc(e.source).path||"/workspace"}appLaunchCwdForFolder(e,n,s){const i=function(e,n,s){if("local"===s.type)return Tp(i=n).resolve(i);var i;if("local-folder"!==e.source.type)return;const r=function(e,t){if(kp(e)!==kp(t))return;const n=Tp(e),s=n.resolve(e),i=n.resolve(t),r=n.relative(s,i);return r?".."===r||r.startsWith(`..${n.sep}`)||n.isAbsolute(r)?void 0:r.split(n.sep).filter(Boolean):[]}(e.source.path,n);if(!r)return;const o=e.runtime.workspacePath||e.workspace.path||lc(e.source).path||"/workspace";return r.length?t.posix.join(o,...r):o}(e,n.path,s);if(i)return i;if("local-folder"!==e.source.type){const e=new Error("App cwd folder selection is only supported for local-folder instances.");throw Object.assign(e,{statusCode:400,code:"APP_CWD_REQUIRES_LOCAL_FOLDER_SOURCE"}),e}const r=new Error(`Local folder ${n.path} is outside the instance workspace ${e.source.path}.`);throw Object.assign(r,{statusCode:400,code:"APP_CWD_OUTSIDE_WORKSPACE"}),r}requireProject(e){return this.catalogService.requireProject(e)}requireModel(e,t=!1){return this.modelService.require(e,t)}requireImage(e){return this.catalogService.requireImage(e)}requireNode(e){const t=this.nodes.get(e);return t||yc("NODE_NOT_FOUND",`Node ${e} was not found.`),t}requirePublicNode(e){return cc(this.projectNodeConnection(this.requireNode(e)))}async requireControlledInstance(e,t=!1){const n=await this.requireNodeInstance(e);return t?n:pc(n)}}function _p(e){return g(String(e),"escape").replace(/\n+$/,"")}function Pp(e){const[t,...n]=String(e).split("\n");return[`*${_p(t)}*`,...n.map(_p)].join("\n")}function jp(e,t=4e3){const n=String(e),s=Pp(n);if(s.length<=t)return s;const[i,...r]=n.split("\n"),o=r.join("\n"),a="...\n";let d=i;for(;Pp(`${d}\n${a}`).length>t&&d.length>0;)d=d.slice(0,Math.floor(.8*d.length));let c=0,l=o.length,p=0,u=Pp(`${d}\n${a}`);for(;c<=l;){const e=Math.floor((c+l)/2),n=Pp(`${d}\n${a}${o.slice(-e)}`);n.length<=t?(u=n,p=e,c=e+1):l=e-1}const h=o.slice(-p),m=h.indexOf("\n");return m>=0&&m<200&&(u=Pp(`${d}\n${a}${h.slice(m+1)}`)),u}function Dp(e){return String(e).replace(/\\([_*\[\]()~`>#+\-=|{}.!\\])/g,"$1")}async function Mp(e,t,n,s,i={}){if(!t.token)return;const r=n=>e(`https://api.telegram.org/bot${t.token}/sendMessage`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)}),o=function(e,t={}){const n=String(e),s=t.rawMarkdownV2?e=>e:_p;if(s(n).length<=4e3)return[n];const i=[];let r=n;for(;r;){let e=1,t=r.length,n=1;for(;e<=t;){const i=Math.floor((e+t)/2);s(r.slice(0,i)).length<=4e3?(n=i,e=i+1):t=i-1}if(n<r.length){const e=r.slice(0,n),t=Math.max(e.lastIndexOf("\n"),e.lastIndexOf(" "));t>=Math.floor(.6*n)&&(n=t+1)}i.push(r.slice(0,n).trimEnd()),r=r.slice(n).trimStart()}return i.filter(Boolean)}(s,i);let a;for(const[e,t]of o.entries())a=await qp(r,"sendMessage",t,{chat_id:n,...0===e&&i.replyToMessageId?{reply_to_message_id:i.replyToMessageId,allow_sending_without_reply:!0}:{},...e===o.length-1&&i.replyMarkup?{reply_markup:i.replyMarkup}:{}},i);return a}async function Lp(e,t,n){if(!t.token||!n)throw new Error("Telegram file id is required.");const s=await e(`https://api.telegram.org/bot${t.token}/getFile`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({file_id:n})}),i=await s.json().catch(()=>({}));if(!s.ok||!1===i.ok||!i.result?.file_path)throw new Error(i.description||`Telegram getFile failed with HTTP ${s.status}`);return`https://api.telegram.org/file/bot${t.token}/${i.result.file_path}`}async function qp(e,t,n,s,i){const r=i.parseMode||"MarkdownV2",o=i.rawMarkdownV2?String(n):_p(n),a=await e({...s,text:o,disable_web_page_preview:!0,parse_mode:r}),d=await a.json().catch(()=>({}));if(a.ok&&!1!==d.ok)return d.result;if("editMessageText"===t&&$p(d.description))return;if(i.rawMarkdownV2&&"MarkdownV2"===r){const i=await e({...s,text:Dp(n),disable_web_page_preview:!0,parse_mode:"Markdown"}),r=await i.json().catch(()=>({}));if(i.ok&&!1!==r.ok)return r.result;if("editMessageText"===t&&$p(r.description))return}const c=await e({...s,text:i.rawMarkdownV2?Dp(n):String(n),disable_web_page_preview:!0}),l=await c.json().catch(()=>({}));if(c.ok&&!1!==l.ok)return l.result;if("editMessageText"!==t||!$p(l.description))throw new Error(l.description||d.description||`Telegram ${t} failed with HTTP ${c.status}`)}function $p(e){return"string"==typeof e&&e.toLowerCase().includes("message is not modified")}function Bp(e,t){if("string"==typeof e&&e.trim())return e.trim();Up(`Chat action token is missing ${t}.`)}function Fp(e){if("allow"===e||"deny"===e||"skip"===e)return e;Up("Chat action token has an invalid decision.")}function Up(e){const t=new Error(e);throw Object.assign(t,{statusCode:400,code:"CHAT_ACTION_TOKEN_INVALID"}),t}function Hp(e){return Buffer.from(e,"base64url").toString("utf8")}function Wp(e){return String(e||"").split(/\r?\n/,1)[0].replace(/^#+\s*/,"").trim().slice(0,20)||"消息通知"}function Gp(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,"string"==typeof t?t:JSON.stringify(t)]))}function Vp(e){return`dtv1.card//IM_GROUP.${e}`}function Kp(e){return`dtv1.card//IM_ROBOT.${e}`}function Jp(e,t){return lu(t.biz_conversation_id).trim()||lu(e.spaceId).replace(/^dtv1\.card\/\/(?:IM_GROUP|IM_SINGLE|IM_ROBOT)\./,"")}function Yp(e,t={}){const n=lu(e).trim().toUpperCase();return"2"===n||"IM_GROUP"===n?"IM_GROUP":"1"===n||"IM_SINGLE"===n?t.robotMessage?"IM_ROBOT":"IM_SINGLE":"IM_ROBOT"===n?"IM_ROBOT":void 0}function Qp(e){if(e.startsWith("task_handoff:"))return e;if(!e.startsWith("th_cb_"))return"";try{return Buffer.from(e.slice(6),"base64url").toString("utf8")}catch{return""}}function Xp(e,t,n,s,i){const r=Jp(s,i);return{cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},cardData:{cardParamMap:Gp({type:"actions",title:"TaskHandoff",description:e,list:Ql(t),biz_out_track_id:s.outTrackId||i.biz_out_track_id||"",biz_conversation_id:r,biz_sender_id:i.biz_sender_id||s.userId||"",biz_session_webhook:i.biz_session_webhook||"",biz_conversation_type:i.biz_conversation_type||"",biz_step:n,error_msg:""})}}}function Zp(e,t,n){const s=[];return eu(s,n),eu(s,t),eu(s,e),s.find(e=>Qp(e))||""}function eu(e,t){for(const n of["actionIdList","actionIds"]){const s=t[n];Array.isArray(s)&&e.push(...s.map(e=>lu(e)).filter(Boolean))}for(const n of["actionId","action_id","id","actionValue"]){const s=lu(t[n]);s&&e.push(s)}}async function tu(e,t,n,s){s?.("info",{target:"sessionWebhook",hasSessionWebhook:Boolean(t),textPreview:au(n)},"dingding webhook send requested");const i=await e(t,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({msgtype:"markdown",markdown:{title:Wp(n),text:n}})}),r=await i.json().catch(()=>{});if(s?.(i.ok?"info":"warn",{target:"sessionWebhook",status:i.status,response:ou(r)},"dingding webhook send completed"),!i.ok)throw new Error(`DingDing webhook failed with HTTP ${i.status}`)}async function nu(e){const t=Ql(e.replyMarkup);if(!t.length&&!e.forceCard)return e.sessionWebhook&&await tu(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),e.sessionWebhook?{delivered:!0}:void 0;const n=e.bridge.settings||{},s=lu(n.robotCode),i=lu(n.cardTemplateId)||"13fc6717-12e4-43ed-8533-111a310d4995.schema",r=lu(n.cardCallbackRouteKey)||"task_handoff_message",o=e.senderId||e.runtime.senderIds.get(e.chatId)||lu(n.senderId),a=(d=e.runtime,c=e.chatId,d.conversationTypes?.get(c)||"IM_GROUP");var d,c;if(!s||!i||!o){if(e.sessionWebhook&&!e.forceCard)return await tu(e.fetchImpl,e.sessionWebhook,e.text,e.runtime.onLog),{delivered:!0};throw new Error("DingDing card target is incomplete.")}const l=`task_handoff_cp_${Date.now()}_${Math.random().toString(16).slice(2)}`,p=Gp({type:"actions",title:e.title||Wp(e.text),description:e.text,list:t,biz_out_track_id:l,biz_step:e.step||"task_handoff_actions",biz_conversation_id:e.chatId,biz_sender_id:o,biz_session_webhook:e.sessionWebhook||e.runtime.chatWebhooks.get(e.chatId)||"",biz_conversation_type:a,error_msg:""}),u=function(e,t,n,s){return"IM_SINGLE"===e?{openSpaceId:(i=t,`dtv1.card//IM_SINGLE.${i}`),imSingleOpenSpaceModel:{},imSingleOpenDeliverModel:{extension:{}}}:"IM_ROBOT"===e?{openSpaceId:Kp(n),imRobotOpenSpaceModel:{supportForward:!1},imRobotOpenDeliverModel:{extension:{},robotCode:s,spaceType:"IM_ROBOT"}}:{openSpaceId:Vp(t),imGroupOpenSpaceModel:{supportForward:!1},imGroupOpenDeliverModel:{extension:{},robotCode:s}};var i}(a,e.chatId,o,s);return e.runtime.onLog?.("info",{target:"card",chatId:e.chatId,senderId:o,conversationType:a,openSpaceId:u.openSpaceId,hasSessionWebhook:Boolean(e.sessionWebhook||e.runtime.chatWebhooks.get(e.chatId)),hasReplyMarkup:Boolean(e.replyMarkup),actionCount:t.length,textPreview:au(e.text)},"dingding card send requested"),await su(e.fetchImpl,e.bridge,e.runtime,"POST","/v1.0/card/instances/createAndDeliver",{userId:o,cardTemplateId:i,outTrackId:l,callbackType:"STREAM",callbackRouteKey:r,cardData:{cardParamMap:p},userIdType:Number(n.cardUserIdType||1),...u}),{delivered:!0,outTrackId:l}}async function su(e,t,n,s,i,r){const o=await async function(e,t,n){if(n.accessToken&&n.accessToken.expiresAt>Date.now()+6e4)return n.accessToken.value;const s=lu(t.settings.clientSecret);if(!t.token||!s)throw new Error("DingDing client id/secret is not configured.");const i=await e("https://api.dingtalk.com/v1.0/oauth2/accessToken",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({appKey:t.token,appSecret:s})}),r=await i.json().catch(()=>({}));if(!i.ok||!r.accessToken)throw new Error(`DingDing access token failed with HTTP ${i.status}`);const o=Number(r.expireIn||7200);return n.accessToken={value:r.accessToken,expiresAt:Date.now()+1e3*Math.max(60,o-120)},n.accessToken.value}(e,t,n);n.onLog?.("info",{method:s,path:i,body:iu(r)},"dingding api request");const a=await e(`https://api.dingtalk.com${i}`,{method:s,headers:{"content-type":"application/json","x-acs-dingtalk-access-token":o},body:JSON.stringify(r)}),d=await a.json().catch(()=>{});if(n.onLog?.(a.ok?"info":"warn",{method:s,path:i,status:a.status,response:ou(d)},"dingding api response"),!a.ok)throw new Error(`DingDing API failed with HTTP ${a.status}`);const c=du(d),l=c.code??c.errcode,p=c.success;if(void 0!==l&&"0"!==String(l)||!1===p)throw new Error(lu(c.message||c.errmsg)||`DingDing API returned ${String(l||"failure")}`);const u=function(e){const t=du(du(e).result).deliverResults;if(!Array.isArray(t))return"";const n=t.find(e=>!1===du(e).success);if(!n)return"";const s=du(n),i=lu(s.spaceId),r=lu(s.errorMsg||s.message||s.errmsg)||"delivery failed";return i?`DingDing card delivery failed for ${i}: ${r}`:`DingDing card delivery failed: ${r}`}(d);if(u)throw new Error(u);return a}function iu(e){const t=du(e),n=du(t.cardData),s=du(n.cardParamMap);return{openSpaceId:lu(t.openSpaceId),outTrackId:lu(t.outTrackId),userId:lu(t.userId),userIdType:t.userIdType,callbackType:lu(t.callbackType),callbackRouteKey:lu(t.callbackRouteKey),hasImGroupTarget:Boolean(t.imGroupOpenSpaceModel||t.imGroupOpenDeliverModel),hasImSingleTarget:Boolean(t.imSingleOpenSpaceModel||t.imSingleOpenDeliverModel),hasImRobotTarget:Boolean(t.imRobotOpenSpaceModel||t.imRobotOpenDeliverModel),imGroupOpenDeliverModel:ru(t.imGroupOpenDeliverModel),imSingleOpenDeliverModel:ru(t.imSingleOpenDeliverModel),imRobotOpenDeliverModel:ru(t.imRobotOpenDeliverModel),bizConversationId:lu(s.biz_conversation_id),bizConversationType:lu(s.biz_conversation_type),bizSenderId:lu(s.biz_sender_id),hasBizSessionWebhook:Boolean(lu(s.biz_session_webhook))}}function ru(e){const t=du(e);if(Object.keys(t).length)return{hasExtension:Boolean(t.extension),hasRobotCode:Boolean(lu(t.robotCode)),spaceType:lu(t.spaceType),recipients:Array.isArray(t.recipients)?t.recipients.length:void 0,atUserIds:t.atUserIds&&"object"==typeof t.atUserIds?Object.keys(t.atUserIds).length:void 0}}function ou(e){const t=du(e),n=du(t.result);return{code:t.code??t.errcode,message:au(t.message||t.errmsg,240),success:t.success,requestId:t.requestId,result:Object.keys(n).length?n:void 0}}function au(e,t=160){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function du(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function cu(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:"string"==typeof e&&e.trim()?pu(e):{}}function lu(e){return"string"==typeof e?e:""}function pu(e){try{return du(JSON.parse(String(e||"{}")))}catch{return{}}}function uu(e){return JSON.stringify(Ql(e))}const hu="task_handoff_action_id";function mu(e,t){const n=Ql(t);return{schema:"2.0",config:{summary:{content:fu(e)}},body:{elements:[{tag:"markdown",content:e},...n.map(e=>({tag:"button",text:{tag:"plain_text",content:e.text},type:Iu(e.text),width:"fill",size:"medium",behaviors:[{type:"callback",value:{[hu]:e.id}}]}))]}}}function gu(e){const t=function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e);return function(e){const t=String(e||"");return t.startsWith("th_cb_")?function(e){try{return Buffer.from(e,"base64url").toString("utf8")}catch{return""}}(t.slice(6)):""}(t[hu]||t.action_id||t.actionId||t.id||e)}function yu(e){return JSON.stringify(Ql(e))}function fu(e){const t=e.replace(/\s+/g," ").trim();return t.length<=50?t:`${t.slice(0,47)}...`}function Iu(e){const t=e.trim().toLowerCase();return["deny","cancel","delete","remove"].some(e=>t.includes(e))?"danger":["allow","approve","launch","open"].some(e=>t.includes(e))?"primary":"default"}function bu(e){return e instanceof Error?e.message:String(e)}function vu(e){const t=Number(function(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}(e).message_id);return Number.isInteger(t)&&t>0?t:void 0}function Su(e){return Array.isArray(e?.actionRows)?e.actionRows:(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e])}function wu(e,t){const n=Su(e),s=Su(t);return n.length===s.length&&n.every((e,t)=>{const n=s[t];return e.length===n.length&&e.every((e,t)=>{const s=n[t];return e.text===s?.text&&e.callbackData===s.callbackData})})}class Au{entries;updateIntervalMs;send;edit;deleteMessage;messageIdFromResult;retryAfterMs;isMessageTooLong;onLog;constructor(e){this.entries=e.entries||new Map,this.updateIntervalMs=e.updateIntervalMs||1e3,this.send=e.send,this.edit=e.edit,this.deleteMessage=e.delete,this.messageIdFromResult=e.messageIdFromResult||vu,this.retryAfterMs=e.retryAfterMs,this.isMessageTooLong=e.isMessageTooLong,this.onLog=e.onLog}remember(e,t,n,s,i,r){const o=this.entries.get(e);return o&&(clearTimeout(o.timer),o.timer=void 0,o.pendingText=void 0),this.entries.set(e,{lastText:n,lastUpdateAt:Date.now(),messageId:t,route:s,options:i,lastOptions:i,renderOptions:r}),o}rekey(e,t){if(e===t)return this.entries.has(e);const n=this.entries.get(e);if(!n||this.entries.has(t))return!1;if(clearTimeout(n.timer),n.timer=void 0,this.entries.delete(e),this.entries.set(t,n),n.pendingText){const e=n.rateLimitedUntil?Math.max(0,n.rateLimitedUntil-Date.now()):Math.max(0,this.updateIntervalMs-(Date.now()-n.lastUpdateAt));this.scheduleFlush(t,e)}return!0}scheduleFlush(e,t){const n=this.entries.get(e);n&&!n.timer&&(n.timer=setTimeout(()=>{n.timer=void 0;const t=n.pendingText;n.pendingText=void 0,t&&this.applyUpdate(e,t,n.route,n.options)},t))}markRateLimited(e,t,n,s){const i=this.entries.get(e);i&&(i.rateLimitedUntil=Date.now()+n,i.pendingText=t,i.route=s||i.route,this.scheduleFlush(e,n))}async applyUpdate(e,t,n,s){let i=this.entries.get(e);const r=i,o=n||i?.route,a=s||i?.options;try{if(i&&(i.route=o,i.options=a),i?.pending&&await i.pending,i=this.entries.get(e),r&&i!==r)return!1;if(i?.messageId){if(i.lastText===t&&wu(i.lastOptions,a))return!0;const n=Date.now()-(i.lastUpdateAt||0);return n<this.updateIntervalMs?(i.pendingText=t,i.route=o||i.route,i.options=a||i.options,this.scheduleFlush(e,this.updateIntervalMs-n),!0):(await this.edit(i.messageId,t,o||i.route,a),i.lastText=t,i.lastOptions=a,i.lastUpdateAt=Date.now(),i.rateLimitedUntil=void 0,!0)}const n={lastText:t,lastUpdateAt:Date.now(),route:o,options:a,lastOptions:a};return n.pending=this.send(t,o,a).then(e=>{const t=this.messageIdFromResult(e);t&&(n.messageId=t)}).finally(()=>{n.pending=void 0}),this.entries.set(e,n),await n.pending,this.entries.get(e)===n&&(n.rateLimitedUntil=void 0,Boolean(n.messageId))}catch(n){const s=this.retryAfterMs?.(n);return s&&this.markRateLimited(e,t,s,o),this.onLog?.(`Telegram progress update skipped: ${bu(n)}`),!1}}update(e,t,n,s){const i=String(t||"").trim();if(!i)return;const r=this.entries.get(e);if(r&&(r.route=n||r.route,r.options=s||r.options),r?.lastText===i&&wu(r.lastOptions,s||r.options)&&!r.pending&&!r.pendingText)return;const o=Date.now();if(r?.rateLimitedUntil){if(r.rateLimitedUntil>o)return r.pendingText=i,void this.scheduleFlush(e,r.rateLimitedUntil-o);r.rateLimitedUntil=void 0}if(r?.pending&&!r.messageId)return r.pendingText=i,void this.scheduleFlush(e,this.updateIntervalMs);if(!r||!r.messageId)return void this.applyUpdate(e,i,n,s);const a=Date.now()-(r.lastUpdateAt||0);if(a>=this.updateIntervalMs)return clearTimeout(r.timer),r.timer=void 0,r.pendingText=void 0,void this.applyUpdate(e,i,n||r.route,s||r.options);r.pendingText=i,this.scheduleFlush(e,this.updateIntervalMs-a)}async finish(e,t,n,s,i){const r=this.entries.get(e);if(!r)return!1;try{if(clearTimeout(r.timer),r.timer=void 0,r.pendingText=void 0,r.pending&&await r.pending,this.entries.delete(e),!r.messageId)return!1;const o=s||r.options;return r.lastText===t&&wu(r.lastOptions,o)||await this.edit(r.messageId,t,n||r.route,o,i||r.renderOptions),!0}catch(t){return this.entries.delete(e),this.isMessageTooLong?.(t)?this.onLog?.("Telegram progress finish too long; sending result as multiple messages"):this.onLog?.(`Telegram progress finish skipped: ${bu(t)}`),!1}}async delete(e,t){const n=this.entries.get(e);if(!n)return!1;try{return clearTimeout(n.timer),n.timer=void 0,n.pendingText=void 0,n.pending&&await n.pending,this.entries.delete(e),!(!this.deleteMessage||!n.messageId)&&(await this.deleteMessage(n.messageId,t||n.route),!0)}catch(t){return this.entries.delete(e),this.onLog?.(`Telegram progress delete skipped: ${bu(t)}`),!1}}async flush(e){const t=this.entries.get(e);if(t?.pending&&await t.pending,t?.timer){clearTimeout(t.timer),t.timer=void 0;const n=t.pendingText;t.pendingText=void 0,n&&await this.applyUpdate(e,n,t.route,t.options)}}async wait(e){await function(e){return new Promise(t=>setTimeout(t,e))}(e)}}const zu=20971520;function ku(e){const t=[],n=[...e.photo||[]].filter(e=>e.file_id).sort((e,t)=>Number(t.file_size||t.width||0)-Number(e.file_size||e.width||0))[0];return n?.file_id&&t.push({fileId:n.file_id,fileName:"telegram-photo.jpg",fileSize:n.file_size}),e.document?.file_id&&String(e.document.mime_type||"").startsWith("image/")&&t.push({fileId:e.document.file_id,fileName:e.document.file_name,fileSize:e.document.file_size}),t}async function Tu(e,n,s="telegram-image",i){if(i&&i>zu)throw new Error(`image is too large: ${i} bytes`);const r=await e.getFileLink(n),o=String(r),a=await(e.fetchFile||fetch)(o);if(!a.ok)throw new Error(`download failed with HTTP ${a.status}`);const d=Number(a.headers.get("content-length")||0);if(d>zu)throw new Error(`image is too large: ${d} bytes`);const c=t.extname(s)||".jpg";let l=c;try{l=t.extname(new URL(o).pathname)||c}catch{l=c}const p=t.join(f.tmpdir(),"task-handoff-images");await y.mkdir(p,{recursive:!0});const u=l.replace(/[^.\w-]/g,"")||".jpg",h=t.join(p,`telegram-${Date.now()}-${Math.random().toString(16).slice(2)}${u}`),m=Buffer.from(await a.arrayBuffer());if(m.length>zu)throw new Error(`image is too large: ${m.length} bytes`);return await y.writeFile(h,m),h}class Cu{store;constructor(e){this.store=new Au({updateIntervalMs:e.updateIntervalMs,send:(t,n,s)=>e.send(e.requireBridge(n?.bridgeId||""),n?.chatId||"",jp(t),{rawMarkdownV2:!0,replyMarkup:_u(s)}),edit:(t,n,s,i)=>e.edit(e.requireBridge(s?.bridgeId||""),s?.chatId||"",t,jp(n),{rawMarkdownV2:!0,replyMarkup:_u(i)}),delete:(t,n)=>e.deleteMessage(e.requireBridge(n?.bridgeId||""),n?.chatId||"",t),onLog:e.onLog})}get entries(){return this.store.entries}remember(e,t,n,s){return this.store.remember(e,t,n,s)}rekey(e,t){return this.store.rekey(e,t)}delete(e){return this.store.delete(e)}async applyUpdate(e){return this.store.applyUpdate(e.key,e.text,{bridgeId:e.bridge.id,chatId:e.chatId},{actionRows:e.actionRows})}}async function Eu(e){return(await async function(e,t,n,s){const i=[];for(const r of ku(n))try{const n=await Tu({getFileLink:n=>Lp(e,t,n),fetchFile:e},r.fileId,r.fileName,r.fileSize);i.push(n)}catch(e){s?.({fileId:r.fileId,fileName:r.fileName,error:e})}return i}(e.fetchImpl,e.bridge,e.message,e.onImageDownloadError)).map((e,i)=>{const r=n.readFileSync(e);return{id:`tg_${s.randomUUID().replace(/-/g,"").slice(0,24)}`,kind:"image",name:t.basename(e)||`telegram-image-${i+1}`,mime:xu(e),size:r.length,source:{type:"inline",encoding:"base64",data:r.toString("base64")}}})}function xu(e){const n=t.extname(e).toLowerCase();return".png"===n?"image/png":".webp"===n?"image/webp":".gif"===n?"image/gif":".bmp"===n?"image/bmp":"image/jpeg"}function Nu(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function Ru(e){return e&&"object"==typeof e?e:{}}function Ou(e){return"string"==typeof e?e:""}function _u(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Kl(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function Pu(e){const t=Array.isArray(e.item_list)?e.item_list:[];for(const e of t){const t=ju(e);if(1!==t.type)continue;const n=Du(ju(t.text_item).text).trim();if(n)return n}return""}function ju(e){return e&&"object"==typeof e?e:{}}function Du(e){return"string"==typeof e?e:""}function Mu(e){const{fetchImpl:t,bridge:n,dingdingRuntime:i,larkRuntime:r}=e;return"telegram"===n.channel?function(e,t){return{bridge:t,send:async(n,s,i={})=>{const r=await Mp(e,t,n,s,{replyMarkup:i.replyMarkup,replyToMessageId:i.replyToMessageId,rawMarkdownV2:i.rawMarkdownV2,parseMode:i.parseMode});return{provider:"telegram",raw:r,messageId:Number(Ru(r).message_id)||void 0}}}}(t,n):"dingding"===n.channel?function(e,t,n){return{bridge:t,send:async(s,i,r={})=>{const o=r.sessionWebhook||n?.chatWebhooks.get(s)||lu(t.settings.sessionWebhook);if(r.replyMarkup&&n){const a=await nu({fetchImpl:e,bridge:t,runtime:n,chatId:s,text:i,replyMarkup:r.replyMarkup,sessionWebhook:o,senderId:r.senderId||n.senderIds.get(s)||lu(t.settings.senderId)});if(a?.delivered)return{provider:"dingding",interactionId:a.outTrackId}}if(o)return await tu(e,o,i,n?.onLog),{provider:"dingding"}}}}(t,n,i):"lark"===n.channel?function(e,t){return{bridge:e,send:async(e,n,s={})=>{if(!t)return;const i=await t.channel.send(e,s.replyMarkup?{card:mu(n,s.replyMarkup)}:{markdown:n});return{provider:"lark",interactionId:i.messageId,raw:i}}}}(n,r):"wechat"===n.channel?function(e,t){return{bridge:t,send:async(n,i,r={})=>{const o=r.contextToken||Du(t.settings.contextToken);if(o)return await async function(e,t,n,i,r){const o=Du(t.settings.baseUrl)||"https://ilinkai.weixin.qq.com",a=await e(`${o}/ilink/bot/sendmessage`,{method:"POST",headers:{"content-type":"application/json",AuthorizationType:"ilink_bot_token",Authorization:`Bearer ${t.token}`,"X-WECHAT-UIN":String(Math.floor(Math.random()*2**31))},body:JSON.stringify({msg:{from_user_id:"",to_user_id:n,client_id:s.randomUUID(),message_type:2,message_state:2,context_token:i,item_list:[{type:1,text_item:{text:r}}]},base_info:{channel_version:"1.0.2"}})}),d=await a.json().catch(()=>({}));if(!a.ok||d.errcode)throw new Error(Du(d.errmsg)||`WeChat send failed with HTTP ${a.status}`)}(e,t,n,o,i),{provider:"wechat"}}}}(t,n):{bridge:n,send:async()=>{}}}class Lu{entries=new Map;fetchImpl;generations=new Map;constructor(e){this.fetchImpl=e}clear(){for(const e of new Set([...this.generations.keys(),...[...this.entries.values()].map(e=>e.bridgeId)]))this.clearBridge(e)}clearBridge(e){this.generations.set(e,this.generation(e)+1),this.clearEntries(t=>t.bridgeId===e)}generation(e){return this.generations.get(e)||0}isCurrent(e,t){return this.generation(e)===t}clearEntries(e){for(const[t,n]of this.entries)e(n)&&(n.timer&&clearTimeout(n.timer),n.cancelPending?.(new Error("DingDing progress update was cancelled.")),this.entries.delete(t))}async applyUpdate(e,t){const n=this.generation(e.bridge.id),s=uu(e.replyMarkup);let i=this.entries.get(e.key);if(i?.pending&&await i.pending,!this.isCurrent(e.bridge.id,n))return!1;if(i=this.entries.get(e.key),i?.outTrackId){if(i.lastText===e.text&&i.lastActionsFingerprint===s)return!0;const r=Date.now()-(i.lastUpdateAt||0);return r<1e3?(i.pendingText=e.text,i.pendingReplyMarkup=e.replyMarkup,i.timer||(i.pending=new Promise((s,o)=>{i.cancelPending=o,i.timer=setTimeout(()=>{i.timer=void 0,i.cancelPending=void 0;const r=i.pendingText,a=i.pendingReplyMarkup;if(i.pendingText=void 0,i.pendingReplyMarkup=void 0,!r)return s(void 0);this.updateExistingEntry(e,t,i,r,a,uu(a),n).then(s,o)},1e3-r)}).finally(()=>{i.pending=void 0,i.timer=void 0,i.cancelPending=void 0})),await i.pending,this.isCurrent(e.bridge.id,n)&&this.entries.has(e.key)):(await this.updateExistingEntry(e,t,i,e.text,e.replyMarkup,s,n),this.isCurrent(e.bridge.id,n))}const r={bridgeId:e.bridge.id,lastText:e.text,lastActionsFingerprint:s,lastUpdateAt:Date.now()};return r.pending=nu({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,chatId:e.chatId,text:e.text,replyMarkup:e.replyMarkup,sessionWebhook:t.chatWebhooks.get(e.chatId)||qu(e.bridge.settings.sessionWebhook),senderId:t.senderIds.get(e.chatId)||qu(e.bridge.settings.senderId),title:"TaskHandoff 执行中",step:"progress",forceCard:!0}).then(t=>{this.isCurrent(e.bridge.id,n)&&(t?.outTrackId&&(r.outTrackId=t.outTrackId),t?.delivered&&(r.delivered=!0,r.lastUpdateAt=Date.now()))}).catch(t=>{throw this.isCurrent(e.bridge.id,n)&&this.entries.delete(e.key),t}).finally(()=>{r.pending=void 0}),this.entries.set(e.key,r),await r.pending,this.isCurrent(e.bridge.id,n)&&Boolean(r.delivered)}async updateExistingEntry(e,t,n,s,i,r,o){n.outTrackId&&(await async function(e){await su(e.fetchImpl,e.bridge,e.runtime,"PUT","/v1.0/card/instances",{outTrackId:e.outTrackId,cardData:{cardParamMap:Gp({type:"actions",title:e.title,description:e.text,list:Ql(e.replyMarkup),biz_step:e.step,error_msg:""})},cardUpdateOptions:{updateCardDataByKey:!0,updatePrivateDataByKey:!1},userIdType:Number(e.bridge.settings.cardUserIdType||1)})}({fetchImpl:this.fetchImpl,bridge:e.bridge,runtime:t,outTrackId:n.outTrackId,text:s,replyMarkup:i,title:"TaskHandoff 执行中",step:"progress"}),this.isCurrent(e.bridge.id,o)&&(n.lastText=s,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function qu(e){return"string"==typeof e?e:""}function $u(e){const t=new I.DWClient({clientId:e.clientId,clientSecret:e.clientSecret,ua:"task-handoff-control-plane",keepAlive:!1,autoReconnect:!1});let n,s=!1;return{async connect(){s=!1,await t.getEndpoint(),await t._connect();const e=t.socket;e?.once("close",()=>{s||n?.(new Error("DingDing stream connection closed."))})},disconnect(){s=!0,t.disconnect()},onDisconnect(e){n=e},getConfig:()=>t.getConfig(),registerCallbackListener(e,n){t.registerCallbackListener(e,n)},socketCallBackResponse(e,n){t.socketCallBackResponse(e,n)}}}class Bu{runtimes=new Map;connected=new Set;reconnectTimers=new Map;progress;options;createClient;constructor(e){this.options=e,this.createClient=e.createClient||$u,this.progress=new Lu(e.fetchImpl)}has(e){return this.runtimes.has(e)}isRunning(e){return this.connected.has(e)}get(e){return this.runtimes.get(e)}ids(){return this.runtimes.keys()}start(e){const t=(n=e.settings?.clientSecret,"string"==typeof n?n:"");var n;if(!e.token||!t)return this.options.onError(e.id,"DingDing client id/secret is not configured."),!1;const s={client:this.createClient({clientId:e.token,clientSecret:t}),chatWebhooks:new Map,senderIds:new Map,conversationTypes:new Map,onLog:(t,n,s)=>{this.options.logger["warn"===t?"warn":"info"]({bridgeId:e.id,...n},s)}};return s.client.onDisconnect?.(t=>{this.runtimes.get(e.id)===s&&this.handleConnectionFailure(e,s,t)}),s.client.registerCallbackListener(I.TOPIC_ROBOT,t=>{this.options.onRobotMessage(e,s,t).catch(t=>{this.options.onError(e.id,t)})}),s.client.registerCallbackListener(I.TOPIC_CARD,t=>{const n=t;this.options.onCardCallback(e,s,n).then(e=>s.client.socketCallBackResponse(n.headers.messageId,e||{})).catch(t=>{this.options.onError(e.id,t),s.client.socketCallBackResponse(n.headers.messageId,{})})}),this.options.clearError(e.id),this.runtimes.set(e.id,s),this.connect(e,s),!0}connect(e,t){this.reconnectTimers.delete(e.id),this.connected.add(e.id),t.client.connect().then(()=>{this.runtimes.get(e.id)===t&&(this.connected.add(e.id),this.options.clearError(e.id))}).catch(n=>{this.runtimes.get(e.id)===t&&this.handleConnectionFailure(e,t,n)})}handleConnectionFailure(e,t,n){if(this.connected.delete(e.id),this.progress.clearBridge(e.id),this.options.onError(e.id,n||"DingDing stream connection failed."),this.reconnectTimers.has(e.id))return;const s=setTimeout(()=>{this.runtimes.get(e.id)===t&&this.connect(e,t)},this.options.reconnectDelayMs??1e3);s.unref?.(),this.reconnectTimers.set(e.id,s)}stop(e){const t=this.reconnectTimers.get(e);t&&clearTimeout(t),this.reconnectTimers.delete(e),this.connected.delete(e);const n=this.runtimes.get(e);if(n){try{n.client.disconnect()}catch{}this.runtimes.delete(e)}this.progress.clearBridge(e)}stopAll(){for(const e of[...this.runtimes.keys()])this.stop(e);this.progress.clear()}applyUpdate(e){const t=this.runtimes.get(e.bridge.id);return t?this.progress.applyUpdate(e,t):Promise.resolve(!1)}applyProgressUpdate(e){return this.applyUpdate(e)}}class Fu{entries=new Map;generations=new Map;updateIntervalMs;constructor(e=1e3){this.updateIntervalMs=e}clear(){for(const e of new Set([...this.generations.keys(),...[...this.entries.values()].map(e=>e.bridgeId)]))this.clearBridge(e)}clearBridge(e){this.generations.set(e,this.generation(e)+1);for(const[t,n]of this.entries)n.bridgeId===e&&(n.timer&&clearTimeout(n.timer),n.cancelPending?.(new Error("Lark progress update was cancelled.")),this.entries.delete(t))}generation(e){return this.generations.get(e)||0}isCurrent(e,t){return this.generation(e)===t}async applyUpdate(e,t){const n=this.generation(e.bridge.id),s=yu(e.replyMarkup);let i=this.entries.get(e.key);if(i?.pending&&await i.pending,!this.isCurrent(e.bridge.id,n))return!1;if(i=this.entries.get(e.key),i?.messageId){if(i.lastText===e.text&&i.lastActionsFingerprint===s)return!0;const r=Date.now()-i.lastUpdateAt;return r<this.updateIntervalMs?(i.pendingText=e.text,i.pendingReplyMarkup=e.replyMarkup,i.timer||(i.pending=new Promise((s,o)=>{i.cancelPending=o,i.timer=setTimeout(()=>{i.timer=void 0,i.cancelPending=void 0;const r=i.pendingText,a=i.pendingReplyMarkup;if(i.pendingText=void 0,i.pendingReplyMarkup=void 0,!r)return s(void 0);this.updateExistingEntry(e,t,i,r,a,yu(a),n).then(s,o)},this.updateIntervalMs-r)}).finally(()=>{i.pending=void 0,i.timer=void 0,i.cancelPending=void 0})),await i.pending,this.isCurrent(e.bridge.id,n)&&this.entries.has(e.key)):(await this.updateExistingEntry(e,t,i,e.text,e.replyMarkup,s,n),this.isCurrent(e.bridge.id,n))}const r={bridgeId:e.bridge.id,lastText:e.text,lastActionsFingerprint:s,lastUpdateAt:Date.now()};return r.pending=t.channel.send(e.chatId,{card:mu(e.text,e.replyMarkup)}).then(t=>{this.isCurrent(e.bridge.id,n)&&(r.messageId=t.messageId,r.delivered=!0,r.lastUpdateAt=Date.now())}).catch(t=>{throw this.isCurrent(e.bridge.id,n)&&this.entries.delete(e.key),t}).finally(()=>{r.pending=void 0}),this.entries.set(e.key,r),await r.pending,this.isCurrent(e.bridge.id,n)&&Boolean(r.delivered)}async updateExistingEntry(e,t,n,s,i,r,o){n.messageId&&(await t.channel.updateCard(n.messageId,mu(s,i)),this.isCurrent(e.bridge.id,o)&&(n.lastText=s,n.lastActionsFingerprint=r,n.lastUpdateAt=Date.now()))}}function Uu(e){const t={appId:e.appId,appSecret:e.appSecret,domain:e.domain,transport:"websocket",source:"task-handoff-control-plane",handshakeTimeoutMs:15e3,policy:{requireMention:!0,dmMode:"open",respondToMentionAll:!1}};return b.createLarkChannel(t)}class Hu{runtimes=new Map;connected=new Set;unsubscribe=new Map;reconnectTimers=new Map;options;createChannel;progress;constructor(e){this.options=e,this.createChannel=e.createChannel||Uu,this.progress=new Fu(e.progressUpdateIntervalMs)}has(e){return this.runtimes.has(e)}isRunning(e){return this.connected.has(e)}get(e){return this.runtimes.get(e)}ids(){return this.runtimes.keys()}start(e){const t=(n=e.settings?.appSecret,"string"==typeof n?n.trim():"");var n;if(!e.token||!t)return this.options.onError(e.id,"Lark app id/secret is not configured."),!1;const s={channel:this.createChannel({appId:e.token,appSecret:t,domain:Wu(e.settings?.domain)})},i=s.channel.on({message:t=>{this.options.onMessage(e,s,t).catch(t=>{this.options.onError(e.id,t)})},cardAction:t=>{this.options.onCardAction(e,s,t).catch(t=>{this.options.onError(e.id,t)})},error:t=>{this.options.onError(e.id,t),this.options.logger.warn({bridgeId:e.id,error:t.message},"lark channel error")},reconnecting:()=>{this.connected.delete(e.id),this.options.onError(e.id,"Lark WebSocket is reconnecting."),this.options.logger.info({bridgeId:e.id},"lark channel reconnecting")},reconnected:()=>{this.runtimes.get(e.id)===s&&(this.connected.add(e.id),this.options.clearError(e.id),this.options.logger.info({bridgeId:e.id},"lark channel reconnected"))}});return this.options.clearError(e.id),this.runtimes.set(e.id,s),this.unsubscribe.set(e.id,i),this.connect(e,s),!0}connect(e,t){this.reconnectTimers.delete(e.id),t.channel.connect().then(()=>{this.runtimes.get(e.id)===t&&(this.connected.add(e.id),this.options.clearError(e.id),this.options.logger.info({bridgeId:e.id},"lark channel connected"))}).catch(n=>{if(this.runtimes.get(e.id)!==t)return;if(this.connected.delete(e.id),this.options.onError(e.id,n),t.channel.rawWsClient||this.reconnectTimers.has(e.id))return;const s=setTimeout(()=>{this.runtimes.get(e.id)===t&&this.connect(e,t)},this.options.reconnectDelayMs??1e3);s.unref?.(),this.reconnectTimers.set(e.id,s)})}stop(e){const t=this.reconnectTimers.get(e);t&&clearTimeout(t),this.reconnectTimers.delete(e),this.unsubscribe.get(e)?.(),this.unsubscribe.delete(e),this.connected.delete(e);const n=this.runtimes.get(e);if(this.runtimes.delete(e),this.progress.clearBridge(e),n){try{n.channel.rawWsClient?.close({force:!0})}catch{}n.channel.disconnect().catch(()=>{})}}stopAll(){for(const e of[...this.runtimes.keys()])this.stop(e);this.progress.clear()}applyUpdate(e){const t=this.runtimes.get(e.bridge.id);return t?this.progress.applyUpdate(e,t):Promise.resolve(!1)}applyProgressUpdate(e){return this.applyUpdate(e)}}function Wu(e){return"lark"===String(e||"").trim().toLowerCase()?b.Domain.Lark:b.Domain.Feishu}class Gu{ttlMs;load;now;cached;pending;generation=0;constructor(e,t,n={}){this.ttlMs=e,this.load=t,this.now=n.now||Date.now}get(){if(this.cached&&this.cached.expiresAt>this.now())return Promise.resolve(this.cached.value);if(this.pending)return this.pending;const e=this.generation,t=this.load().then(t=>(this.generation===e&&(this.cached={expiresAt:this.now()+this.ttlMs,value:t}),t)).finally(()=>{this.pending===t&&(this.pending=void 0)});return this.pending=t,t}invalidate(){this.generation+=1,this.cached=void 0,this.pending=void 0}}class Vu{aggregates=new Map;endTokens=new Map;options;delayMs;constructor(e){this.options=e,this.delayMs=e.delayMs??1e3}async handleIncoming(e,t,n,s,i=[],r={},o={}){const a=s.trim(),d=a.split(/\s+/,1)[0]?.toLowerCase()||"",c=Ku(e.id,t,n),l=this.aggregates.get(c);return o.autoBegin&&!l?(this.start(c,e,t,n,r),this.enqueue(c,e,t,n,s,i,r,!0),void await this.sendCollectionStarted(e,t,c,r.sourceMessageId,"Image received. Continue sending messages, then send /end when done.")):"/begin"===d?(this.start(c,e,t,n,r),void await this.sendCollectionStarted(e,t,c,r.sourceMessageId,"Started collecting messages. Send /end when done.")):void("/end"!==d?l?.explicit?this.enqueue(c,e,t,n,s,i,r,!0):a.startsWith("/")?await this.options.dispatch(e,t,n,s,i,r):this.enqueue(c,e,t,n,s,i,r,!1):await this.flush(c,"manual"))}async handleEndCallback(e,t,n,s,i){const r=this.endTokens.get(s)||"";if(r!==Ku(e.id,t,i))return void await this.options.answerCallback(e,n,"This collection is not active here");const o=await this.flush(r,"callback");await this.options.answerCallback(e,n,o?"Collected message sent":"No messages collected")}stop(){for(const e of this.aggregates.values())e.timer&&clearTimeout(e.timer);this.aggregates.clear(),this.endTokens.clear()}stopBridge(e){for(const[t,n]of this.aggregates)n.bridgeId===e&&(n.timer&&clearTimeout(n.timer),this.aggregates.delete(t));for(const[t,n]of this.endTokens)n.startsWith(`${e}:`)&&this.endTokens.delete(t)}start(e,t,n,s,i){const r=this.aggregates.get(e);r?.timer&&clearTimeout(r.timer),this.aggregates.set(e,{bridgeId:t.id,chatId:n,userId:s,texts:[],attachments:[],context:i,explicit:!0})}enqueue(e,t,n,s,i,r,o,a){const d=this.aggregates.get(e);d?.timer&&clearTimeout(d.timer);const c=d||{bridgeId:t.id,chatId:n,userId:s,texts:[],attachments:[],context:o,explicit:a};var l,p;c.bridgeId=t.id,c.chatId=n,c.userId=s,c.context=(l=c.context,p=o,{sourceMessageId:l?.sourceMessageId??p.sourceMessageId,replyToMessageId:l?.replyToMessageId??p.replyToMessageId,quoteText:l?.quoteText||p.quoteText}),c.explicit=c.explicit||a,i.trim()&&c.texts.push(i),c.attachments.push(...r),c.timer=c.explicit?void 0:setTimeout(()=>{this.flush(e,"timer").catch(e=>this.options.onError?.(c.bridgeId,e))},this.delayMs),this.aggregates.set(e,c)}async flush(e,t){const n=this.aggregates.get(e);if(!n)return!1;n.timer&&clearTimeout(n.timer),this.aggregates.delete(e);const s=this.options.requireBridge(n.bridgeId),i=n.texts.join("\n\n").trim();return i||n.attachments.length?(await this.options.dispatch(s,n.chatId,n.userId,i,n.attachments,n.context||{}),!0):("timer"!==t&&await this.options.send(s,n.chatId,"No messages collected.",{replyToMessageId:n.context?.sourceMessageId}),!1)}sendCollectionStarted(e,t,n,s,i){return this.options.send(e,t,i,{replyToMessageId:s,replyMarkup:Kl([[{text:"/end",callbackData:this.endCallbackData(n)}]])})}endCallbackData(e){const t=s.createHash("sha256").update(e).digest("base64url").slice(0,16);return this.endTokens.set(t,e),`task_handoff:cp_msg_end:${t}`}}function Ku(e,t,n){return[e,t,n||""].join(":")}class Ju{cancelTokens=new Map;queueActionTokens=new Map;options;constructor(e){this.options=e}cancelCallbackData(e,t){this.pruneExpired();const n=Qu([e,t]);return this.cancelTokens.set(n,this.expiring({instanceId:e,sessionId:t})),`task_handoff:cp_ai_cancel:${n}`}queueSteerCallbackData(e,t,n){return`task_handoff:cp_ai_steer:${this.queueActionToken({type:"steer",instanceId:e,sessionId:t,queueId:n})}`}queueDeleteMenuCallbackData(e,t){return`task_handoff:cp_ai_qdel_menu:${this.queueActionToken({type:"delete-menu",instanceId:e,sessionId:t})}`}async tryHandle(e,t){this.pruneExpired();const n=Yu(e,"task_handoff:cp_ai_cancel:");if(void 0!==n){const e=this.cancelTokens.get(n)?.value;return e?(await this.cancel(t,e.instanceId,e.sessionId),!0):this.expired(t)}const s=Yu(e,"task_handoff:cp_ai_steer:");if(void 0!==s){const e=this.queueActionTokens.get(s)?.value;return e&&"steer"===e.type?(await this.steer(t,e),!0):this.expired(t)}const i=Yu(e,"task_handoff:cp_ai_qdel_menu:");if(void 0!==i){const e=this.queueActionTokens.get(i)?.value;return e&&"delete-menu"===e.type?(await this.deleteMenu(t,e),!0):this.expired(t)}const r=Yu(e,"task_handoff:cp_ai_qdel:");if(void 0!==r){const e=this.queueActionTokens.get(r)?.value;return e&&"delete-item"===e.type?(await this.deleteItem(t,e),!0):this.expired(t)}return!1}async cancel(e,t,n){await this.requireAllowed(e,t,n)&&await this.run(e,{instanceId:t,sessionId:n,successText:"Interrupt sent",failurePrefix:"Interrupt failed",logMessage:"chat ai session cancel sent",operation:()=>this.options.interrupt(t,n)})}async steer(e,t){await this.requireAllowed(e,t.instanceId,t.sessionId)&&await this.run(e,{...t,successText:"Steered queued message",failurePrefix:"Steer failed",logMessage:"chat ai session queued message steered",operation:()=>this.options.steer(t.instanceId,t.sessionId,t.queueId)})}async deleteMenu(e,t){if(await this.requireAllowed(e,t.instanceId,t.sessionId))try{const n=Zu(await this.options.queue(t.instanceId,t.sessionId)),s=(Array.isArray(n.items)?n.items:[]).map(Zu).filter(e=>"queued"===eh(e.status)&&eh(e.id));if(!s.length)return void await this.answer(e,"Queue is empty");const i=s.slice(0,5).map((e,n)=>[{text:Xu(eh(e.message),n),callbackData:this.queueDeleteItemCallbackData(t.instanceId,t.sessionId,eh(e.id))}]);await this.send(e,"Delete queued message",{replyMarkup:Kl(i)}),await this.answer(e,"Select a queued message"),this.options.info(this.logData(e,t,{itemCount:s.length}),"chat ai session queue delete menu sent")}catch(t){await this.fail(e,t,"Queue menu failed")}}async deleteItem(e,t){if(await this.requireAllowed(e,t.instanceId,t.sessionId))try{await this.options.remove(t.instanceId,t.sessionId,t.queueId),await this.answer(e,"Queued message deleted"),(e.deleteMessage||Number.isInteger(e.messageId))&&await this.deleteMessage(e).catch(n=>{this.options.warn(this.logData(e,t,{messageId:e.messageId,error:th(n)}),"chat ai session queue delete menu message delete failed")}),this.options.info(this.logData(e,t),"chat ai session queued message deleted")}catch(t){await this.fail(e,t,"Delete failed")}}async run(e,t){try{await t.operation(),await this.answer(e,t.successText),this.options.info(this.logData(e,t),t.logMessage)}catch(n){await this.fail(e,n,t.failurePrefix)}}async requireAllowed(e,t,n){return!!(e.actionAllowed?e.actionAllowed(t,n):this.options.actionAllowed(e.bridge,e.chatId,t,n,Number.isInteger(e.messageId)?e.messageId:void 0))||(await this.answer(e,"This chat is not bound to that AI session"),!1)}async fail(e,t,n){const s=th(t);this.options.setBridgeError(e.bridge.id,s),await this.answer(e,`${n}: ${function(e){const t=e.replace(/\s+/g," ").trim();return t.length<=120?t:`${t.slice(0,Math.max(0,119))}…`}(s)}`)}async expired(e){return await this.answer(e,"This AI session action expired"),!0}answer(e,t){return e.answer?e.answer(t):this.options.answer(e.bridge,e.callbackQueryId,t)}send(e,t,n){return e.send?e.send(t,n):this.options.send(e.bridge,e.chatId,t,n)}deleteMessage(e){return e.deleteMessage?e.deleteMessage():Number.isInteger(e.messageId)?this.options.deleteMessage(e.bridge,e.chatId,e.messageId):Promise.resolve(void 0)}queueDeleteItemCallbackData(e,t,n){return`task_handoff:cp_ai_qdel:${this.queueActionToken({type:"delete-item",instanceId:e,sessionId:t,queueId:n})}`}queueActionToken(e){this.pruneExpired();const t=Qu([e.type,e.instanceId,e.sessionId,"queueId"in e?e.queueId:""]);return this.queueActionTokens.set(t,this.expiring(e)),t}clear(){this.cancelTokens.clear(),this.queueActionTokens.clear()}expiring(e){return{value:e,expiresAt:(this.options.now||Date.now)()+(this.options.tokenTtlMs??864e5)}}pruneExpired(){const e=(this.options.now||Date.now)();for(const[t,n]of this.cancelTokens)n.expiresAt<=e&&this.cancelTokens.delete(t);for(const[t,n]of this.queueActionTokens)n.expiresAt<=e&&this.queueActionTokens.delete(t)}logData(e,t,n={}){return{bridgeId:e.bridge.id,chatId:e.chatId,instanceId:t.instanceId,sessionId:t.sessionId,...t.queueId?{queueId:t.queueId}:{},userId:e.userId,...n}}}function Yu(e,t){if(!e.startsWith(t))return;const n=e.slice(t.length);return n&&!n.includes(":")?n:void 0}function Qu(e){return s.createHash("sha256").update(e.join("\0")).digest("base64url").slice(0,16)}function Xu(e,t){const n=`${t+1}. `,s=eh(e).replace(/\s+/g," ").trim()||"Queued message",i=Math.max(8,48-n.length),r=Array.from(s);return`${n}${r.length>i?`${r.slice(0,Math.max(1,i-3)).join("")}...`:s}`}function Zu(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function eh(e){return"string"==typeof e?e.trim():""}function th(e){return e instanceof Error?e.message:String(e)}class nh{announced=new Set;options;constructor(e){this.options=e}async poll(){const e=await this.options.listRoutes().catch(()=>[]);for(const t of e){if(this.announced.has(t.id))continue;const e=sh(t,this.options.callbackData),n=t.aiSessionId?this.options.listBindings().filter(e=>e.activeInstanceId===t.instanceId&&e.activeAiSessionId===t.aiSessionId):[];(await this.sendToBindings(n,e)||await this.sendToDefaults(e))&&this.announced.add(t.id)}}async sendToBindings(e,t){let n=!1;for(const s of e){if(!s.bridgeId)continue;const e=this.options.requireBridge(s.bridgeId);if(!e.enabled)continue;const i=await this.send(e,s.chatSessionId,t);n||=i}return n}async sendToDefaults(e){let t=!1;for(const n of this.options.listBridges()){if(!n.enabled||!n.defaultChatId)continue;let s=!1;await this.options.send(n,n.defaultChatId,e).catch(e=>(this.options.setBridgeError(n.id,ih(e)),s=!0,!1))?t=!0:s||this.options.setBridgeError(n.id,"Chat bridge message was not delivered.")}return t}async send(e,t,n){return this.options.send(e,t,n).then(Boolean).catch(t=>(this.options.setBridgeError(e.id,ih(t)),!1))}}function sh(e,t){const n=`${e.project?.name||e.projectId} / ${e.instance?.name||e.instanceId}`,s="approval"===e.kind?`/approve ${e.id}\n/deny ${e.id}\n/skip ${e.id}`:`/reply ${e.id} <message>`,i=`[${n}]\n${e.result}\n\n${s}`;return"approval"!==e.kind?{text:i}:{text:i,replyMarkup:Kl([[{text:"Allow",callbackData:t(e.id,"allow")},{text:"Skip",callbackData:t(e.id,"skip")},{text:"Deny",callbackData:t(e.id,"deny")}]])}}function ih(e){return e instanceof Error?e.message:String(e)}function rh(){return e=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(e||"").trim().toLowerCase());var e}class oh{service;fetchImpl;logger;diagnosticLogsEnabled;bridgeTimers=new Map;bridgePollingGenerations=new Map;bridgePolls=new Map;dingdingBridges;larkBridges;bridgeErrors=new Map;telegramOffsets=new Map;seenTelegramUpdates=new Set;wechatCursors=new Map;pendingRouteNotifier;deliveredAiSessionFingerprints=new Map;telegramAiSessionCallbacks;telegramMessageAggregator;telegramProgressMessageTargets=new Map;aiSessionInstanceNamesCache;aiSessionPendingRoutesCache;telegramProgress;stopAiSessionListener;constructor(e,t=fetch,n={}){this.service=e,this.fetchImpl=t,this.logger=n.logger,this.diagnosticLogsEnabled=n.diagnosticLogsEnabled||rh,this.aiSessionInstanceNamesCache=new Gu(3e4,async()=>{const e=await(this.service.listAiSessionInstanceNames?.()||this.service.boardAsync()).catch(()=>[]);return new Map(e.map(e=>[e.id,e.name||e.id]))}),this.aiSessionPendingRoutesCache=new Gu(1e3,()=>this.service.listPendingRoutes().catch(()=>[])),this.telegramMessageAggregator=new Vu({requireBridge:e=>this.service.requireChatBridge(e),send:(e,t,n,s={})=>this.sendTelegramMessage(e,t,n,s),answerCallback:(e,t,n)=>this.answerTelegramCallback(e,t,n),dispatch:(e,t,n,s,i,r)=>this.dispatchTelegramGatewayMessage(e,t,n,s,i,r),onError:(e,t)=>this.bridgeErrors.set(e,gh(t))}),this.telegramAiSessionCallbacks=new Ju({interrupt:(e,t)=>this.service.interruptAiSession(e,t),queue:(e,t)=>this.service.aiSessionQueue(e,t),steer:(e,t,n)=>this.service.steerAiSessionQueuedMessage(e,t,n),remove:(e,t,n)=>this.service.removeAiSessionQueuedMessage(e,t,n),actionAllowed:(e,t,n,s,i)=>this.telegramAiSessionActionAllowed(e,t,n,s,i),answer:(e,t,n)=>this.answerTelegramCallback(e,t,n),send:(e,t,n,s={})=>this.sendTelegramMessage(e,t,n,s),deleteMessage:(e,t,n)=>this.deleteTelegramMessage(e,t,n),setBridgeError:(e,t)=>this.bridgeErrors.set(e,t),info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)}),this.pendingRouteNotifier=new nh({listRoutes:()=>this.service.listPendingRoutes(),listBindings:()=>this.service.listChatSessions(),listBridges:()=>this.service.listChatBridges(),requireBridge:e=>this.service.requireChatBridge(e),callbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),send:(e,t,n)=>this.sendViaBridge(e,t,n),setBridgeError:(e,t)=>this.bridgeErrors.set(e,t)}),this.telegramProgress=new Cu({updateIntervalMs:n.telegramProgressUpdateIntervalMs,requireBridge:e=>this.service.requireChatBridge(e),send:(e,t,n,s={})=>this.sendTelegramMessage(e,t,n,s),edit:(e,t,n,s,i={})=>this.editTelegramMessage(e,t,n,s,i),deleteMessage:(e,t,n)=>this.deleteTelegramMessage(e,t,n),onLog:e=>this.logWarn({message:e},"telegram progress store warning")}),this.dingdingBridges=new Bu({fetchImpl:this.fetchImpl,createClient:n.createDingdingClient,logger:{info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)},onRobotMessage:(e,t,n)=>this.handleDingdingRobotMessage(e,t,n),onCardCallback:(e,t,n)=>this.handleDingdingCardCallback(e,t,n),onError:(e,t)=>this.bridgeErrors.set(e,gh(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.larkBridges=new Hu({createChannel:n.createLarkChannel,progressUpdateIntervalMs:n.larkProgressUpdateIntervalMs,logger:{info:(e,t)=>this.logInfo(e,t),warn:(e,t)=>this.logWarn(e,t)},onMessage:(e,t,n)=>this.handleLarkMessage(e,t,n),onCardAction:(e,t,n)=>this.handleLarkCardAction(e,t,n),onError:(e,t)=>this.bridgeErrors.set(e,gh(t)),clearError:e=>this.bridgeErrors.delete(e)}),this.stopAiSessionListener=n.aiSessions?.onSnapshot(e=>{this.deliverAiSessionSnapshot(e.instanceId,e.aiSessions).catch(t=>{this.logWarn({instanceId:e.instanceId,snapshotRevision:e.revision,error:gh(t)},"chat ai session snapshot delivery failed")})})}logInfo(e,t){this.diagnosticLogsEnabled()&&this.logger?.info?.({component:"control-plane-chat-gateway",...e},t)}logWarn(e,t){this.diagnosticLogsEnabled()&&this.logger?.warn?.({component:"control-plane-chat-gateway",...e},t)}updateChatBridge(e,t){this.service.updateChatBridge?.(e,t)}startEnabled(){this.logAiSessionDelivery({stage:"runtime-start-enabled",bridgeCount:this.service.listChatBridges().length,enabledBridgeCount:this.service.listChatBridges().filter(e=>e.enabled).length});for(const e of this.service.listChatBridges())e.enabled&&this.startBridge(e.id)}startBridge(e){if(this.bridgeTimers.has(e)||this.dingdingBridges.has(e)||this.larkBridges.has(e))return this.logAiSessionDelivery({stage:"bridge-start-skipped-running",bridgeId:e}),this.status();const t=this.service.requireChatBridge(e);return this.logAiSessionDelivery({stage:"bridge-start",bridgeId:t.id,channel:t.channel,enabled:t.enabled,hasToken:Boolean(t.token)}),"wechat"===t.channel?this.startPollingBridge(t,(e,t)=>this.pollWechat(e,t)):"dingding"===t.channel?this.startDingdingBridge(t):"lark"===t.channel?this.startLarkBridge(t):"telegram"!==t.channel?(this.bridgeErrors.set(e,`${t.channel} bridge is not supported in the control plane.`),this.status()):t.token?this.startPollingBridge(t,(e,t)=>this.pollTelegram(e,t)):(this.bridgeErrors.set(e,"Telegram token is not configured."),this.status())}stopBridge(e){this.advanceBridgePollingGeneration(e);const t=`:${e}:`;for(const e of this.deliveredAiSessionFingerprints.keys())e.includes(t)&&this.deliveredAiSessionFingerprints.delete(e);const n=this.bridgeTimers.get(e);return n&&(clearInterval(n),this.bridgeTimers.delete(e)),this.dingdingBridges.stop(e),this.larkBridges.stop(e),this.telegramMessageAggregator.stopBridge(e),this.status()}stopAll(){const e=new Set([...this.service.listChatBridges().map(e=>e.id),...this.bridgePollingGenerations.keys(),...this.bridgeTimers.keys(),...this.bridgePolls.keys(),...this.dingdingBridges.ids(),...this.larkBridges.ids()]);for(const t of e)this.stopBridge(t);this.dingdingBridges.stopAll(),this.larkBridges.stopAll(),this.telegramMessageAggregator.stop(),this.telegramAiSessionCallbacks.clear(),this.stopAiSessionListener?.(),this.stopAiSessionListener=void 0}async pollBridgeNow(e){const t=this.service.requireChatBridge(e),n=this.bridgePollingGeneration(e);return"telegram"===t.channel?(await this.runBridgePoll(t,n,(e,t)=>this.pollTelegram(e,t)),this.status()):"wechat"===t.channel?(await this.runBridgePoll(t,n,(e,t)=>this.pollWechat(e,t)),this.status()):("dingding"===t.channel||"lark"===t.channel||this.bridgeErrors.set(e,`${t.channel} bridge is not supported in the control plane.`),this.status())}async pollAiSessionsNow(){return await this.pollAiSessionUpdates(),this.status()}status(){const e=this.service.listChatBridges().map(e=>({id:e.id,channel:e.channel,name:e.name,running:this.bridgeTimers.has(e.id)||this.dingdingBridges.isRunning(e.id)||this.larkBridges.isRunning(e.id),tokenSet:Boolean(e.tokenSet),defaultChatId:e.defaultChatId,lastUpdateId:this.telegramOffsets.get(e.id),error:this.bridgeErrors.get(e.id)}));return{running:e.some(e=>e.running),bridges:e}}startPollingBridge(e,t){if(!e.token)return this.bridgeErrors.set(e.id,`${e.channel} token is not configured.`),this.status();this.bridgeErrors.delete(e.id);const n=this.advanceBridgePollingGeneration(e.id),s=()=>this.bridgePollingGeneration(e.id)===n,i=i=>{s()&&this.runBridgePoll(i,n,t).catch(t=>{s()&&this.bridgeErrors.set(e.id,t instanceof Error?t.message:String(t))})},r=setInterval(()=>{if(!s())return;const t=this.service.requireChatBridge(e.id);t.enabled?i(t):this.stopBridge(e.id)},e.pollIntervalMs);if(this.bridgeTimers.set(e.id,r),this.logAiSessionDelivery({stage:"bridge-poll-started",bridgeId:e.id,channel:e.channel,intervalMs:e.pollIntervalMs}),e.enabled){const t=this.service.requireChatBridge(e.id);i(t)}return this.status()}runBridgePoll(e,t,n){const s=this.bridgePolls.get(e.id);if(s?.generation===t)return s.promise;const i=(async()=>{const s=()=>this.bridgePollingGeneration(e.id)===t;s()&&await n(e,s)})();this.bridgePolls.set(e.id,{generation:t,promise:i});const r=()=>{this.bridgePolls.get(e.id)?.promise===i&&this.bridgePolls.delete(e.id)};return i.then(r,r),i}bridgePollingGeneration(e){return this.bridgePollingGenerations.get(e)||0}advanceBridgePollingGeneration(e){const t=this.bridgePollingGeneration(e)+1;return this.bridgePollingGenerations.set(e,t),t}startDingdingBridge(e){return this.dingdingBridges.start(e),this.status()}startLarkBridge(e){return this.larkBridges.start(e),this.status()}async handleLarkMessage(e,t,n){const s=this.bindOrAllowChatUser(e,n.senderId),i=String(n.content||"").trim();if(!s||!i)return void this.logWarn({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,allowed:s,hasText:Boolean(i)},"lark message ignored");let r;e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:n.chatId}),this.logInfo({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,chatType:n.chatType,messageId:n.messageId,textPreview:fh(i)},"lark chat gateway message received");try{r=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"lark",bridgeId:e.id,chatSessionId:n.chatId,userId:n.senderId},message:{text:i,attachments:[]}})}catch(e){return void await t.channel.send(n.chatId,{markdown:`Failed to handle message: ${gh(e)}`})}const o=ah(r);if(!o)return;const a=ch(r);if(await this.sendLarkRoutedAiSessionProgress(r,e,n.chatId,o,a))return;const d=Mu({fetchImpl:this.fetchImpl,bridge:e,larkRuntime:t}),c=await d.send(n.chatId,o,{replyMarkup:a});c&&this.logInfo({bridgeId:e.id,chatId:n.chatId,senderId:n.senderId,provider:c.provider,interactionId:c.interactionId,routed:!0===vh(r).routed,replyPreview:fh(o)},"lark chat gateway reply sent")}async sendLarkRoutedAiSessionProgress(e,t,n,s,i){if(!0!==e.routed)return!1;const r=Ah(e),{instanceId:o,sessionId:a,turnId:d}=r;if(!o||!a||!d)return this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,routed:e.routed},"lark ai session progress message not started"),!1;const c=xh(o,a,d,t.id,n);return!!await this.larkBridges.applyProgressUpdate({bridge:t,key:c,chatId:n,text:s,replyMarkup:i})&&(this.deliveredAiSessionFingerprints.delete(c),this.logInfo({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,key:c,textPreview:fh(s)},"lark ai session progress message started"),!0)}async handleLarkCardAction(e,t,n){const s=n.operator.openId||n.operator.userId;if(!this.bindOrAllowChatUser(e,s))return void this.logWarn({bridgeId:e.id,chatId:n.chatId,messageId:n.messageId,userId:s},"lark card action ignored");const i=gu(n.action.value),r=(e,s)=>t.channel.updateCard(n.messageId,mu(e||"Updated",s));if(!i)return void await r("Unsupported action");if(await this.telegramAiSessionCallbacks.tryHandle(i,{bridge:e,chatId:n.chatId,callbackQueryId:n.messageId,userId:s,messageId:n.messageId,actionAllowed:(t,s)=>this.chatAiSessionBindingActive(e,n.chatId,t,s),answer:e=>r(e),send:(e,s)=>t.channel.send(n.chatId,{card:mu(e,s?.replyMarkup)})}))return;let o;try{o=await this.parseChatGatewayCallbackAction(i)}catch(e){if(yh(e,"CHAT_PENDING_ACTION_STALE"))return void await r(gh(e));throw e}if(!o)return void await r("Unsupported action");const a=await this.service.handleChatGatewayAction({source:{channel:"lark",bridgeId:e.id,chatSessionId:n.chatId,userId:s},action:o});if("pending-decision"===o.type&&dh(a))return void await r(`${o.decision} sent`);const d=ah(a)||mh(a.message)||"Updated";await r(d,ch(a))}async handleDingdingRobotMessage(e,t,n){const s=function(e){const t=pu(e),n=lu(t.conversationId),s=lu(du(t.text).content).trim();if(!n||!s)return;const i=lu(t.senderStaffId||t.senderId);return{chatId:n,userId:i||void 0,senderId:i||void 0,sessionWebhook:lu(t.sessionWebhook)||void 0,conversationType:Yp(t.conversationType,{robotMessage:!0}),text:s,raw:t}}(n.data);if(t.client.socketCallBackResponse(n.headers.messageId,{}),!s||!this.bindOrAllowChatUser(e,s.senderId))return void this.logWarn({bridgeId:e.id,hasEvent:Boolean(s),senderId:s?.senderId,allowed:s?this.bindOrAllowChatUser(e,s.senderId):void 0},"dingding robot message ignored");const{chatId:i,text:r,senderId:o,sessionWebhook:a}=s;a&&t.chatWebhooks.set(i,a),s.conversationType&&t.conversationTypes.set(i,s.conversationType);const d=a||t.chatWebhooks.get(i)||mh(e.settings.sessionWebhook);let c;o&&t.senderIds.set(i,o),e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:i}),this.logInfo({bridgeId:e.id,chatId:i,senderId:o,conversationType:s.conversationType,hasSessionWebhook:Boolean(a),hasCachedSessionWebhook:Boolean(t.chatWebhooks.get(i)),hasResolvedSessionWebhook:Boolean(d),textPreview:fh(r)},"dingding chat gateway message received");try{c=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"dingding",bridgeId:e.id,chatSessionId:i,userId:o||void 0},message:{text:r,attachments:[]}})}catch(e){if(d)return void await tu(this.fetchImpl,d,`Failed to handle message: ${gh(e)}`,t.onLog);throw e}const l=ah(c);if(l){const n=ch(c);if(await this.sendDingdingRoutedAiSessionProgress(c,e,t,i,l,{replyMarkup:n,sessionWebhook:d,senderId:o,sourcePrompt:r}))return;const s=Mu({fetchImpl:this.fetchImpl,bridge:e,dingdingRuntime:t}),a=await s.send(i,l,{replyMarkup:n,sessionWebhook:d,senderId:o});if(a)return void this.logInfo({bridgeId:e.id,chatId:i,senderId:o,provider:a.provider,interactionId:a.interactionId,routed:!0===vh(c).routed,hasReplyMarkup:Boolean(n),replyPreview:fh(l)},"dingding chat gateway reply sent");this.logWarn({bridgeId:e.id,chatId:i,senderId:o,hasReplyMarkup:Boolean(n),hasSessionWebhook:Boolean(d),hasRobotCode:Boolean(mh(e.settings.robotCode)),replyPreview:fh(l)},"dingding chat gateway reply skipped")}}async sendDingdingRoutedAiSessionProgress(e,t,n,s,i,r={}){if(!0!==e.routed)return!1;const o=Ah(e),{instanceId:a,sessionId:d,turnId:c}=o;if(!a||!d||!c)return this.logWarn({bridgeId:t.id,chatId:s,instanceId:a,sessionId:d,turnId:c,turnIdSources:o.sources,routed:e.routed},"dingding ai session progress card not started"),!1;const l=xh(a,d,c,t.id,s);return!!await this.dingdingBridges.applyProgressUpdate({bridge:t,key:l,chatId:s,text:i,replyMarkup:r.replyMarkup})&&(this.deliveredAiSessionFingerprints.delete(l),this.logInfo({bridgeId:t.id,chatId:s,instanceId:a,sessionId:d,turnId:c,key:l,hasSessionWebhook:Boolean(r.sessionWebhook),hasSenderId:Boolean(r.senderId),sourcePrompt:fh(r.sourcePrompt,80),textPreview:fh(i)},"dingding ai session progress card started"),!0)}async handleDingdingCardCallback(e,t,n){const s=function(e){const t=pu(e),n=cu(t.cardActionData||t.content),s=cu(n.cardPrivateData||t.cardPrivateData||t.content),i=cu(s.params||n.params||t.params),r=lu(t.userId),o=lu(i.biz_sender_id);return{userId:r||void 0,chatId:Jp(t,i),senderId:r||void 0,deliverySenderId:o||void 0,sessionWebhook:lu(i.biz_session_webhook)||void 0,conversationType:Yp(i.biz_conversation_type||t.conversationType||t.conversation_type),callbackData:Qp(Zp(t,n,s)),body:t,params:i}}(n.data);if(!this.bindOrAllowChatUser(e,s.userId))return Xp("not authorized",void 0,"unauthorized",s.body,s.params);const i=s.chatId||mh(e.defaultChatId),r=s.deliverySenderId||s.senderId,o=s.sessionWebhook;let a;i&&o&&t.chatWebhooks.set(i,o),i&&s.conversationType&&t.conversationTypes.set(i,s.conversationType),i&&r&&t.senderIds.set(i,r);try{a=await this.parseChatGatewayCallbackAction(s.callbackData)}catch(e){if(yh(e,"CHAT_PENDING_ACTION_STALE"))return Xp(gh(e),void 0,"approval_stale",s.body,s.params);throw e}if(!a)return this.logWarn({bridgeId:e.id,chatId:i,userId:s.userId,senderId:r,...Ih(s)},"dingding card callback action unsupported"),Xp("Unsupported action",void 0,"unsupported",s.body,s.params);this.logInfo({bridgeId:e.id,chatId:i,userId:s.userId,senderId:r,actionType:a.type,...Ih(s)},"dingding card callback action parsed");const d=await this.service.handleChatGatewayAction({source:{channel:"dingding",bridgeId:e.id,chatSessionId:i,userId:s.userId||void 0},action:a});return"pending-decision"===a.type&&dh(d)?Xp(`${a.decision} sent`,void 0,"approval_done",s.body,s.params):Xp(ah(d)||mh(d.message)||"updated",ch(d),"updated",s.body,s.params)}async pollWechat(e,t=()=>!0){if(!e.token)return;const n=e.settings||{},s=this.wechatCursors.get(e.id)||mh(n.updatesBuf),i=await async function(e){const t=Du((e.bridge.settings||{}).baseUrl)||"https://ilinkai.weixin.qq.com",n=await e.fetchImpl(`${t}/ilink/bot/getupdates`,{method:"POST",headers:{"content-type":"application/json",AuthorizationType:"ilink_bot_token",Authorization:`Bearer ${e.bridge.token}`,"X-WECHAT-UIN":String(Math.floor(Math.random()*2**31))},body:JSON.stringify({get_updates_buf:e.cursor,base_info:{channel_version:"1.0.2"}})}),s=await n.json().catch(()=>({}));if(!n.ok)throw new Error(`HTTP ${n.status}`);const i=Number(s.errcode??s.ret??0);if(0!==i)throw new Error(Du(s.errmsg||s.msg)||`chat bridge API returned ${i}`);const r=[];for(const e of Array.isArray(s.msgs)?s.msgs:[]){const t=ju(e);if(1!==t.message_type)continue;const n=Du(t.from_user_id),s=Pu(t);n&&s&&r.push({chatId:n,text:s,contextToken:Du(t.context_token)})}return{cursor:Du(s.get_updates_buf),messages:r}}({fetchImpl:this.fetchImpl,bridge:e,cursor:s});if(t()){i.cursor&&(this.wechatCursors.set(e.id,i.cursor),this.updateChatBridge(e.id,{settings:{updatesBuf:i.cursor}}));for(const s of i.messages){if(!t())return;const{chatId:i,contextToken:r,text:o}=s;if(e.defaultChatId||this.updateChatBridge(e.id,{defaultChatId:i,settings:{contextToken:r}}),e.defaultChatId&&e.defaultChatId!==i)continue;const a=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"wechat",bridgeId:e.id,chatSessionId:i},message:{text:o,attachments:[]}});if(!t())return;const d=ah(a);if(d){const t=Mu({fetchImpl:this.fetchImpl,bridge:e});await t.send(i,d,{contextToken:r||mh(n.contextToken)})}}}}pollPendingRoutes(){return this.pendingRouteNotifier.poll()}async sendToChatBinding(e,t){if(!e.bridgeId)return!1;const n=this.service.requireChatBridge(e.bridgeId);if(!n.enabled)return!1;const s=await this.sendViaBridge(n,e.chatSessionId,t).catch(e=>{this.bridgeErrors.set(n.id,e instanceof Error?e.message:String(e))});return Boolean(s)}async sendViaBridge(e,t,n){const s="string"==typeof n?n:n.text,i="string"==typeof n?void 0:n.replyMarkup;return Mu({fetchImpl:this.fetchImpl,bridge:e,dingdingRuntime:this.dingdingBridges.get(e.id),larkRuntime:this.larkBridges.get(e.id)}).send(t,s,{replyMarkup:i})}async pollTelegram(e,t=()=>!0){if(!e.token)return;const n=Number(e.settings?.telegramLastUpdateId),s=this.telegramOffsets.get(e.id)||(Number.isInteger(n)?n:void 0),i=await async function(e){const t=new URLSearchParams({timeout:"0",...e.offset?{offset:String(e.offset+1)}:{}}),n=await e.fetchImpl(`https://api.telegram.org/bot${e.bridge.token}/getUpdates?${t.toString()}`),s=await n.json().catch(()=>({}));if(!n.ok||!1===s.ok){if(409===n.status||/terminated by other getUpdates request/i.test(String(s.description||"")))return{updates:[],conflict:s.description||"Telegram getUpdates conflict: another bot instance is polling this token."};throw new Error(s.description||`Telegram getUpdates failed with HTTP ${n.status}`)}const i=[];for(const t of s.result||[]){const n=Number(t.update_id),s=Number.isInteger(n)?n:void 0,r=Ru(t.callback_query);if(Object.keys(r).length>0){i.push({updateId:s,callbackQuery:r});continue}const o=Ru(t.message||t.edited_message);if(0===Object.keys(o).length)continue;const a=Ru(o.chat),d=Ru(o.from),c=void 0!==a.id?String(a.id):e.bridge.defaultChatId,l=void 0!==d.id?String(d.id):void 0;if(!c)continue;const p=Ou(o.text??o.caption),u=ku(o);(p||0!==u.length)&&i.push({updateId:s,chatId:c,userId:l,text:p,rawText:p,message:o,messageId:Nu(o),replyToMessageId:Nu(Ru(o.reply_to_message)),quoteText:Ou(Ru(o.quote).text),autoBegin:1===u.length&&!p.trim(),hasSingleImageWithoutText:1===u.length&&!p.trim()})}return{updates:i}}({fetchImpl:this.fetchImpl,bridge:e,offset:s});if(t())if(i.conflict)this.bridgeErrors.set(e.id,i.conflict);else for(const n of i.updates){if(!t())return;if(void 0!==n.updateId){const t=`${e.id}:${n.updateId}`;if(this.seenTelegramUpdates.has(t)||n.updateId<=(this.telegramOffsets.get(e.id)||0))continue;this.seenTelegramUpdates.add(t),this.telegramOffsets.set(e.id,n.updateId),this.updateChatBridge(e.id,{settings:{...e.settings,telegramLastUpdateId:n.updateId}})}if("callbackQuery"in n){const t=n.callbackQuery;await this.handleTelegramCallback(e,t).catch(async n=>{const s=vh(t.message),i=vh(s.chat),r=void 0!==i.id?String(i.id):e.defaultChatId;this.bridgeErrors.set(e.id,gh(n)),r&&await this.sendTelegramMessage(e,r,`Action failed: ${gh(n)}`).catch(t=>{this.bridgeErrors.set(e.id,gh(t))})});continue}if(!this.bindOrAllowChatUser(e,n.userId))continue;const s=await Eu({fetchImpl:this.fetchImpl,bridge:e,message:n.message,onImageDownloadError:({fileId:t,fileName:n,error:s})=>{this.logWarn({bridgeId:e.id,fileId:t,fileName:n,error:gh(s)},"telegram image download skipped")}});if(!t())return;const i=n.rawText.trim();(i||s.length)&&(this.logInfo({bridgeId:e.id,chatId:n.chatId,messageId:n.messageId,replyToMessageId:n.replyToMessageId,hasQuote:Boolean(n.quoteText),textPreview:fh(i)},"telegram chat gateway message received"),await this.telegramMessageAggregator.handleIncoming(e,n.chatId,n.userId,i,s,{sourceMessageId:n.messageId,replyToMessageId:n.replyToMessageId,quoteText:n.quoteText},{autoBegin:n.autoBegin}))}}async dispatchTelegramGatewayMessage(e,t,n,s,i=[],r={}){try{const o=void 0!==r.replyToMessageId?this.telegramReplyAiSessionTarget(e.id,t,r.replyToMessageId):void 0,a=function(e,t){const n=String(t||"").trim(),s=e.trim();return n?[`引用:${n}`,s].filter(Boolean).join("\n"):s}(s,r.quoteText),d=await this.service.handleChatGatewayMessage({source:{type:"chat-gateway",channel:"telegram",bridgeId:e.id,chatSessionId:t,userId:n},message:{text:a,attachments:i},...o?{target:{instanceId:o.instanceId,aiSessionId:o.sessionId}}:{}}),c=ah(d),l=ch(d);if(c){const n=await this.sendTelegramMessage(e,t,c,{replyMarkup:l,replyToMessageId:r.sourceMessageId});this.logInfo({bridgeId:e.id,chatId:t,sourceMessageId:r.sourceMessageId,replyToMessageId:r.replyToMessageId,replyTargetInstanceId:o?.instanceId,replyTargetSessionId:o?.sessionId,sentMessageId:Number(vh(n).message_id)||void 0,routed:!0===vh(d).routed,replyPreview:fh(c)},"telegram chat gateway reply sent"),await this.rememberTelegramProgressMessage(d,e,t,n,c)}}catch(n){this.bridgeErrors.set(e.id,gh(n)),await this.sendTelegramMessage(e,t,`Failed to handle message: ${gh(n)}`,{replyToMessageId:r.sourceMessageId}).catch(t=>{this.bridgeErrors.set(e.id,gh(t))})}}async handleTelegramCallback(e,t){const n=mh(t.data),s=vh(t.from),i=vh(t.message),r=vh(i.chat),o=void 0!==r.id?String(r.id):e.defaultChatId,a=void 0!==s.id?String(s.id):void 0;if(!o||!this.bindOrAllowChatUser(e,a))return;if(await this.telegramAiSessionCallbacks.tryHandle(n,{bridge:e,chatId:o,callbackQueryId:mh(t.id),userId:a,messageId:ph(i)}))return;const d=n.match(/^task_handoff:cp_msg_end:([^:]+)$/);if(d)return void await this.telegramMessageAggregator.handleEndCallback(e,o,mh(t.id),d[1],a);let c;try{c=await this.parseChatGatewayCallbackAction(n)}catch(n){if(yh(n,"CHAT_PENDING_ACTION_STALE")){await this.answerTelegramCallback(e,mh(t.id),gh(n));const s=ph(i);return void(void 0!==s&&await this.deleteTelegramStandaloneApprovalMessage(e,o,s))}throw n}if(!c)return void await this.answerTelegramCallback(e,mh(t.id),"Unsupported action");const l=await this.service.handleChatGatewayAction({source:{channel:"telegram",bridgeId:e.id,chatSessionId:o,userId:a},action:c});if("pending-decision"===c.type&&dh(l)){await this.answerTelegramCallback(e,mh(t.id),"");const n=ph(i);return void(void 0!==n&&await this.deleteTelegramStandaloneApprovalMessage(e,o,n))}await this.answerTelegramCallback(e,mh(t.id),mh(l.message)||"updated");const p=ah(l),u=ch(l),h=i.message_id;p&&"number"==typeof h?await this.editTelegramMessage(e,o,h,p,{replyMarkup:u}):p&&await this.sendTelegramMessage(e,o,p,{replyMarkup:u})}async deleteTelegramStandaloneApprovalMessage(e,t,n){[...this.telegramProgress.entries.values()].find(s=>s.messageId===n&&s.route?.bridgeId===e.id&&s.route?.chatId===t)||await this.deleteTelegramMessage(e,t,n).catch(s=>{this.logWarn({bridgeId:e.id,chatId:t,messageId:n,error:gh(s)},"telegram callback message delete failed")})}chatAiSessionBindingActive(e,t,n,s){return this.service.listChatSessions().some(i=>i.bridgeId===e.id&&i.chatSessionId===t&&i.activeInstanceId===n&&i.activeAiSessionId===s)}telegramAiSessionActionAllowed(e,t,n,s,i){if(this.chatAiSessionBindingActive(e,t,n,s))return!0;if(!Number.isInteger(i))return!1;const r=this.telegramReplyAiSessionTarget(e.id,t,i);return Boolean(r&&r.instanceId===n&&r.sessionId===s)}async parseChatGatewayCallbackAction(e){const t=function(e){const t=e.match(/^task_handoff:cp_p:v1:([ads]):([A-Za-z0-9_-]{16})$/);if(!t)return;const n=Object.entries($l).find(([,e])=>e===t[1])?.[0];return"allow"===n||"deny"===n||"skip"===n?{routeFingerprint:t[2],decision:n}:void 0}(e);if(t){const e=(await this.service.listPendingRoutes()).filter(e=>"approval"===e.kind&&"pending"===e.status&&Bl(e.id)===t.routeFingerprint);if(1!==e.length){const e=new Error("This approval is no longer pending.");throw Object.assign(e,{statusCode:409,code:"CHAT_PENDING_ACTION_STALE"}),e}return{type:"pending-decision",routeId:e[0].id,decision:t.decision}}return function(e,t){const n=e.match(/^task_handoff:cp_session:(\d+)$/);if(n)return{type:"ai-session",index:Number(n[1])};const s=e.match(/^task_handoff:cp_i:([^:]+)$/)||e.match(/^task_handoff:cp_instance_apps:([^:]+)$/);if(s)return s[0].startsWith("task_handoff:cp_i:")?{type:"instance-app-menu",instanceId:Bp(t(s[1],"instance-app-menu").instanceId,"instanceId")}:{type:"instance-app-menu",instanceId:Hp(s[1])};const i=e.match(/^task_handoff:cp_a:([^:]+)$/)||e.match(/^task_handoff:cp_launch_app:([^:]+):([^:]+)$/);if(i){if(i[0].startsWith("task_handoff:cp_a:")){const e=t(i[1],"launch-app");return{type:"launch-app",instanceId:Bp(e.instanceId,"instanceId"),appId:Bp(e.appId,"appId")}}return{type:"launch-app",instanceId:Hp(i[1]),appId:Hp(i[2])}}const r=e.match(/^task_handoff:cp_p:([^:]+)$/);if(r){const e=t(r[1],"pending-decision");return{type:"pending-decision",routeId:Bp(e.routeId,"routeId"),decision:Fp(e.decision)}}const o=e.match(/^task_handoff:approval:([^:]+:ai:[^:]+):(allow|deny|skip)$/);return o?{type:"pending-decision",routeId:o[1],decision:o[2]}:void 0}(e,(e,t)=>this.service.resolveChatActionToken(e,t))}bindOrAllowChatUser(e,t){const n=String(t||"").trim();return!!n&&(0===e.allowedUserIds.length?(e.allowedUserIds=[n],this.updateChatBridge(e.id,{allowedUserIds:e.allowedUserIds}),this.logInfo({bridgeId:e.id,channel:e.channel,userId:n},"chat user bound"),!0):e.allowedUserIds.includes(n))}async answerTelegramCallback(e,t,n){return async function(e,t,n,s){t.token&&n&&await e(`https://api.telegram.org/bot${t.token}/answerCallbackQuery`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({callback_query_id:n,text:s.slice(0,200)})})}(this.fetchImpl,e,t,n)}async editTelegramMessage(e,t,n,s,i={}){return async function(e,t,n,s,i,r={}){if(t.token)return qp(n=>e(`https://api.telegram.org/bot${t.token}/editMessageText`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(n)}),"editMessageText",i,{chat_id:n,message_id:s,...r.replyMarkup?{reply_markup:r.replyMarkup}:{}},r)}(this.fetchImpl,e,t,n,s,i)}async sendTelegramMessage(e,t,n,s={}){return Mp(this.fetchImpl,e,t,n,s)}async deleteTelegramMessage(e,t,n){return async function(e,t,n,s){if(!t.token||!Number.isInteger(s))return;const i=await e(`https://api.telegram.org/bot${t.token}/deleteMessage`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({chat_id:n,message_id:s})}),r=await i.json().catch(()=>({}));if(!i.ok||!1===r.ok)throw new Error(r.description||`Telegram deleteMessage failed with HTTP ${i.status}`)}(this.fetchImpl,e,t,n)}async rememberTelegramProgressMessage(e,t,n,s,i){if(!0!==e.routed)return;const r=Ah(e),{instanceId:o,sessionId:a,turnId:d}=r,c=Number(vh(s).message_id);if(!(o&&a&&d&&Number.isInteger(c)))return void this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,messageId:Number.isInteger(c)?c:void 0,routed:e.routed},"telegram ai session progress message not remembered");const l=xh(o,a,d,t.id,n),p=this.telegramProgress.remember(l,c,i,{bridgeId:t.id,chatId:n});this.telegramProgressMessageTargets.set(uh(t.id,n,c),{instanceId:o,sessionId:a,turnId:d,messageId:c}),this.deliveredAiSessionFingerprints.delete(l),this.logInfo({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,turnIdSources:r.sources,key:l,messageId:c,progressKeys:this.telegramProgressKeysFor(o,a,t.id,n),textPreview:fh(i)},"telegram ai session progress message remembered"),"queue"===function(e){return e.aiSession&&"action"in e.aiSession?e.aiSession.action:void 0}(e)&&p?.messageId&&p.messageId!==c&&(this.telegramProgressMessageTargets.delete(uh(t.id,n,p.messageId)),await this.deleteTelegramMessage(t,n,p.messageId).catch(e=>{this.logWarn({bridgeId:t.id,chatId:n,instanceId:o,sessionId:a,turnId:d,replacedMessageId:p.messageId,replacementMessageId:c,error:gh(e)},"telegram queued progress message replacement cleanup failed")}))}telegramReplyAiSessionTarget(e,t,n){const s=this.telegramProgressMessageTargets.get(uh(e,t,n));if(s)return s;for(const[s,i]of this.telegramProgress.entries)if(i.messageId===n&&i.route?.bridgeId===e&&i.route?.chatId===t){const i=hh(s,e,t);if(i){const s={...i,messageId:n};return this.telegramProgressMessageTargets.set(uh(e,t,n),s),s}}}async pollAiSessionUpdates(){this.logAiSessionDelivery({stage:"poll-tick"});const e=await this.service.listAiSessions({refresh:!0}).catch(()=>{});if(!e)return void this.logAiSessionDelivery({stage:"poll-no-snapshot"});const t=new Map(e.instances.map(e=>[e.instanceId,e.aiSessions]));this.logAiSessionDelivery({stage:"poll-snapshot",instanceCount:t.size,instances:[...t.entries()].map(([e,t])=>({instanceId:e,sessionCount:t.sessions?.length||0,runningCount:t.runningCount,waitingCount:t.waitingCount,updatedAt:t.updatedAt}))});const n=await this.aiSessionInstanceNames();for(const[e,s]of t)await this.deliverAiSessionSnapshot(e,s,n)}async deliverAiSessionSnapshot(e,t,n){const s=Array.isArray(t.sessions)?t.sessions:[];if(this.pruneAiSessionDeliveryState(e,new Set(s.map(e=>e.id))),0===s.length)return;const i=n||await this.aiSessionInstanceNames(),r=await this.aiSessionPendingApprovalRoutes(e);await this.deliverOwnedTelegramProgress(e,s,i,r),await this.deliverActiveBindingTelegramProgress(e,s,i,r)}pruneAiSessionDeliveryState(e,t){for(const[n,s]of this.telegramProgress.entries){const i=s.route?.bridgeId&&s.route.chatId?this.telegramProgressMessageTargets.get(uh(s.route.bridgeId,s.route.chatId,s.messageId||0))||hh(n,s.route.bridgeId,s.route.chatId):void 0;i&&i.instanceId===e&&!t.has(i.sessionId)&&(s.timer&&clearTimeout(s.timer),this.telegramProgress.entries.delete(n),this.deliveredAiSessionFingerprints.delete(n),s.route?.bridgeId&&s.route.chatId&&s.messageId&&this.telegramProgressMessageTargets.delete(uh(s.route.bridgeId,s.route.chatId,s.messageId)))}}async deliverActiveBindingTelegramProgress(e,t,n,s){for(const i of this.service.listChatSessions()){if(!i.bridgeId||i.activeInstanceId!==e||!i.activeAiSessionId)continue;const r=t.find(e=>e.id===i.activeAiSessionId);if(!r)continue;const o=Ph(n.get(e)||e,r),a=_h(r,o);if(!a){this.logAiSessionDelivery({stage:"skip-empty-text",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:bh(Dh(r))});continue}const d=Nh(r);if(!d){this.logAiSessionDelivery({stage:"skip-empty-turn-id",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:bh(Dh(r))});continue}if(this.listTelegramOwnedProgressEntries(e).some(e=>e.route.bridgeId===i.bridgeId&&e.route.chatId===i.chatSessionId&&e.owner.sessionId===r.id&&e.owner.turnId===d))continue;const c=xh(e,r.id,d,i.bridgeId||"",i.chatSessionId),l=Rh(r,o);if(!l||this.deliveredAiSessionFingerprints.get(c)===l){this.logAiSessionDelivery({stage:"skip-duplicate-fingerprint",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,hasFingerprint:Boolean(l),fingerprintMatched:this.deliveredAiSessionFingerprints.get(c)===l,latestTurn:bh(Dh(r)),textPreview:fh(a)});continue}const p=Th({cancelCallbackData:this.telegramAiSessionCallbacks.cancelCallbackData(e,r.id),queueSteerCallbackData:t=>this.telegramAiSessionCallbacks.queueSteerCallbackData(e,r.id,t),queueDeleteMenuCallbackData:()=>this.telegramAiSessionCallbacks.queueDeleteMenuCallbackData(e,r.id),permissionCallbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),pendingApproval:s.get(r.id)||Ch(e,r),session:r});if(this.logAiSessionDelivery({stage:"attempt",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,relatedProgressKeys:this.telegramProgressKeysFor(e,r.id,i.bridgeId||"",i.chatSessionId),hasProgressEntry:this.telegramProgress.entries.has(c),status:r.status,phase:r.phase,activeTurnId:r.activeTurnId,latestTurn:bh(Dh(r)),textPreview:fh(a)}),await this.updateChatAiSessionProgress(i,a,c,p).catch(t=>(this.bridgeErrors.set(i.bridgeId||"",t instanceof Error?t.message:String(t)),this.logWarn({bridgeId:i.bridgeId,chatId:i.chatSessionId,instanceId:e,sessionId:r.id,turnId:d,key:c,error:gh(t)},"chat ai session progress update failed"),!1)))this.logAiSessionDelivery({stage:"delivered",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,textPreview:fh(a)}),this.deliveredAiSessionFingerprints.set(c,l);else{if("telegram"===this.service.requireChatBridge(i.bridgeId).channel){const t=this.telegramProgress.entries.get(c),n=this.service.requireChatBridge(i.bridgeId);this.logAiSessionDelivery({stage:t?"telegram-update-not-delivered":"telegram-no-progress-entry",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,relatedProgressKeys:this.telegramProgressKeysFor(e,r.id,i.bridgeId||"",i.chatSessionId),bridgeEnabled:n.enabled,bridgeChannel:n.channel,progressMessageId:t?.messageId,progressLastText:fh(t?.lastText),progressHasPending:Boolean(t?.pending),latestTurn:bh(Dh(r)),textPreview:fh(a)});continue}await this.sendToChatBinding(i,{text:a}).catch(e=>(this.bridgeErrors.set(i.bridgeId||"",e instanceof Error?e.message:String(e)),!1))&&(this.logAiSessionDelivery({stage:"fallback-sent",instanceId:e,sessionId:r.id,bridgeId:i.bridgeId,chatId:i.chatSessionId,turnId:d,key:c,textPreview:fh(a)}),this.deliveredAiSessionFingerprints.set(c,l))}}}async deliverOwnedTelegramProgress(e,t,n,s){for(const i of this.listTelegramOwnedProgressEntries(e)){const r=this.service.requireChatBridge(i.route.bridgeId);if("telegram"!==r.channel||!r.enabled)continue;const o=this.matchTelegramOwnedProgressSession(i,t);if(!o)continue;const a={bridgeId:i.route.bridgeId,chatSessionId:i.route.chatId},d=Ph(n.get(e)||e,o),c=_h(o,d),l=Nh(o);if(!c||!l){this.logAiSessionDelivery({stage:"remembered-skip-turn-or-text",key:i.key,parsedTurnId:i.owner.turnId,currentTurnId:l,hasText:Boolean(c),instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId});continue}if(i.owner.turnId&&l!==i.owner.turnId){this.logAiSessionDelivery({stage:"remembered-skip-different-active-turn",key:i.key,ownerTurnId:i.owner.turnId,currentTurnId:l,instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId});continue}const p=l===i.owner.turnId?i.key:xh(e,o.id,l,i.route.bridgeId,i.route.chatId);if(p!==i.key&&this.telegramProgress.entries.has(p))continue;if(p!==i.key&&!this.rekeyTelegramOwnedProgress(i,p,{instanceId:e,sessionId:o.id,turnId:l}))continue;const u=Rh(o,d);if(!u||this.deliveredAiSessionFingerprints.get(p)===u){this.logAiSessionDelivery({stage:"remembered-skip-fingerprint",key:i.key,hasFingerprint:Boolean(u),fingerprintMatched:this.deliveredAiSessionFingerprints.get(p)===u,instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId});continue}const h=Th({cancelCallbackData:this.telegramAiSessionCallbacks.cancelCallbackData(e,o.id),queueSteerCallbackData:t=>this.telegramAiSessionCallbacks.queueSteerCallbackData(e,o.id,t),queueDeleteMenuCallbackData:()=>this.telegramAiSessionCallbacks.queueDeleteMenuCallbackData(e,o.id),permissionCallbackData:(e,t)=>this.service.pendingDecisionCallbackData(e,t),pendingApproval:s.get(o.id)||Ch(e,o),session:o}),m=await this.updateChatAiSessionProgress(a,c,p,h).catch(e=>(this.bridgeErrors.set(a.bridgeId||"",e instanceof Error?e.message:String(e)),!1));this.logAiSessionDelivery({stage:m?"remembered-delivered":"remembered-not-delivered",key:p,instanceId:e,sessionId:o.id,bridgeId:i.route.bridgeId,chatId:i.route.chatId,textPreview:fh(c)}),m&&(this.telegramProgressMessageTargets.set(uh(i.route.bridgeId,i.route.chatId,i.messageId),{instanceId:e,sessionId:o.id,turnId:l,messageId:i.messageId}),this.deliveredAiSessionFingerprints.set(p,u))}}rekeyTelegramOwnedProgress(e,t,n){return!!this.telegramProgress.rekey(e.key,t)&&(this.deliveredAiSessionFingerprints.delete(e.key),this.telegramProgressMessageTargets.set(uh(e.route.bridgeId,e.route.chatId,e.messageId),{...n,messageId:e.messageId}),!0)}logAiSessionDelivery(e){this.logInfo(e,"telegram ai session delivery flow")}telegramProgressKeysFor(e,t,n,s){const i=`${e}:${t}:`,r=`:${n}:${s}`;return[...this.telegramProgress.entries.keys()].filter(e=>e.startsWith(i)&&e.endsWith(r))}listTelegramOwnedProgressEntries(e){const t=[];for(const[n,s]of this.telegramProgress.entries){if(!s.route?.bridgeId||!s.route.chatId||!Number.isInteger(s.messageId))continue;const i=this.telegramProgressMessageTargets.get(uh(s.route.bridgeId,s.route.chatId,s.messageId))||hh(n,s.route.bridgeId,s.route.chatId);i&&i.instanceId===e&&t.push({key:n,route:{bridgeId:s.route.bridgeId,chatId:s.route.chatId},messageId:s.messageId,owner:{...i,messageId:s.messageId}})}return t}matchTelegramOwnedProgressSession(e,t){const n=t.find(t=>t.id===e.owner.sessionId);if(n)return n;if(e.owner.turnId){const n=t.find(t=>t.activeTurnId===e.owner.turnId||Dh(t)?.id===e.owner.turnId||Dh(t)?.providerTurnId===e.owner.turnId);if(n)return n}}async updateChatAiSessionProgress(e,t,n,s){if(!e.bridgeId)return this.logAiSessionDelivery({stage:"chat-update-skip-missing-bridge",chatId:e.chatSessionId,key:n}),!1;const i=this.service.requireChatBridge(e.bridgeId);if(!i.enabled)return this.logAiSessionDelivery({stage:"chat-update-skip-bridge-state",bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,bridgeEnabled:i.enabled,bridgeChannel:i.channel}),!1;if("dingding"===i.channel){if(!this.dingdingBridges.get(i.id))return!1;const r=await this.dingdingBridges.applyProgressUpdate({bridge:i,key:n,chatId:e.chatSessionId,text:t,replyMarkup:lh({actionRows:s})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:fh(t)},"dingding ai session progress updated"),r}if("lark"===i.channel){const r=await this.larkBridges.applyProgressUpdate({bridge:i,key:n,chatId:e.chatSessionId,text:t,replyMarkup:lh({actionRows:s})});return r&&this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,textPreview:fh(t)},"lark ai session progress updated"),r}if("telegram"!==i.channel)return!1;const r=this.telegramProgress.entries.get(n);if(!await this.telegramProgress.applyUpdate({bridge:i,key:n,chatId:e.chatSessionId,text:t,actionRows:s})){const t=this.telegramProgress.entries.get(n);return this.logAiSessionDelivery({stage:"telegram-update-returned-false",bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,progressMessageId:r?.messageId||t?.messageId,progressLastText:fh(r?.lastText||t?.lastText),progressHasPending:Boolean(r?.pending||t?.pending)}),!1}return this.logInfo({bridgeId:e.bridgeId,chatId:e.chatSessionId,key:n,messageId:r?.messageId||this.telegramProgress.entries.get(n)?.messageId,textPreview:fh(t)},r?"telegram ai session progress edited":"telegram ai session progress sent"),!0}async aiSessionInstanceNames(){return this.aiSessionInstanceNamesCache.get()}async aiSessionPendingApprovalRoutes(e){const t=await this.aiSessionPendingRoutesCache.get();return new Map(t.filter(t=>t.instanceId===e&&t.aiSessionId&&"approval"===t.kind).map(e=>[e.aiSessionId||"",e]))}}function ah(e){return"object"==typeof e&&e&&"reply"in e?String(e.reply||""):""}function dh(e){return"object"==typeof e&&null!==e&&!0===e.accepted}function ch(e){const t="object"==typeof e&&e&&"replyMarkup"in e?e.replyMarkup:void 0;if(t&&"object"==typeof t&&!Array.isArray(t))return t}function lh(e){const t=Array.isArray(e?.actionRows)?e.actionRows:void 0;return Kl(t||(Array.isArray(e?.actions)?e.actions:[]).map(e=>[e]))}function ph(e){const t=Number(e?.message_id);return Number.isInteger(t)?t:void 0}function uh(e,t,n){return[e,t,String(n)].join(":")}function hh(e,t,n){const s=`:${t}:${n}`;if(!e.endsWith(s))return;const i=e.slice(0,-s.length).split(":"),r=i[0]||"",o=i[1]||"",a=i.slice(2).join(":")||void 0;return r&&o?{instanceId:r,sessionId:o,turnId:a}:void 0}function mh(e){return"string"==typeof e?e:""}function gh(e){return e instanceof Error?e.message:String(e)}function yh(e,t){return Boolean(e&&"object"==typeof e&&"code"in e&&e.code===t)}function fh(e,t=160){const n=String(e||"").replace(/\s+/g," ").trim();return n.length<=t?n:`${n.slice(0,Math.max(0,t-3))}...`}function Ih(e){const t=Sh(e.body.cardActionData||e.body.content),n=Sh(t.cardPrivateData||e.body.cardPrivateData||e.body.content);return{outTrackId:mh(e.body.outTrackId),spaceId:mh(e.body.spaceId),conversationType:e.conversationType,hasCallbackData:Boolean(e.callbackData),callbackDataPreview:fh(e.callbackData,120),actionIds:[...wh(n.actionIdList),...wh(t.actionIdList),mh(n.actionId),mh(t.actionId),mh(e.body.actionId)].filter(Boolean).slice(0,5),cardActionDataKeys:Object.keys(t).sort(),privateDataKeys:Object.keys(n).sort(),paramKeys:Object.keys(e.params).sort(),hasSessionWebhook:Boolean(e.sessionWebhook)}}function bh(e){if(e)return{id:e.id,providerTurnId:e.providerTurnId,source:e.source,status:e.status,phase:e.phase,revision:e.revision,userPrompt:fh(e.userPrompt,80),hasResponse:Boolean(e.lastMessage?.trim()||e.summary?.trim()),responsePreview:fh(e.lastMessage||e.summary,80),updatedAt:e.updatedAt,observedAt:e.observedAt}}function vh(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:{}}function Sh(e){if(e&&"object"==typeof e&&!Array.isArray(e))return e;if("string"==typeof e&&e.trim())try{return vh(JSON.parse(e))}catch{return{}}return{}}function wh(e){return Array.isArray(e)?e.map(e=>mh(e)).filter(Boolean):[]}function Ah(e){const t=e.aiSession&&"session"in e.aiSession?e.aiSession:void 0,n=t?.session||(e.aiSession&&"id"in e.aiSession?e.aiSession:void 0);return{instanceId:e.instanceId||e.instance?.id||"",sessionId:e.aiSessionId||n?.id||e.binding?.activeAiSessionId||"",turnId:e.turnId||e.providerTurnId||t?.turnId||t?.providerTurnId||(n?Nh(n):""),sources:{resultTurnId:e.turnId,resultProviderTurnId:e.providerTurnId,actionTurnId:t?.turnId,actionProviderTurnId:t?.providerTurnId,sessionActiveTurnId:n?.activeTurnId,latestTurnId:n?Dh(n)?.id:void 0}}}const zh=5,kh=48;function Th(e){const{cancelCallbackData:t,queueSteerCallbackData:n,queueDeleteMenuCallbackData:s,permissionCallbackData:i,pendingApproval:r,session:o}=e,a="approval"===r?.kind?[[{text:"Allow",callbackData:i(r.id,"allow")},{text:"Skip",callbackData:i(r.id,"skip")},{text:"Deny",callbackData:i(r.id,"deny")}]]:[];if("running"!==o.status)return a;const d=(o.queue?.items||[]).filter(e=>"queued"===e.status).slice(0,zh);return[...d.map((e,t)=>[{text:Eh(e.message,t),callbackData:n(e.id)}]),d.length?[{text:"Delete Queue",callbackData:s()},{text:"Cancel",callbackData:t}]:[{text:"Cancel",callbackData:t}]]}function Ch(e,t){if("approval"===t.phase)return{id:`${e}:ai:${t.id}`,kind:"approval"}}function Eh(e,t){const n=`${t+1}. `,s=e.replace(/\s+/g," ").trim()||"Queued message",i=Math.max(8,kh-n.length),r=Array.from(s);return`${n}${r.length>i?`${r.slice(0,Math.max(1,i-3)).join("")}...`:s}`}function xh(e,t,...n){return[e,t,...n].join(":")}function Nh(e){const t=Dh(e);return t?.id?t.id:mh(e.activeTurnId)}function Rh(e,t=""){const n=Dh(e);return[t,n?.id||"",n?.status||e.status||"",n?.phase||e.phase||"",n?.lastMessage||"",n?.summary||"",n?.userPrompt||"",e.error||"",e.currentTool?.id||"",e.currentTool?.name||"",e.currentTool?.inputPreview||"",String(e.toolCallsSinceLastMessage??0),Oh(e)].join("\0")}function Oh(e){return(e.queue?.items||[]).map(e=>[e.id,e.status,e.message].join(":")).join("|")}function _h(e,t){const n=function(e,t){let n="";t?"waiting"===t.status&&"approval"===t.phase&&t.summary?.trim()?n=t.summary.trim():t.lastMessage?.trim()?n=t.lastMessage.trim():t.summary?.trim()&&(n=t.summary.trim()):"waiting"===e.status&&"approval"===e.phase&&e.summary?.trim()?n=e.summary.trim():e.lastMessage?.trim()?n=e.lastMessage.trim():e.summary?.trim()?n=e.summary.trim():e.error?.trim()&&(n="failed"===e.status?`${e.agent} session failed:\n${e.error.trim()}`:e.error.trim());const s=function(e){if(e.currentTool?.name)return`Thinking... · ${e.currentTool.name}${e.currentTool.inputPreview?` · ${e.currentTool.inputPreview}`:""}`;const t=e.toolCallsSinceLastMessage??0;return t>0?`Thinking... · ${t} ${1===t?"tool":"tools"} completed`:""}(e);return[n,s&&!jh(n,e)?s:""].filter(Boolean).join("\n\n")}(e,Dh(e));return n?`${t}\n${n}`:""}function Ph(e,t){const n=["idle"===t.status?"completed":t.status,t.phase&&"unknown"!==t.phase?t.phase:void 0].filter(Boolean).join("/");return`${e} · ${t.agent||"ai"} ${n||"unknown"}`}function jh(e,t){if("waiting"!==t.status||"approval"!==t.phase)return!1;const n=t.currentTool?.inputPreview?.trim();return Boolean(n&&e.includes(n))}function Dh(e){return(e.turns||[]).filter(e=>e.id||e.userPrompt?.trim()||e.lastMessage?.trim()||e.summary?.trim()).at(-1)}class Mh{clients=new Set;listeners=new Set;transientDemandListeners=new Set;externalTransientDemands=new Map;seq=0;connect(e,t={}){e.topics=new Set(["*"]),e.instanceIds=t.instanceIds?.length?new Set(t.instanceIds):void 0,e.subscriptionReceived=!0!==t.expectsTransientSubscription,this.clients.add(e),this.publishTransientDemand(),e.on("close",()=>{this.clients.delete(e),this.publishTransientDemand()}),e.on("message",t=>{const n=function(e){try{const t=JSON.parse(String(e||"{}"));if(!t||"object"!=typeof t)return;const n=t,s=void 0===n.aiSessionTransient?void 0:yo.safeParse(n.aiSessionTransient);if(s&&!s.success)return;return{type:n.type,topics:Array.isArray(n.topics)?n.topics.map(String).filter(Boolean):void 0,instanceIds:Array.isArray(n.instanceIds)?n.instanceIds.map(String).map(e=>e.trim()).filter(Boolean):void 0,...s?.success?{aiSessionTransient:s.data}:{}}}catch{return}}(t);"subscribe"===n?.type&&(e.topics=new Set(void 0===n.topics?["*"]:n.topics),e.instanceIds=n.instanceIds?.length?new Set(n.instanceIds):void 0,e.aiSessionTransient=n.aiSessionTransient,e.subscriptionReceived=!0,this.publishTransientDemand())})}publish(e,t,n={}){const s=this.createEvent(e,t,n),i=s.topic,r=JSON.stringify(s),o=Buffer.byteLength(r,"utf8");for(const e of this.listeners)try{e(s)}catch{this.listeners.delete(e)}for(const t of this.clients)if(t.readyState===t.OPEN&&qh(t.topics,i,e)&&Bh(t.instanceIds,s.scope)&&Fh(t,s)){if((t.bufferedAmount??0)+o>16777216){this.clients.delete(t);try{t.close?.(1013,"Event consumer is too slow.")}catch{}this.publishTransientDemand();continue}try{t.send(r)}catch{this.clients.delete(t),this.publishTransientDemand()}}return s}on(e){return this.listeners.add(e),()=>{this.listeners.delete(e)}}onAiSessionTransientDemand(e){return this.transientDemandListeners.add(e),e(this.aiSessionTransientDemand()),()=>this.transientDemandListeners.delete(e)}registerAiSessionTransientDemand(e){const t=Symbol("ai-session-transient-demand");return this.externalTransientDemands.set(t,e),this.publishTransientDemand(),()=>{this.externalTransientDemands.delete(t),this.publishTransientDemand()}}registerLegacyAiSessionTransientDemand(e){const t=new Set(e);if(t.has("*")||t.has(_))return this.registerAiSessionTransientDemand();const n=t.has(M),s=t.has(L);return n||s?this.registerAiSessionTransientDemand({messageDeltas:{allInstances:n,instanceIds:[]},timelineAllSessions:s,timelineSessions:[]}):()=>{}}aiSessionTransientDemand(){let e=!1,t=!1,n=!1;const s=new Set,i=new Map;let r;for(const o of this.clients)if(o.subscriptionReceived&&$h(o.topics))if(o.aiSessionTransient){t||=o.aiSessionTransient.messageDeltas.allInstances,n||=o.aiSessionTransient.timelineAllSessions,r=Lh(r,o.aiSessionTransient.replaySince);for(const e of o.aiSessionTransient.messageDeltas.instanceIds)s.add(e);for(const e of o.aiSessionTransient.timelineSessions)i.set(JSON.stringify([e.instanceId,e.sessionId]),e)}else e=!0;for(const o of this.externalTransientDemands.values())if(o){t||=o.messageDeltas.allInstances,n||=o.timelineAllSessions,r=Lh(r,o.replaySince);for(const e of o.messageDeltas.instanceIds)s.add(e);for(const e of o.timelineSessions)i.set(JSON.stringify([e.instanceId,e.sessionId]),e)}else e=!0;return{legacyAll:e,...r?{replaySince:r}:{},messageDeltas:{allInstances:e||t,instanceIds:[...s]},timelineAllSessions:e||n,timelineSessions:[...i.values()]}}send(e,t,n,s={}){const i=this.createEvent(t,n,s);return e.send(JSON.stringify(i)),i}createEvent(e,t,n={}){return{v:1,id:n.sourceEvent?.id||`evt_${Date.now().toString(36)}_${Math.random().toString(16).slice(2)}`,seq:++this.seq,type:e,topic:n.topic||go(e),createdAt:n.sourceEvent?.createdAt||(new Date).toISOString(),payload:t,...n.sourceEvent?.replay?{replay:!0}:{},scope:n.scope}}publishTransientDemand(){const e=this.aiSessionTransientDemand();for(const t of this.transientDemandListeners)try{t(e)}catch{}}}function Lh(e,t){return t&&(!e||t<e)?t:e}function qh(e,t,n){return!e||e.has("*")||e.has(t)||e.has(n)}function $h(e){return qh(e,_,M)||qh(e,_,L)}function Bh(e,t){return!e||!t?.instanceId||e.has(t.instanceId)}function Fh(e,t){return"ai-session.message-delta"!==t.type&&"ai-session.timeline-item"!==t.type||!!e.subscriptionReceived&&fo(e.aiSessionTransient,t)}function Uh(e,n="attachment",s={}){const i=s.maxLength??240,r=s.maxBytes??240,o=t.posix.basename(String(e).replace(/\\/g,"/")).replace(/[\u0000-\u001f\u007f<>:"/\\|?*]/g,"_").trim().replace(/[. ]+$/g,""),a=Hh(/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(o)?`_${o}`:o,i,r).replace(/[. ]+$/g,"");return a&&"."!==a&&".."!==a?a:Hh(n,i,r)||"attachment"}function Hh(e,t,n){if(!Number.isInteger(t)||t<=0||!Number.isInteger(n)||n<=0)return"";let s="",i=0,r=0;for(const o of e){const e=i+o.length,a=r+Buffer.byteLength(o);if(e>t||a>n)break;s+=o,i=e,r=a}return s}const Wh={"image/bmp":".bmp","image/gif":".gif","image/jpeg":".jpg","image/png":".png","image/webp":".webp"},Gh=d.z.object({instanceId:d.z.string().trim().min(1).max(120),sessionId:d.z.string().trim().min(1).max(120),kind:d.z.enum(["image","file"]),name:d.z.string().trim().min(1).max(240),mime:d.z.string().trim().min(1).max(120),data:d.z.string().min(1).max(31457280)}).strict();function Vh(){return t.join(f.tmpdir(),"task-handoff-ai-session-attachments")}class Kh{items=new Map;ttlMs;constructor(e=864e5){this.ttlMs=e,this.pruneOrphanFiles()}upload(e){this.pruneExpired();const i=Gh.parse(e),r=function(e,t){const n=/^data:([^;,]+);base64,(.+)$/i.exec(e.trim()),s=n?.[1]||t,i=n?.[2]||e;return{mime:s,buffer:Buffer.from(i,"base64")}}(i.data,i.mime),o=r.mime.toLowerCase(),a=Wh[o]||"";if("image"===i.kind&&!a)throw new Error(`Unsupported image type: ${o}`);const d="image"===i.kind?r.buffer.length>x:r.buffer.length>=N;if(!r.buffer.length||d)throw new Error("image"===i.kind?"Image must be between 1 byte and 20971520 bytes.":"File must be smaller than 512000 bytes.");const c=`att_${s.randomUUID().replace(/-/g,"").slice(0,24)}`,l=new Date,p=new Date(l.getTime()+this.ttlMs),u=Vh();n.mkdirSync(u,{recursive:!0});const h=Uh(i.name),m=`${c}-`,g=Uh(h.endsWith(a)?h:`${h}${a}`,"attachment",{maxBytes:255-Buffer.byteLength(m)}),y=t.join(u,`${m}${g}`);n.writeFileSync(y,r.buffer);const f={id:c,instanceId:i.instanceId,sessionId:i.sessionId,kind:i.kind,name:h,mime:o,size:r.buffer.length,source:{type:"inline",encoding:"base64",data:r.buffer.toString("base64")},path:y,createdAt:l.toISOString(),expiresAt:p.toISOString()};return this.items.set(c,f),this.publicAttachment(f)}resolveRefs(e,t,n){this.pruneExpired();const s=d.z.array(ve).max(6).default([]).parse(e),i=s.map(e=>"runtime-path"===e.source.type?Ie.parse(e):this.requireAttachment(e,t,n));if(i.reduce((e,t)=>e+("inline"===t.source.type?t.size:0),0)>R)throw new Error("Inline attachments must be 41943040 bytes or less in total.");for(const e of s)"upload-ref"===e.source.type&&this.consumeAttachment(e.id);return i}dispose(){for(const e of[...this.items.keys()])this.consumeAttachment(e)}requireAttachment(e,t,n){const s=this.items.get(e.id);if(!s)throw new Error(`AI session attachment not found or expired: ${e.id}`);if(e.kind&&e.kind!==s.kind)throw new Error(`AI session attachment kind mismatch: ${e.id}`);if(s.instanceId!==t||s.sessionId!==n)throw new Error(`AI session attachment scope mismatch: ${e.id}`);return Ie.parse({id:s.id,kind:s.kind,name:s.name,mime:s.mime,size:s.size,source:s.source})}consumeAttachment(e){const t=this.items.get(e);if(t){this.items.delete(e);try{n.unlinkSync(t.path)}catch{}}}publicAttachment(e){return{id:e.id,kind:e.kind,name:e.name,mime:e.mime,size:e.size,expiresAt:e.expiresAt}}pruneExpired(){const e=Date.now();for(const[t,s]of this.items)if(!(Date.parse(s.expiresAt)>e)){this.items.delete(t);try{n.unlinkSync(s.path)}catch{}}this.pruneOrphanFiles()}pruneOrphanFiles(){const e=Vh();let s;try{s=n.readdirSync(e)}catch{return}const i=Date.now()-Math.max(this.ttlMs,864e5);for(const r of s){const s=t.join(e,r);try{n.statSync(s).isFile()&&n.statSync(s).mtimeMs<=i&&n.unlinkSync(s)}catch{}}}}const Jh=864e5,Yh=d.z.object({schemaVersion:d.z.literal(1),cacheId:d.z.string().regex(/^[a-f0-9]{64}$/),instanceId:d.z.string().trim().min(1).max(120),scopeType:d.z.enum(["session","create-request"]),scopeId:d.z.string().trim().min(1).max(160),attachmentId:d.z.string().trim().min(1).max(120),sessionId:d.z.string().trim().min(1).max(120).optional(),messageId:d.z.string().trim().min(1).max(240).optional(),kind:d.z.enum(["image","file"]),name:d.z.string().trim().min(1).max(240),mime:d.z.string().trim().min(1).max(120),disposition:d.z.string().trim().min(1).max(1024).optional(),size:d.z.number().int().positive(),etag:d.z.string().trim().min(1).max(160).optional(),instanceEpoch:d.z.string().trim().min(1).max(240).optional(),cachedAt:d.z.string().datetime(),lastAccessedAt:d.z.string().datetime(),expiresAt:d.z.string().datetime()}).strict();class Qh{root;contentDir;manifestDir;maxBytes;now;onWarning;entries=new Map;pendingBindings=new Map;reservedBytes=0;constructor(e,s={}){this.root=t.join(e,"ai-session-attachment-cache"),this.contentDir=t.join(this.root,"content"),this.manifestDir=t.join(this.root,"manifests"),this.maxBytes=s.maxBytes??2147483648,this.now=s.now||Date.now,this.onWarning=s.onWarning,n.mkdirSync(this.contentDir,{recursive:!0,mode:448}),n.mkdirSync(this.manifestDir,{recursive:!0,mode:448}),this.restore(),this.gc()}putFile(e){this.gc();const t=n.statSync(e.sourcePath);if(!t.isFile()||t.size!==e.size||e.size<=0)throw new Error("Attachment cache source size mismatch.");if(this.evictFor(e.size),this.usedBytes()+this.reservedBytes+e.size>this.maxBytes)return;const i=Xh(e.instanceId,e.attachmentId),r=this.contentPath(i),o=`${r}.${process.pid}.${s.randomUUID()}.tmp`;n.copyFileSync(e.sourcePath,o,n.constants.COPYFILE_EXCL),n.chmodSync(o,384),n.renameSync(o,r);const a=new Date(this.now()).toISOString(),d=new Date(Math.min(this.now()+Jh,e.cacheUntil??Number.POSITIVE_INFINITY)).toISOString(),c=Yh.parse({schemaVersion:1,cacheId:i,instanceId:e.instanceId,scopeType:e.scopeType,scopeId:e.scopeId,attachmentId:e.attachmentId,...e.sessionId?{sessionId:e.sessionId}:{},...e.messageId?{messageId:e.messageId}:{},kind:e.kind,name:Uh(e.name),mime:e.mime.toLowerCase(),...e.disposition?{disposition:e.disposition}:{},size:e.size,...e.etag?{etag:e.etag}:{},...e.instanceEpoch?{instanceEpoch:e.instanceEpoch}:{},cachedAt:a,lastAccessedAt:a,expiresAt:d});return this.save(c),this.project(c)}beginBestEffortWrite(e){if(this.gc(),this.evictFor(e.size),e.size<=0||this.usedBytes()+this.reservedBytes+e.size>this.maxBytes)return;this.reservedBytes+=e.size;const t=Xh(e.instanceId,e.attachmentId),i=this.contentPath(t),r=`${i}.${process.pid}.${s.randomUUID()}.tmp`,o=n.createWriteStream(r,{flags:"wx",mode:384,highWaterMark:1048576});let a=0,d=!1,c=!0;const l=()=>{c&&(c=!1,this.reservedBytes=Math.max(0,this.reservedBytes-e.size))},p=()=>{if(!d){d=!0,l(),o.destroy();try{n.unlinkSync(r)}catch{}}};return o.on("error",p),{offer:t=>!d&&(a+=t.byteLength,!(a>e.size||!o.write(t))||(p(),!1)),finish:async()=>{if(d||a!==e.size)p();else if(await new Promise((e,t)=>{o.once("finish",e),o.once("error",t),o.end()}).catch(()=>{}),!d){l();try{n.renameSync(r,i);const s=new Date(this.now()).toISOString(),o=new Date(Math.min(this.now()+Jh,e.cacheUntil??Number.POSITIVE_INFINITY)).toISOString(),a=Yh.parse({schemaVersion:1,cacheId:t,instanceId:e.instanceId,scopeType:e.scopeType,scopeId:e.scopeId,attachmentId:e.attachmentId,...e.sessionId?{sessionId:e.sessionId}:{},...e.messageId?{messageId:e.messageId}:{},kind:e.kind,name:Uh(e.name),mime:e.mime.toLowerCase(),...e.disposition?{disposition:e.disposition}:{},size:e.size,...e.etag?{etag:e.etag}:{},...e.instanceEpoch?{instanceEpoch:e.instanceEpoch}:{},cachedAt:s,lastAccessedAt:s,expiresAt:o});return this.save(a),this.project(a)}catch{return void p()}}},abort:p}}bind(e){const t=Xh(e.instanceId,e.attachmentId),n=this.entries.get(t);if(!n)return this.pendingBindings.set(t,e),!1;if(n.scopeId!==e.scopeId)return!1;const s=new Date(Math.min(Date.parse(n.expiresAt),e.cacheUntil??Number.POSITIVE_INFINITY)).toISOString();return this.save(Yh.parse({...n,sessionId:e.sessionId,messageId:e.messageId,expiresAt:s,...e.etag?{etag:e.etag}:{}})),!0}get(e){this.gc();const t=Xh(e.instanceId,e.attachmentId),n=this.entries.get(t);if(!n||n.sessionId!==e.sessionId||n.messageId!==e.messageId||n.instanceEpoch&&n.instanceEpoch!==e.instanceEpoch)return;const s=Yh.parse({...n,lastAccessedAt:new Date(this.now()).toISOString()});return this.entries.set(t,s),this.project(s)}removeInstance(e){for(const t of[...this.entries.values()])t.instanceId===e&&this.remove(t.cacheId);for(const[t,n]of this.pendingBindings)n.instanceId===e&&this.pendingBindings.delete(t)}gc(){const e=this.now();for(const t of[...this.entries.values()])(Date.parse(t.expiresAt)<=e||!this.validContent(t))&&this.remove(t.cacheId);this.cleanupOrphans()}restore(){let e=[];try{e=n.readdirSync(this.manifestDir)}catch{return}for(const s of e)if(s.endsWith(".json"))try{const e=JSON.parse(n.readFileSync(t.join(this.manifestDir,s),"utf8")),i=Zh(e),r=Yh.safeParse(i);if(!r.success)throw new Error("invalid manifest");Object.keys(e).some(e=>!(e in Yh.shape))&&this.writeManifest(r.data),this.entries.set(r.data.cacheId,r.data)}catch{this.onWarning?.(`invalid AI session attachment cache manifest ignored: ${s}`)}}evictFor(e){const t=[...this.entries.values()].sort((e,t)=>Date.parse(e.lastAccessedAt)-Date.parse(t.lastAccessedAt));let n=this.usedBytes();for(const s of t){if(n+this.reservedBytes+e<=this.maxBytes)break;n-=s.size,this.remove(s.cacheId)}}save(e){const t=this.pendingBindings.get(e.cacheId),n=t&&t.scopeId===e.scopeId?Yh.parse({...e,sessionId:t.sessionId,messageId:t.messageId,expiresAt:new Date(Math.min(Date.parse(e.expiresAt),t.cacheUntil??Number.POSITIVE_INFINITY)).toISOString(),...t.etag?{etag:t.etag}:{}}):e;this.pendingBindings.delete(e.cacheId),this.writeManifest(n),this.entries.set(n.cacheId,n)}writeManifest(e){l.sync(this.manifestPath(e.cacheId),`${JSON.stringify(e,null,2)}\n`,{mode:384})}remove(e){this.entries.delete(e);try{n.unlinkSync(this.manifestPath(e))}catch{}try{n.unlinkSync(this.contentPath(e))}catch{}}cleanupOrphans(){const e=new Set(this.entries.keys());let s=[];try{s=n.readdirSync(this.contentDir)}catch{return}for(const i of s)if(!e.has(i))try{n.unlinkSync(t.join(this.contentDir,i))}catch{}}validContent(e){try{const t=n.statSync(this.contentPath(e.cacheId));return t.isFile()&&t.size===e.size}catch{return!1}}usedBytes(){return[...this.entries.values()].reduce((e,t)=>this.validContent(t)?e+t.size:e,0)}project(e){return{...e,path:this.contentPath(e.cacheId)}}contentPath(e){return t.join(this.contentDir,e)}manifestPath(e){return t.join(this.manifestDir,`${e}.json`)}}function Xh(e,t){return s.createHash("sha256").update(`${e}\0${t}`).digest("hex")}function Zh(e){if(!e||"object"!=typeof e||Array.isArray(e))return e;const t=e;return Object.fromEntries(Object.keys(Yh.shape).filter(e=>Object.prototype.hasOwnProperty.call(t,e)).map(e=>[e,t[e]]))}const em={controlPlaneAuthBoundary:"public"},tm={controlPlaneAuthBoundary:"public-ui"},nm={controlPlaneAuthBoundary:"proxy-binding"},sm={controlPlaneAuthBoundary:"node-tunnel"};function im(e,t=Math.random){const n=Math.max(1,Math.floor(e));if(1===n)return 0;if(2===n)return 250;const s=Math.min(6e4,250*2**(n-2));return Math.min(6e4,Math.round(s*(.75+.5*t())))}class rm{retryNumber=0;random;constructor(e=Math.random){this.random=e}get attempts(){return this.retryNumber}next(){return this.retryNumber+=1,{attempt:this.retryNumber,delay:im(this.retryNumber,this.random)}}reset(){this.retryNumber=0}}class om{backoff;timer;constructor(e=Math.random){this.backoff=new rm(e)}get pending(){return Boolean(this.timer)}get attempts(){return this.backoff.attempts}schedule(e,t={}){if(this.timer)return;const n=this.backoff.next(),s=t.setTimeoutFn||setTimeout;return this.timer=s(()=>{this.timer=void 0,e()},n.delay),n}reset(e=clearTimeout){this.timer&&e(this.timer),this.timer=void 0,this.backoff.reset()}cancel(e=clearTimeout){this.timer&&e(this.timer),this.timer=void 0}}class am extends om{}function dm(e,t){return Number.isFinite(e)&&Number(e)>0?Number(e):t}function cm(e){if(!e.length)return;const t=[...e].sort((e,t)=>e-t);return t[Math.ceil(.95*t.length)-1]}function lm(e){return e.unref?.(),e}class pm{connectTimeoutMs;handshakeTimeoutMs;heartbeatIntervalMs;heartbeatTimeoutMs;heartbeatMissThreshold;stableThresholdMs;now;setTimeoutFn;clearTimeoutFn;ping;onTimeout;onStable;onPhase;connectTimer;handshakeTimer;heartbeatTimer;stableTimer;awaitingPongSince;consecutiveHeartbeatMisses=0;stable=!1;stopped=!1;currentPhase="connecting";lastActivityAt;lastPongAt;pingRttMs;recentPingRttMs=[];constructor(e){this.connectTimeoutMs=dm(e.connectTimeoutMs,1e4),this.handshakeTimeoutMs=dm(e.handshakeTimeoutMs,1e4),this.heartbeatIntervalMs=dm(e.heartbeatIntervalMs,25e3),this.heartbeatTimeoutMs=dm(e.heartbeatTimeoutMs,15e3),this.heartbeatMissThreshold=Math.max(1,Math.floor(dm(e.heartbeatMissThreshold,2))),this.stableThresholdMs=dm(e.stableThresholdMs,6e4),this.now=e.now||Date.now,this.setTimeoutFn=e.setTimeoutFn||setTimeout,this.clearTimeoutFn=e.clearTimeoutFn||clearTimeout,this.ping=e.ping,this.onTimeout=e.onTimeout,this.onStable=e.onStable,this.onPhase=e.onPhase}get phase(){return this.currentPhase}start(){this.stopped=!1,this.setPhase("connecting"),this.clearTimer("connectTimer"),this.connectTimer=lm(this.setTimeoutFn(()=>this.timeout("connect"),this.connectTimeoutMs))}opened(){this.stopped||(this.clearTimer("connectTimer"),this.setPhase("handshaking"),this.handshakeTimer=lm(this.setTimeoutFn(()=>this.timeout("handshake"),this.handshakeTimeoutMs)),this.scheduleHeartbeat(this.heartbeatIntervalMs))}healthy(){this.stopped||(this.clearTimer("handshakeTimer"),this.activity(),this.setPhase("healthy"),this.stable||this.stableTimer||(this.stableTimer=lm(this.setTimeoutFn(()=>{this.stableTimer=void 0,this.stopped||"healthy"!==this.currentPhase||(this.stable=!0,this.onStable?.())},this.stableThresholdMs))))}activity(){this.stopped||(this.lastActivityAt=this.now(),this.awaitingPongSince=void 0,this.consecutiveHeartbeatMisses=0,"handshaking"!==this.currentPhase&&"healthy"!==this.currentPhase||this.scheduleHeartbeat(this.heartbeatIntervalMs))}pong(){if(this.stopped)return;const e=this.now();void 0!==this.awaitingPongSince&&(this.pingRttMs=Math.max(0,e-this.awaitingPongSince),this.recentPingRttMs.push(this.pingRttMs),this.recentPingRttMs.length>20&&this.recentPingRttMs.shift()),this.awaitingPongSince=void 0,this.consecutiveHeartbeatMisses=0,this.lastPongAt=e,this.lastActivityAt=e,this.scheduleHeartbeat(this.heartbeatIntervalMs)}close(){this.stopped||(this.stopped=!0,this.clearTimers(),this.awaitingPongSince=void 0,this.setPhase("closed"))}diagnostics(){return{phase:this.currentPhase,stable:this.stable,...void 0===this.pingRttMs?{}:{pingRttMs:this.pingRttMs},...this.recentPingRttMs.length?{pingRttP95Ms:cm(this.recentPingRttMs)}:{},...void 0===this.lastActivityAt?{}:{lastActivityAt:new Date(this.lastActivityAt).toISOString()},...void 0===this.lastPongAt?{}:{lastPongAt:new Date(this.lastPongAt).toISOString()},...this.consecutiveHeartbeatMisses?{consecutiveHeartbeatMisses:this.consecutiveHeartbeatMisses}:{}}}scheduleHeartbeat(e){this.stopped||(this.clearTimer("heartbeatTimer"),this.heartbeatTimer=lm(this.setTimeoutFn(()=>{if(this.heartbeatTimer=void 0,!this.stopped){if(void 0!==this.awaitingPongSince){const e=Math.max(0,this.now()-this.awaitingPongSince);return e>=this.heartbeatTimeoutMs?(this.consecutiveHeartbeatMisses+=1,this.awaitingPongSince=void 0,this.consecutiveHeartbeatMisses>=this.heartbeatMissThreshold?void this.timeout("heartbeat"):void this.sendHeartbeatProbe()):void this.scheduleHeartbeat(this.heartbeatTimeoutMs-e)}this.sendHeartbeatProbe()}},e)))}sendHeartbeatProbe(){this.awaitingPongSince=this.now();try{this.ping()}catch{if(this.consecutiveHeartbeatMisses+=1,this.awaitingPongSince=void 0,this.consecutiveHeartbeatMisses>=this.heartbeatMissThreshold)return void this.timeout("heartbeat")}this.scheduleHeartbeat(this.heartbeatTimeoutMs)}timeout(e){this.stopped||(this.clearTimers(),this.setPhase("failed"),this.onTimeout(e))}setPhase(e){this.currentPhase!==e&&(this.currentPhase=e,this.onPhase?.(e))}clearTimers(){this.clearTimer("connectTimer"),this.clearTimer("handshakeTimer"),this.clearTimer("heartbeatTimer"),this.clearTimer("stableTimer")}clearTimer(e){const t=this[e];t&&this.clearTimeoutFn(t),this[e]=void 0}}class um{transport;constructor(e){this.transport=e}attachMain(e,t){this.transport.attach(e,t),t.send(JSON.stringify({type:"control-plane.hello",protocolVersion:"2026-08-01",nodeId:e,serverTime:(new Date).toISOString(),capabilities:{reverseTunnel:"request-response",auxiliaryChannels:!0,httpResponseStreaming:!0,lifecycleCommands:!0,instanceApiProxy:!0}})),t.on("message",n=>this.handleMainMessage(e,t,n))}attachAuxiliary(e,t,n){return this.transport.attachAuxiliary(e,t,n)}handleMainMessage(e,t,n){if(!this.transport.isCurrentSocket(e,t))return;let s;try{s=JSON.parse(String(n))}catch{return void t.send(JSON.stringify({type:"control-plane.error",code:"INVALID_JSON"}))}const i=s&&"object"==typeof s?s:{},r=this.transport.handleSocketMessage(e,t,i);if(void 0!==r&&!r){if("node-agent.ping"!==i.type)return"node-agent.identify"===i.type?(this.transport.markHealthy(e,t),void t.send(JSON.stringify({type:"control-plane.identified",nodeId:e,serverTime:(new Date).toISOString()}))):void t.send(JSON.stringify({type:"control-plane.error",code:"UNSUPPORTED_MESSAGE"}));t.send(JSON.stringify({type:"control-plane.pong",nodeId:e,serverTime:(new Date).toISOString()}))}}}const hm={[P]:vt,[j]:St,[D]:wt,[M]:At,[L]:zt,[Nt]:Ft,[Rt]:Ut,[Ot]:Ht},mm=new Set(Object.keys(hm));class gm{options;validatedScopes=new Map;validatingScopes=new Map;eventQueues=new Map;scopeEpochs=new Map;constructor(e={}){this.options=e}handle(e,t){const n="string"==typeof t.type?t.type:"";if("node-agent.streams.hello"===n){const n="string"==typeof t.instanceId?t.instanceId:"",s=ra(vo,t.payload);return n&&s.success&&this.enqueue(e,n,()=>this.options.onStreamsHello?.(n,s.data)),!0}if(!n.startsWith("node-agent.event."))return!1;const s=ym(t.event),i="string"==typeof s?.type?s.type:"";if(!i)return!0;const r="payload"in s?s.payload:{},o=ym(s.scope)||{},a="string"==typeof t.instanceId?t.instanceId:void 0,d=function(...e){return e.find(e=>"string"==typeof e)}(o.instanceId,s.instanceId,a);if("instance.metrics.snapshot"===i){const t=ra(_r,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(i,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(i===eo){const t=ra(to,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(i,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(i===wr||i===Ar){const t=ra(i===wr?kr:Tr,r);return!t.success||t.data.instanceId!==d||(this.enqueue(e,t.data.instanceId,()=>{this.options.events?.publish(i,t.data,{topic:"instances",scope:{...o,nodeId:e,instanceId:t.data.instanceId}})}),!0)}if(mm.has(i)){const t=function(e,t){const n=hm[e];if(!n)return;const s=ra(n,t);if(!s.success)return;const i=s.data;return{instanceId:"meta"in i?i.meta.instanceId:i.instanceId,payload:i}}(i,r);return!t||([o.instanceId,s.instanceId,a].filter(e=>"string"==typeof e&&Boolean(e)).some(e=>e!==t.instanceId)||this.enqueue(e,t.instanceId,()=>{const n={...o,nodeId:e,instanceId:t.instanceId},r={v:1,id:"string"==typeof s.id?s.id:`forwarded_${Date.now().toString(36)}`,seq:"number"==typeof s.seq?s.seq:0,type:i,topic:"string"==typeof s.topic?s.topic:i.startsWith("app-session.")?"app.sessions":"ai.sessions",createdAt:"string"==typeof s.createdAt?s.createdAt:(new Date).toISOString(),payload:t.payload,...!0===s.replay?{replay:!0}:{},scope:n};this.options.onSessionEvent&&!this.options.onSessionEvent(r)||this.options.events?.publish(i,t.payload,{topic:r.topic,scope:n,sourceEvent:{id:r.id,createdAt:r.createdAt,replay:r.replay}})}),!0)}const c=()=>{this.options.events?.publish(i,r,{topic:"string"==typeof s.topic?s.topic:void 0,scope:{...o,nodeId:e,...d?{instanceId:d}:{}}})};return d?this.enqueue(e,d,c):c(),!0}invalidate(e={}){const t=new Set;for(const[n,s]of this.validatedScopes)e.nodeId&&s.nodeId!==e.nodeId||e.instanceId&&s.instanceId!==e.instanceId||t.add(n);for(const n of new Set([...this.validatingScopes.keys(),...this.eventQueues.keys()])){const[s,i]=Im(n);e.nodeId&&s!==e.nodeId||e.instanceId&&i!==e.instanceId||t.add(n)}for(const e of t)this.scopeEpochs.delete(e),this.validatedScopes.delete(e),this.validatingScopes.delete(e),this.eventQueues.delete(e)}diagnostics(){return{validatedScopes:this.validatedScopes.size,validatingScopes:this.validatingScopes.size,queuedScopes:this.eventQueues.size,scopeEpochs:this.scopeEpochs.size}}enqueue(e,t,n){const s=fm(e,t),i=this.scopeEpoch(s),r=(this.eventQueues.get(s)||Promise.resolve()).catch(()=>{}).then(async()=>{this.scopeEpochs.get(s)===i&&await this.isScopeValid(e,t,i)&&this.scopeEpochs.get(s)===i&&await n()});this.eventQueues.set(s,r);const o=()=>{this.eventQueues.get(s)===r&&this.eventQueues.delete(s),this.scopeEpochs.get(s)!==i||this.eventQueues.has(s)||this.validatingScopes.has(s)||this.scopeEpochs.delete(s)};r.then(o,o)}async isScopeValid(e,t,n){const s=fm(e,t);if((this.validatedScopes.get(s)?.expiresAt||0)>Date.now())return!0;const i=this.validatingScopes.get(s);if(i)return i;const r=Promise.resolve(this.options.validateInstanceScope?.(e,t)).then(Boolean).catch(()=>!1).then(i=>(i&&this.scopeEpochs.get(s)===n&&this.validatedScopes.set(s,{nodeId:e,instanceId:t,expiresAt:Date.now()+(this.options.scopeTtlMs??3e4)}),i));return this.validatingScopes.set(s,r),r.finally(()=>{this.validatingScopes.get(s)===r&&this.validatingScopes.delete(s)})}scopeEpoch(e){const t=this.scopeEpochs.get(e);if(t)return t;const n={};return this.scopeEpochs.set(e,n),n}}function ym(e){return e&&"object"==typeof e&&!Array.isArray(e)?e:void 0}function fm(e,t){return JSON.stringify([e,t])}function Im(e){const t=JSON.parse(e);return Array.isArray(t)&&2===t.length?[String(t[0]),String(t[1])]:["",""]}const bm=d.z.object({nodeId:d.z.string().trim().min(1).max(120)}).strict();class vm{OPEN=1;readyState=this.OPEN;listeners=new Map;pingUpstream;sendToUpstream;on(e,t){const n=this.listeners.get(e)||new Set;n.add(t),this.listeners.set(e,n)}send(e){this.readyState===this.OPEN&&this.emit("message",e,!1)}sendUpstream(e){if(this.readyState===this.OPEN)try{this.sendToUpstream?.(e)}catch{this.close(1011,"Node event subscription delivery failed.")}}ping(){this.readyState===this.OPEN&&this.pingUpstream?.()}control(e,t,n){this.pingUpstream=e,this.sendToUpstream=n,t?.(()=>this.emit("pong"))}opened(){this.readyState===this.OPEN&&this.emit("open")}terminate(){this.close(1006)}close(e=1e3,t=""){this.readyState===this.OPEN&&(this.readyState=3,this.emit("close",e,Buffer.from(t)))}emit(e,...t){for(const n of this.listeners.get(e)||[])n(...t)}}function Sm(){return`req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2,10)}`}const wm=new Map;function Am(e,t){if("paired-hmac"!==e.auth.mode||!e.auth.keyId||!e.auth.secret){const e=new Error("Reverse tunnel requires paired-HMAC node auth.");throw Object.assign(e,{statusCode:401,code:"NODE_AGENT_TUNNEL_REQUIRES_PAIRED_HMAC"}),e}const n=function(e){const t=new Map;for(const[n,s]of Object.entries(e)){const e=Array.isArray(s)?s.join(","):"string"==typeof s?s:void 0===s?"":String(s);t.set(n.toLowerCase(),e)}return{nodeId:t.get("x-taskhandoff-node-id")||"",keyId:t.get("x-taskhandoff-key-id")||"",timestamp:t.get("x-taskhandoff-timestamp")||"",nonce:t.get("x-taskhandoff-nonce")||"",bodySha256:t.get("x-taskhandoff-body-sha256")||"",signature:t.get("x-taskhandoff-signature")||""}}(t.headers);if(n.nodeId!==e.id)throw Object.assign(new Error("Invalid reverse tunnel node id."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NODE_MISMATCH"});if(n.keyId!==e.auth.keyId)throw Object.assign(new Error("Invalid reverse tunnel key id."),{statusCode:401,code:"NODE_AGENT_TUNNEL_KEY_INVALID"});const i=Date.parse(n.timestamp);if(!Number.isFinite(i)||Math.abs(Date.now()-i)>wd)throw Object.assign(new Error("Reverse tunnel timestamp is outside the allowed window."),{statusCode:401,code:"NODE_AGENT_TUNNEL_TIMESTAMP_INVALID"});const r=Date.now()-wd;for(const[e,t]of wm)t<=r&&wm.delete(e);const o=`${e.id}:${n.keyId}:${n.nonce}`;if(!n.nonce||wm.has(o))throw Object.assign(new Error("Reverse tunnel nonce is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_NONCE_INVALID"});const a=kd("");if(n.bodySha256!==a)throw Object.assign(new Error("Reverse tunnel body hash is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_BODY_HASH_INVALID"});const d=t.url||`${Ad}?nodeId=${encodeURIComponent(e.id)}`,c=Td(e.auth.secret,{keyId:n.keyId,method:"GET",pathWithQuery:d,timestamp:n.timestamp,nonce:n.nonce,bodySha256:a});if(!function(e,t){const n=Buffer.from(e,"hex"),i=Buffer.from(t,"hex");return n.length===i.length&&s.timingSafeEqual(n,i)}(n.signature,c))throw Object.assign(new Error("Reverse tunnel signature is invalid."),{statusCode:401,code:"NODE_AGENT_TUNNEL_SIGNATURE_INVALID"});wm.set(o,Date.now()+wd)}function zm(e){return e?e instanceof Headers?Object.fromEntries(e.entries()):Array.isArray(e)?Object.fromEntries(e.map(([e,t])=>[e,t])):Object.fromEntries(Object.entries(e).map(([e,t])=>[e,String(t)])):{}}class km{sockets=new Map;eventSubscriptions=new Map;eventRouter;httpStreamHeaderTimeoutMs;requestTimeoutMs;auxiliaryAttachTimeoutMs;connectionRuntime;connectionOptions;constructor(e,t={}){this.eventRouter=new gm({events:e,onStreamsHello:t.onStreamsHello,onSessionEvent:t.onSessionEvent,validateInstanceScope:t.validateInstanceScope}),this.httpStreamHeaderTimeoutMs=t.httpStreamHeaderTimeoutMs??3e4,this.requestTimeoutMs=t.requestTimeoutMs??3e4,this.auxiliaryAttachTimeoutMs=t.auxiliaryAttachTimeoutMs??3e4,this.connectionRuntime=t.connectionRuntime,this.connectionOptions=t}attach(e,t){const n=this.sockets.get(e);if(n?.socket===t)return;n&&this.invalidateInstanceScope({nodeId:e});const s=new Map,i={socket:t,runtimeGeneration:this.connectionRuntime?.begin(e,"reverse-wss","handshaking"),pending:s,streams:new Map,httpStreams:new Map,pendingChannels:new Map},r=new pm({...this.connectionOptions,ping:()=>t.ping?.(),onTimeout:n=>{this.sockets.get(e)===i&&(i.failureReason=`Reverse tunnel ${n} timeout.`,void 0!==i.runtimeGeneration&&this.connectionRuntime?.update(e,i.runtimeGeneration,{phase:"suspect",error:i.failureReason}),t.terminate?t.terminate():t.close?.(1011,`Reverse tunnel ${n} timeout.`))},onStable:()=>{void 0!==i.runtimeGeneration&&this.connectionRuntime?.stable(e,i.runtimeGeneration)}});i.supervisor=r,this.sockets.set(e,i),r.start(),r.opened(),t.on?.("pong",()=>{this.sockets.get(e)===i&&(r.pong(),void 0!==i.runtimeGeneration&&this.connectionRuntime?.pong(e,i.runtimeGeneration,r.diagnostics()))}),t.on?.("close",()=>this.detach(e,t)),t.on?.("error",n=>{i.failureReason||=n instanceof Error?n.message:String(n||"Reverse tunnel transport error."),this.detach(e,t)}),n&&n.socket!==t&&this.finalizeConnection(n,new Error(`Reverse tunnel for node ${e} was replaced.`),"Reverse tunnel was replaced.",!0);const o=this.eventSubscriptions.get(e);o&&this.sendEventSubscription(e,o)}setEventSubscription(e,t){this.eventSubscriptions.set(e,t),this.sendEventSubscription(e,t)}sendEventSubscription(e,t){const n=this.sockets.get(e);if(n)try{n.socket.send(JSON.stringify({type:"control-plane.event-subscribe",aiSessionTransient:{...t.replaySince?{replaySince:t.replaySince}:{},messageDeltas:t.messageDeltas,timelineAllSessions:t.timelineAllSessions,timelineSessions:t.timelineSessions}}))}catch(t){n.failureReason=t instanceof Error?t.message:"Reverse tunnel event subscription delivery failed.",this.detach(e,n.socket);try{n.socket.close?.(1011,"Event subscription delivery failed.")}catch{}}}detach(e,t){const n=this.sockets.get(e);!n||t&&n.socket!==t||(this.sockets.delete(e),n.supervisor?.close(),void 0!==n.runtimeGeneration&&this.connectionRuntime?.disconnected(e,n.runtimeGeneration,{error:n.failureReason||"Reverse tunnel disconnected."}),this.invalidateInstanceScope({nodeId:e}),this.finalizeConnection(n,new Error(`Reverse tunnel for node ${e} disconnected.`),"Reverse tunnel disconnected.",!0))}disconnect(e,t="Node connection disabled locally."){const n=this.sockets.get(e);return!!n&&(this.detach(e,n.socket),n.socket.close?.(1e3,t),!0)}connected(e){return this.sockets.has(e)}markHealthy(e,t){const n=this.sockets.get(e);return!(!n||n.socket!==t||void 0===n.runtimeGeneration)&&(n.supervisor?.healthy(),this.connectionRuntime?.connected(e,n.runtimeGeneration)??!0)}finalizeConnection(e,t,n,s){e.supervisor?.close();for(const n of[...e.pending.keys()])this.cancelPendingRequest(e,n,t,!1);for(const[t,s]of e.streams)e.streams.delete(t),s.downstream.close(1011,n);for(const s of[...e.httpStreams.keys()])this.cancelHttpStream(e,s,t,n,!1);for(const t of e.pendingChannels.values())clearTimeout(t.timer);if(e.pendingChannels.clear(),s&&e.socket.close&&3!==e.socket.readyState)try{e.socket.close(1e3,n)}catch{}}isCurrentSocket(e,t){return this.sockets.get(e)?.socket===t}handleSocketMessage(e,t,n){if(this.isCurrentSocket(e,t))return this.sockets.get(e)?.supervisor?.activity(),this.handleMessage(e,n)}handleMessage(e,t){if(this.eventRouter.handle(e,t))return!0;if(this.handleWebSocketMessage(e,t))return!0;if("node-agent.response"!==t.type)return!1;const n="string"==typeof t.requestId?t.requestId:"",s=this.sockets.get(e),i=s?.pending.get(n);if(!i||!s)return!0;s.pending.delete(n),clearTimeout(i.timer),i.signal&&i.onAbort&&i.signal.removeEventListener("abort",i.onAbort);const r=Number(t.status)||502,o=t.headers&&"object"==typeof t.headers?t.headers:{},a="string"==typeof t.body?t.body:"";if(t.error&&"object"==typeof t.error){const e=t.error,n=new Error("string"==typeof e.message?e.message:`Reverse tunnel request failed with HTTP ${r}`);return Object.assign(n,{statusCode:r,code:"string"==typeof e.code?e.code:"NODE_AGENT_REVERSE_REQUEST_FAILED"}),i.reject(n),!0}return i.resolve(new Response(a,{status:r,headers:o})),!0}invalidateInstanceScope(e={}){this.eventRouter.invalidate(e)}instanceScopeDiagnostics(){return this.eventRouter.diagnostics()}async request(e,t,n={}){const s=this.sockets.get(e.id);if(!s){const t=new Error(`Reverse tunnel for node ${e.id} is not connected.`);throw Object.assign(t,{statusCode:503,code:"NODE_AGENT_REVERSE_TUNNEL_OFFLINE"}),t}const i=Sm(),r=$s(n.body),o={type:"control-plane.request",requestId:i,route:t,init:{method:n.method||"GET",headers:zm(n.headers),body:r}};return new Promise((r,a)=>{let d;if(d={resolve:r,reject:a,timer:setTimeout(()=>{const n=new Error(`Reverse tunnel request to ${e.id}${t} timed out.`);Object.assign(n,{statusCode:504,code:"NODE_AGENT_REVERSE_REQUEST_TIMEOUT"}),this.cancelPendingRequest(s,i,n)},this.requestTimeoutMs),signal:n.signal||void 0},n.signal&&(d.onAbort=()=>{this.cancelPendingRequest(s,i,Object.assign(new Error("Reverse tunnel request was aborted."),{name:"AbortError",code:"ABORT_ERR"}))},n.signal.addEventListener("abort",d.onAbort,{once:!0})),s.pending.set(i,d),n.signal?.aborted)d.onAbort?.();else try{s.socket.send(JSON.stringify(o))}catch(e){this.cancelPendingRequest(s,i,e instanceof Error?e:new Error(String(e)),!1)}})}cancelPendingRequest(e,t,n,s=!0){const i=e.pending.get(t);if(!i)return!1;if(e.pending.delete(t),clearTimeout(i.timer),i.signal&&i.onAbort&&i.signal.removeEventListener("abort",i.onAbort),i.reject(n),s)try{e.socket.send(JSON.stringify({type:"control-plane.request.cancel",requestId:t}))}catch{}return!0}async requestStream(e,t,n={}){const s=this.sockets.get(e.id);if(!s)throw Object.assign(new Error(`Reverse tunnel for node ${e.id} is not connected.`),{statusCode:503,code:"NODE_AGENT_REVERSE_TUNNEL_OFFLINE"});const i=Sm(),r=$s(n.body);return new Promise((o,a)=>{const d={resolve:o,reject:a,timer:setTimeout(()=>{this.cancelHttpStream(s,i,Object.assign(new Error(`Reverse tunnel stream to ${e.id}${t} timed out.`),{statusCode:504,code:"NODE_AGENT_REVERSE_STREAM_TIMEOUT"}),"Reverse HTTP stream header timeout.")},this.httpStreamHeaderTimeoutMs),settled:!1,finalized:!1,signal:n.signal||void 0};if(s.httpStreams.set(i,d),this.registerPendingChannel(s,{id:i,attach:t=>this.attachHttpStreamChannel(e.id,i,t),cancel:(e,t)=>{this.cancelHttpStream(s,i,e,t)}},"Reverse HTTP channel attach timed out."),n.signal&&(d.onAbort=()=>this.cancelHttpStream(s,i,Object.assign(new Error("Reverse HTTP stream consumer disconnected."),{name:"AbortError",code:"ABORT_ERR"}),"HTTP consumer disconnected."),n.signal.addEventListener("abort",d.onAbort,{once:!0}),n.signal.aborted))d.onAbort();else try{s.socket.send(JSON.stringify({type:"control-plane.http.open",streamId:i,route:t,init:{method:n.method||"GET",headers:zm(n.headers),body:r}}))}catch(e){this.cancelHttpStream(s,i,e instanceof Error?e:new Error(String(e)),"Reverse tunnel send failed.",!1)}})}cancelHttpStream(e,t,n,s,i=!0){const r=e.httpStreams.get(t);if(!r||r.finalized)return!1;if(r.finalized=!0,e.httpStreams.delete(t),this.removePendingChannel(e,t),clearTimeout(r.timer),r.signal&&r.onAbort&&r.signal.removeEventListener("abort",r.onAbort),r.settled?r.body?.destroy(n):(r.settled=!0,r.reject(n)),1===r.socket?.readyState&&r.socket.close(1e3,s),i)try{e.socket.send(JSON.stringify({type:"control-plane.http.cancel",streamId:t,reason:s}))}catch{}return!0}completeHttpStream(e,t){const n=e.httpStreams.get(t);return!(!n||n.finalized||(n.finalized=!0,e.httpStreams.delete(t),this.removePendingChannel(e,t),clearTimeout(n.timer),n.signal&&n.onAbort&&n.signal.removeEventListener("abort",n.onAbort),n.body?.end(),0))}attachAuxiliary(e,t,n){const s=this.sockets.get(e),i=s?.pendingChannels.get(t);return s&&i?(this.removePendingChannel(s,t),i.attach(n)):(n.close(1008,"Unknown reverse tunnel channel."),!1)}registerPendingChannel(e,t,n){this.removePendingChannel(e,t.id),t.timer=setTimeout(()=>{e.pendingChannels.get(t.id)===t&&(e.pendingChannels.delete(t.id),t.cancel(Object.assign(new Error(n),{code:"NODE_AGENT_REVERSE_CHANNEL_ATTACH_TIMEOUT"}),n))},this.auxiliaryAttachTimeoutMs),t.timer.unref?.(),e.pendingChannels.set(t.id,t)}removePendingChannel(e,t){const n=e.pendingChannels.get(t);return n?.timer&&clearTimeout(n.timer),e.pendingChannels.delete(t),n}attachHttpStream(e,t,n){return this.attachAuxiliary(e,t,n)}attachHttpStreamChannel(e,t,n){const s=this.sockets.get(e),i=s?.httpStreams.get(t);if(!s||!i)return n.close(1008,"Unknown reverse HTTP stream."),!1;i.socket=n;const r=e=>{this.cancelHttpStream(s,t,e,"Reverse HTTP stream failed.")};return n.on("message",(e,o)=>{if(i.finalized||s.httpStreams.get(t)!==i)return;if(o)return i.body?void(i.body.write(Buffer.isBuffer(e)?e:Buffer.from(e))||(n.pause?.(),i.body.once("drain",()=>n.resume?.()))):r(new Error("Reverse HTTP stream received data before response headers."));let a;try{a=JSON.parse(String(e))}catch{return void r(new Error("Reverse HTTP stream sent invalid JSON control data."))}if("node-agent.http.head"===a.type){if(i.settled)return;clearTimeout(i.timer);const e=Number(a.status)||502,n=a.headers&&"object"==typeof a.headers?a.headers:{},r=new m.PassThrough({highWaterMark:65536});return i.body=r,i.settled=!0,r.once("close",()=>{this.cancelHttpStream(s,t,new Error("Reverse HTTP stream consumer closed."),"HTTP consumer closed.")}),void i.resolve(new Response(m.Readable.toWeb(r),{status:e,headers:n}))}"node-agent.http.end"!==a.type?"node-agent.http.error"===a.type&&r(new Error("string"==typeof a.message?a.message:"Reverse HTTP stream failed.")):i.settled?this.completeHttpStream(s,t):r(new Error("Reverse HTTP stream ended before response headers."))}),n.on("close",()=>{r(new Error("Reverse HTTP stream disconnected."))}),n.on("error",()=>r(new Error("Reverse HTTP stream failed."))),!0}proxyWebSocket(e,t,n,s,i={}){const r=e.id,o=this.sockets.get(r);if(!o)return void t.close(1011,"Reverse tunnel is not connected.");const a=Sm(),d=e=>{try{o.socket.send(JSON.stringify(e))}catch{this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,"Reverse tunnel send failed.")}},c={downstream:t,pendingFrames:[]};return o.streams.set(a,c),this.registerPendingChannel(o,{id:a,attach:e=>this.attachWebSocketStreamChannel(r,a,e),cancel:(e,n)=>{this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,n)}},"Reverse websocket channel attach timed out."),d({type:"control-plane.websocket.open",streamId:a,route:n,protocols:Array.isArray(s)?s:s?[s]:[],headers:i}),t.on("message",(e,n)=>{const s=o.streams.get(a);if(s&&!s.upstream)return s.pendingFrames.length>=256?(this.removePendingChannel(o,a),o.streams.delete(a),t.close(1011,"Reverse websocket stream pending frame limit exceeded."),void d({type:"control-plane.websocket.close",streamId:a,code:1011,reason:"Reverse websocket stream pending frame limit exceeded."})):void s.pendingFrames.push({data:e,isBinary:Boolean(n)})}),t.on("close",(e,t)=>{const n=o.streams.get(a);if(n){this.removePendingChannel(o,a),o.streams.delete(a);const s=fd(e),i=yd(t);n.upstream&&Id(n.upstream,s,i),d({type:"control-plane.websocket.close",streamId:a,...void 0===s?{}:{code:s},...i?{reason:i}:{}})}}),t.on("error",()=>{const e=o.streams.get(a);e&&(this.removePendingChannel(o,a),o.streams.delete(a),e.upstream?.close(1011,"Downstream websocket failed."),d({type:"control-plane.websocket.close",streamId:a,code:1011,reason:"Downstream websocket failed."}))}),{send:e=>{const t=o.streams.get(a);t&&(t.upstream?t.upstream.send(e):t.pendingFrames.push({data:e,isBinary:!1}))}}}attachWebSocketStream(e,t,n){return this.attachAuxiliary(e,t,n)}attachWebSocketStreamChannel(e,t,n){const s=this.sockets.get(e),i=s?.streams.get(t);if(!s||!i)return n.close(1008,"Unknown reverse websocket stream."),!1;i.upstream=n;for(const e of i.pendingFrames.splice(0))n.send(e.data,{binary:e.isBinary});return vd(i.downstream,n,{pendingFrameLimit:256,onClientClose:()=>{this.removePendingChannel(s,t),s.streams.delete(t)},onClientError:()=>{this.removePendingChannel(s,t),s.streams.delete(t)},onUpstreamClose:()=>{this.removePendingChannel(s,t),s.streams.delete(t)},onUpstreamError:()=>{this.removePendingChannel(s,t),s.streams.delete(t)}}),!0}handleWebSocketMessage(e,t){const n="string"==typeof t.type?t.type:"";if(!n.startsWith("node-agent.websocket."))return!1;const s=this.sockets.get(e),i="string"==typeof t.streamId?t.streamId:"",r=s?.streams.get(i);return!r||("node-agent.websocket.close"===n?(s&&this.removePendingChannel(s,i),s?.streams.delete(i),Id(r.downstream,t.code,t.reason),!0):"node-agent.websocket.error"!==n||(s&&this.removePendingChannel(s,i),s?.streams.delete(i),r.downstream.close(1011,"string"==typeof t.message?t.message:"Reverse websocket proxy failed."),!0))}}class Tm{sockets=new Map;connectionKeys=new Map;retries=new Map;supervisors=new Map;runtimeGenerations=new Map;service;tunnel;safetyIntervalMs;logger;connectionRuntime;connectionOptions;reconnectAttempts=0;safetyReconciliations=0;timer;running=!1;transientDemand={legacyAll:!1,messageDeltas:{allInstances:!1,instanceIds:[]},timelineAllSessions:!1,timelineSessions:[]};constructor(e,t,n={}){var s;this.service=e,this.tunnel=t,this.safetyIntervalMs=(s=n.safetyIntervalMs,Math.min(6e4,Math.max(3e4,s??45e3))),this.logger=n.logger,this.connectionRuntime=n.connectionRuntime,this.connectionOptions=n}start(){this.running||(this.running=!0,this.sync(),this.timer=setInterval(()=>{this.safetyReconciliations+=1,this.sync()},this.safetyIntervalMs))}stop(){this.running=!1,this.timer&&(clearInterval(this.timer),this.timer=void 0);for(const e of this.sockets.values())e.close();for(const e of this.supervisors.values())e.close();this.sockets.clear(),this.connectionKeys.clear(),this.supervisors.clear(),this.runtimeGenerations.clear();for(const e of this.retries.values())e.timer.cancel();this.retries.clear()}syncNow(){this.sync()}setAiSessionTransientDemand(e){this.transientDemand=e;const t=JSON.stringify({v:1,type:"subscribe",aiSessionTransient:{...e.replaySince?{replaySince:e.replaySince}:{},messageDeltas:e.messageDeltas,timelineAllSessions:e.timelineAllSessions,timelineSessions:e.timelineSessions}});for(const e of this.sockets.values())e.sendUpstream(t);for(const t of this.service.listNodes())"reverse-wss"===t.connectionMode&&this.tunnel.setEventSubscription(t.id,e)}diagnostics(){return{reconnectAttempts:this.reconnectAttempts,safetyReconciliations:this.safetyReconciliations,activeConnections:this.sockets.size,pendingRetries:[...this.retries.values()].filter(e=>e.timer.pending).length,safetyIntervalMs:this.safetyIntervalMs,connections:[...this.supervisors.entries()].map(([e,t])=>({nodeId:e,...t.diagnostics()})),aiSessionTransientDemand:this.transientDemand}}sync(){const e=new Set;for(const t of this.service.listNodes()){const n=this.nodeEventConnectionKey(t);if(!n)continue;e.add(t.id);const s=this.retries.get(t.id);if(s?.timer.pending&&s.connectionKey!==n&&(s.timer.cancel(),this.retries.delete(t.id)),this.connectionKeys.get(t.id)!==n&&this.sockets.has(t.id)){const e=this.sockets.get(t.id),n=this.runtimeGenerations.get(t.id);this.supervisors.get(t.id)?.close(),this.sockets.delete(t.id),this.connectionKeys.delete(t.id),this.supervisors.delete(t.id),this.runtimeGenerations.delete(t.id),void 0!==n&&this.connectionRuntime?.disconnected(t.id,n,{error:"Direct event endpoint changed."}),e?.close()}this.sockets.has(t.id)||this.retries.get(t.id)?.timer.pending||this.connect(t,n)}for(const[t,n]of this.sockets)if(!e.has(t)){const e=this.runtimeGenerations.get(t);this.supervisors.get(t)?.close(),this.sockets.delete(t),this.connectionKeys.delete(t),this.supervisors.delete(t),this.runtimeGenerations.delete(t),void 0!==e&&this.connectionRuntime?.disconnected(t,e,{error:"Direct event connection is no longer configured."}),n.close();const s=this.retries.get(t);s?.timer.cancel(),this.retries.delete(t)}for(const[t,n]of this.retries)e.has(t)||(n.timer.cancel(),this.retries.delete(t),this.connectionKeys.delete(t))}connect(e,t){const n=new vm,s="control-plane-proxy"!==e.connectionMode?this.connectionRuntime?.begin(e.id,"direct-http","connecting"):void 0;void 0!==s&&this.runtimeGenerations.set(e.id,s);const i=this.retries.get(e.id)?.timer||new am;this.retries.set(e.id,{timer:i,connectionKey:t});const r=new pm({...this.connectionOptions,ping:()=>n.ping(),onTimeout:t=>{this.sockets.get(e.id)===n&&(void 0!==s&&this.connectionRuntime?.update(e.id,s,{phase:"suspect",error:`Direct event WebSocket ${t} timeout.`}),n.terminate())},onStable:()=>{i.reset(),void 0!==s&&this.connectionRuntime?.stable(e.id,s)}});this.sockets.set(e.id,n),this.connectionKeys.set(e.id,t),this.supervisors.set(e.id,r),r.start(),n.on("open",()=>{this.sockets.get(e.id)===n&&(r.opened(),void 0!==s&&this.connectionRuntime?.update(e.id,s,{phase:"handshaking"}))}),n.on("message",t=>{if(this.sockets.get(e.id)!==n)return;let i;try{i=JSON.parse(String(t))}catch{return}if(i&&"object"==typeof i&&!Array.isArray(i)){r.activity(),"healthy"!==r.phase&&(r.healthy(),void 0!==s&&this.connectionRuntime?.connected(e.id,s));const t=i,n="string"==typeof t.type&&t.type.startsWith("node-agent.")?t:{type:"node-agent.event.forwarded",event:t};this.tunnel.handleMessage(e.id,n)}}),n.on("pong",()=>{this.sockets.get(e.id)===n&&(r.pong(),void 0!==s&&this.connectionRuntime?.pong(e.id,s,r.diagnostics()))}),n.on("close",(t,i)=>{this.sockets.get(e.id)===n&&(r.close(),this.sockets.delete(e.id),this.connectionKeys.delete(e.id),this.supervisors.delete(e.id),this.runtimeGenerations.delete(e.id),this.scheduleReconnect(e.id,{generation:s,closeCode:"number"==typeof t?t:void 0,error:Buffer.isBuffer(i)?i.toString("utf8"):String(i||"Direct event WebSocket disconnected.")}))}),n.on("error",()=>{this.sockets.get(e.id)===n&&n.terminate()});try{n.opened();const t=this.service.resolveNodeAgentTransport(e).proxyWebSocket(e,n,"/events?aiSessionTransient=1");n.control(t&&t.ping,t&&t.onPong,t&&t.send),n.sendUpstream(JSON.stringify({v:1,type:"subscribe",aiSessionTransient:{...this.transientDemand.replaySince?{replaySince:this.transientDemand.replaySince}:{},messageDeltas:this.transientDemand.messageDeltas,timelineAllSessions:this.transientDemand.timelineAllSessions,timelineSessions:this.transientDemand.timelineSessions}}))}catch{n.close(1011,"Node event transport failed.")}}scheduleReconnect(e,t={}){const n=this.service.listNodes().find(t=>t.id===e),s=n&&this.nodeEventConnectionKey(n);if(!this.running||!n||!s)return void(void 0!==t.generation&&this.connectionRuntime?.disconnected(e,t.generation,t));const i=this.retries.get(e)??{timer:new am};if(i.timer.pending)return;i.connectionKey=s;const r=i.timer.schedule(()=>{this.running&&!this.sockets.has(e)&&this.connect(n,s)});r&&(this.reconnectAttempts+=1,void 0!==t.generation&&this.connectionRuntime?.disconnected(e,t.generation,{...t,nextRetryAt:new Date(Date.now()+r.delay).toISOString()}),this.logger?.info?.({nodeId:e,attempt:r.attempt,delay:r.delay,reconnectAttempts:this.reconnectAttempts},"session-stream.node-connection.reconnect-scheduled")),this.retries.set(e,i)}nodeEventConnectionKey(e){if(!1===e.connectionEnabled)return;if("reverse-wss"===e.connectionMode)return;const t="control-plane-proxy"===e.connectionMode?e.connectionPath:{endpoint:e.controlEndpoint||e.endpoint,auth:e.auth};return`transport:${e.connectionMode}:${kd(JSON.stringify(t))}`}}function Cm(e=function(){return process.env.TASK_HANDOFF_CONTROL_PLANE_DATA_DIR||t.join(f.homedir(),".config","task-handoff","control-plane")}()){const n=t.resolve(e);return{dataDir:n,settingsPath:t.join(n,"control-plane-settings.json"),projectsDir:t.join(n,"projects"),modelsDir:t.join(n,"models"),imagesDir:t.join(n,"images"),marketDir:t.join(n,"market"),marketCachePath:t.join(n,"market","catalog-cache.json"),marketStatePath:t.join(n,"market","catalog-state.json"),marketMigrationBackupPath:t.join(n,"market","legacy-image-migration-backup.json"),nodesDir:t.join(n,"nodes"),pendingPairingRevokesDir:t.join(n,"pending-pairing-revokes"),chatSessionsDir:t.join(n,"chat-sessions"),chatBridgesDir:t.join(n,"chat-bridges"),triggersDir:t.join(n,"triggers"),proxyAuthorityPath:t.join(n,"control-plane-proxy","authority.json"),identitySigningPath:t.join(n,"control-plane-identity-signing.json"),cloudConnectivityPath:t.join(n,"cloud-connectivity.json"),authUsersDir:t.join(n,"auth-users"),authSessionsDir:t.join(n,"auth-sessions"),aiSessionUnreadDir:t.join(n,"ai-session-unread"),logsDir:t.join(n,"logs")}}var Em,xm,Nm=function(){if(xm)return Em;xm=1;const e=n,{spawnSync:t}=v;return Em={processStartIdentity:function(n,s=process.platform){if(Number.isInteger(n)&&!(n<=0)){if("linux"===s)try{const t=e.readFileSync(`/proc/${n}/stat`,"utf8"),s=t.lastIndexOf(")");if(s<0)return;const i=t.slice(s+2).trim().split(/\s+/)[19];return i?`linux:${i}`:void 0}catch{return}if(["darwin","freebsd","openbsd","aix","sunos"].includes(s)){const e=t("ps",["-o","lstart=","-p",String(n)],{encoding:"utf8",timeout:1e3}),i=0===e.status?e.stdout.trim().replace(/\s+/g," "):"";return i?`${s}:${i}`:void 0}if("win32"===s){const e=t("powershell.exe",["-NoProfile","-NonInteractive","-Command",`(Get-Process -Id ${n} -ErrorAction Stop).StartTime.ToUniversalTime().Ticks`],{encoding:"utf8",timeout:2e3}),s=0===e.status?e.stdout.trim():"";return/^\d+$/.test(s)?`win32:${s}`:void 0}}}}}();class Rm extends Error{code;lockPath;owner;constructor(e,t,n={}){const s=t?.pid?` pid ${t.pid}`:"";super(`${n.label||"Process"} is already running${s}. Lock: ${e}`),this.name="ProcessSingletonError",this.code=n.code||"PROCESS_ALREADY_RUNNING",this.lockPath=e,this.owner=t}}function Om(e){return t.join(e,"owner.json")}function _m(e){return t.join(e,"initializing.json")}function Pm(e){return t.join(e,"recovering.json")}function jm(e){return Number.isInteger(e)&&Number(e)>0}const Dm=function(e){try{const t=JSON.parse(n.readFileSync(Om(e),"utf8"));if(jm(t.pid)&&"string"==typeof t.startTime){const e=t;return{pid:e.pid,hostname:"string"==typeof e.hostname&&e.hostname?e.hostname:f.hostname(),component:e.component||"server-update",command:"string"==typeof e.command?e.command:"",acquiredAt:"string"==typeof e.createdAt&&Number.isFinite(Date.parse(e.createdAt))?e.createdAt:new Date(0).toISOString(),token:"string"==typeof e.token&&e.token?e.token:`legacy:${e.pid}:${e.startTime}`,startIdentity:e.startTime.startsWith("linux:")?e.startTime:`linux:${e.startTime}`}}if(!(jm(t.pid)&&"string"==typeof t.hostname&&t.hostname&&"string"==typeof t.command&&"string"==typeof t.acquiredAt&&Number.isFinite(Date.parse(t.acquiredAt))&&"string"==typeof t.token&&t.token))return;return t}catch{return}};function Mm(e){if(!jm(e))return!1;try{return process.kill(Number(e),0),!0}catch(e){return"EPERM"===e.code}}function Lm(e){if(!e||!Mm(e.pid))return!1;if(!e.startIdentity)return!0;const t=Nm.processStartIdentity(e.pid);return void 0===t||t===e.startIdentity}function qm(e,s){const i=t.join(e,`.owner-${s.token}.tmp`);n.writeFileSync(i,`${JSON.stringify(s,null,2)}\n`,{encoding:"utf8",mode:384,flag:"wx"});const r=Bm(e);if(r?.token!==s.token)throw Um(i),new Error(`Process lock initialization was superseded: ${e}`);n.renameSync(i,Om(e)),Um(_m(e))}function $m(e,i,r){const o=Dm(e);if(o?.token!==i.token)return!1;const a={...i};for(const[e,t]of Object.entries(r))void 0===t?delete a[e]:Object.assign(a,{[e]:t});const d=t.join(e,`.owner-update-${i.token}-${s.randomUUID()}.tmp`);try{if(n.writeFileSync(d,`${JSON.stringify(a,null,2)}\n`,{encoding:"utf8",mode:384,flag:"wx"}),Dm(e)?.token!==i.token)return!1;n.renameSync(d,Om(e));for(const e of Object.keys(i))delete i[e];return Object.assign(i,a),!0}catch(e){if("ENOENT"===e.code)return!1;throw e}finally{Um(d)}}function Bm(e){try{return JSON.parse(n.readFileSync(_m(e),"utf8"))}catch{return}}function Fm(e){const t=Bm(e);return jm(t?.pid)&&Lm({pid:t.pid,startIdentity:t.startIdentity})}function Um(e){try{n.unlinkSync(e)}catch(e){if("ENOENT"!==e.code)throw e}}function Hm(){Atomics.wait(new Int32Array(new SharedArrayBuffer(4)),0,0,20)}function Wm(e){try{const t=Bm(e),s=Date.parse(t?.startedAt||"");return Number.isFinite(s)?Math.max(0,Date.now()-s):Math.max(0,Date.now()-n.statSync(e).mtimeMs)}catch{return 0}}function Gm(e,i){try{return n.writeFileSync(Pm(e),`${JSON.stringify({token:i,pid:process.pid,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(r){if("EEXIST"===r.code)return!!function(e){const i=Pm(e),r=Vm(i),o=Date.parse(r?.startedAt||"");if(Mm(r?.pid)||Number.isFinite(o)&&Date.now()-o<2e3)return!1;const a=t.join(e,`.recovering-${s.randomUUID()}.stale`);try{n.renameSync(i,a)}catch(e){if(["ENOENT","EEXIST"].includes(e.code||""))return!1;throw e}const d=Vm(a);if(d?.token===r?.token)return Um(a),!0;try{n.linkSync(a,i)}catch(e){if("EEXIST"!==e.code)throw e}finally{Um(a)}return!1}(e)&&Gm(e,i);if("ENOENT"===r.code)return!1;throw r}}function Vm(e){try{return JSON.parse(n.readFileSync(e,"utf8"))}catch{return}}function Km(e,t){return Vm(Pm(e))?.token===t}function Jm(){const e=process.env.TASK_HANDOFF_CONTROL_PLANE_LOCK_PATH?.trim();return e?t.resolve(e):t.join(f.tmpdir(),`task-handoff-control-plane-${process.getuid?.()??"user"}.lock`)}function Ym(e,i={}){return function(e,i={}){n.mkdirSync(t.dirname(e),{recursive:!0});const r=Nm.processStartIdentity(process.pid),o={pid:process.pid,hostname:f.hostname(),command:process.argv.join(" "),acquiredAt:(new Date).toISOString(),token:s.randomUUID(),...void 0!==i.component?{component:i.component}:{},...r?{startIdentity:r}:{},...void 0!==i.dataDir?{dataDir:i.dataDir}:{},...void 0!==i.host?{host:i.host}:{},...void 0!==i.port?{port:i.port}:{},...void 0!==i.instanceId?{instanceId:i.instanceId}:{}};for(let t=0;t<5;t+=1)try{return n.mkdirSync(e),n.writeFileSync(_m(e),`${JSON.stringify({token:o.token,pid:o.pid,startIdentity:o.startIdentity,startedAt:(new Date).toISOString()})}\n`,{encoding:"utf8",mode:384,flag:"wx"}),qm(e,o),{lockPath:e,owner:o,updateDetails:t=>$m(e,o,t),release(){const t=Dm(e);t?.token===o.token&&n.rmSync(e,{recursive:!0,force:!0})}}}catch(r){if("EEXIST"!==r.code)throw r;const o=Dm(e);if(Lm(o))throw new Rm(e,o,i.error);if(!o&&(Fm(e)||Wm(e)<(i.incompleteLockStaleMs??2e3))){if(t+1<5){Hm();continue}throw new Rm(e,void 0,i.error)}const a=s.randomUUID();if(!Gm(e,a)){if(t+1<5){Hm();continue}throw new Rm(e,Dm(e),i.error)}const d=Dm(e);if(Lm(d))throw Um(Pm(e)),new Rm(e,d,i.error);if(o?.token&&d?.token!==o.token){Um(Pm(e));continue}if(!Km(e,a))continue;n.rmSync(e,{recursive:!0,force:!0})}const a=Dm(e);throw new Rm(e,a,i.error)}(e,{...i,component:"control-plane",error:{label:"Control plane",code:"CONTROL_PLANE_ALREADY_RUNNING"}})}function Qm(e,t,n){if(function(e,t,n){return"system"===e.type||("chat-bridge"===e.type?function(e,t){return"ai-session"===t.type?["read","send-message","approve","interrupt"].includes(e):"instance"===t.type?["read","start","stop","restart"].includes(e):"read"===e}(t,n):"cloud-account"===e.type?function(e,t){return!["control-plane-settings","secret","chat-bridge"].includes(t.type)&&("node"===t.type?"read"===e:Xm(e,t))}(t,n):"admin"===e.role||("viewer"===e.role?"read"===t:"operator"===e.role&&Xm(t,n)))}(e,t,n))return;const s=new Error(`Actor is not allowed to ${t} ${n.type}${n.id?` ${n.id}`:""}.`);throw Object.assign(s,{statusCode:403,code:"CONTROL_PLANE_FORBIDDEN"}),s}function Xm(e,t){return"read"===e||("instance"===t.type?["create","update","delete","start","stop","restart","proxy"].includes(e):"ai-session"===t.type?["send-message","approve","interrupt"].includes(e):("trigger"===t.type||"runtime"===t.type)&&["create","update","delete"].includes(e))}const Zm=d.z.string().trim().min(1),eg=d.z.object({id:Zm}).strict(),tg=d.z.object({id:Zm,keyId:Zm}).strict(),ng=d.z.object({id:Zm,connectionId:Zm}).strict(),sg=d.z.object({id:Zm,runtimeId:Zm}).strict(),ig=d.z.object({id:Zm,folderId:Zm}).strict(),rg=d.z.object({id:Zm,sessionId:Zm}).strict(),og=d.z.object({id:Zm,sessionId:Zm,turnId:Zm}).strict(),ag=d.z.object({id:Zm,sessionId:Zm,messageId:Zm,attachmentId:Zm}).strict(),dg=d.z.object({id:Zm,sessionId:Zm,queueId:Zm}).strict(),cg=d.z.object({configHash:Zm}).strict(),lg=d.z.object({id:Zm,configHash:Zm}).strict(),pg=d.z.object({id:Zm,sessionId:Zm,configHash:Zm}).strict(),ug=d.z.object({path:d.z.string().optional(),depth:d.z.coerce.number().int().min(0).max(32).optional()}).strict();async function hg(e,t,n){const s=new AbortController,i=()=>s.abort(),r=()=>{t.raw.writableEnded||i()};e.raw.once("aborted",i),t.raw.once("close",r);try{return await n(s.signal)}finally{e.raw.off("aborted",i),t.raw.off("close",r)}}const mg=d.z.object({ids:d.z.array(d.z.string().trim().min(1).max(120)).default([])}).strict(),gg=d.z.object({nodeId:d.z.string().trim().min(1).max(120),modelId:d.z.string().trim().min(1).max(120).optional()}).strict(),yg=d.z.object({progressive:d.z.enum(["true","false"]).optional()}).strict(),fg=d.z.object({source:d.z.object({channel:ro,bridgeId:d.z.string().trim().min(1).max(120).optional(),chatSessionId:d.z.string().trim().min(1).max(240),userId:d.z.string().trim().max(240).optional()}).strict(),action:d.z.discriminatedUnion("type",[d.z.object({type:d.z.literal("ai-session"),index:d.z.number().int().nonnegative()}).strict(),d.z.object({type:d.z.literal("instance-app-menu"),instanceId:d.z.string().trim().min(1).max(120)}).strict(),d.z.object({type:d.z.literal("launch-app"),instanceId:d.z.string().trim().min(1).max(120),appId:d.z.string().trim().min(1).max(120)}).strict(),d.z.object({type:d.z.literal("pending-decision"),routeId:d.z.string().trim().min(1).max(120),decision:d.z.enum(["allow","deny","skip"])}).strict()])}).strict();function Ig(e){const t=fg.parse(e);if(!t.action)throw new Error("Chat gateway action is required.");return{source:t.source,action:t.action}}const bg=d.z.object({path:d.z.string().trim().max(1e3).optional(),depth:d.z.coerce.number().int().min(0).max(2).optional()}).strict(),vg=d.z.object({id:d.z.string().trim().min(1),appId:d.z.string().trim().min(1)}).strict(),Sg=d.z.object({id:d.z.string().trim().min(1),jobId:d.z.string().trim().min(1)}).strict(),wg=d.z.object({projection:d.z.literal("directory").optional(),instanceId:d.z.string().trim().min(1).max(120).optional(),progressive:d.z.enum(["true","false"]).optional()}).strict();const Ag=d.z.object({id:d.z.string().trim().min(1).max(120)}).strict(),zg=d.z.object({nodeId:d.z.string().trim().min(1).max(120),templateId:d.z.string().trim().min(1).max(120)}).strict(),kg=d.z.object({force:d.z.enum(["true","false"]).optional()}).strict(),Tg=d.z.object({projection:d.z.literal("directory").optional()}).strict(),Cg=d.z.object({progressive:d.z.enum(["true","false"]).optional()}).strict();const Eg=d.z.object({cwdFolderId:d.z.string().trim().min(1).max(120).optional()}).strict(),xg=d.z.object({appId:d.z.string().trim().min(1).max(120).default("terminal-tty"),cwdFolderId:d.z.string().trim().min(1).max(120).optional(),options:d.z.record(d.z.string(),d.z.unknown()).default({})}).strict().default({appId:"terminal-tty",options:{}}),Ng=d.z.object({title:d.z.string().trim().min(1).max(120)}).strict(),Rg=d.z.object({token:d.z.string().trim().min(1).max(512)}).strict(),Og=d.z.object({}).strict();function _g(e,t){if(!e)return t;const n=/filename\*=UTF-8''([^;]+)/i.exec(e)?.[1];if(n)try{return decodeURIComponent(n)}catch{}const s=/filename="([^"]+)"/i.exec(e)?.[1];return s||t}async function Pg(e){let t={};if(e.body)try{t=await new Response(e.body).json()}catch{}if(e.status<200||e.status>=300)throw Object.assign(new Error(t.error?.message||`Controlled instance attachment request failed with HTTP ${e.status}.`),{statusCode:e.status,code:t.error?.code||"AI_SESSION_ATTACHMENT_UPLOAD_FAILED"});return t.data}function jg(e,t,n){const s=e.safeParse(t);if(s.success)return s.data;throw Object.assign(new Error(`Controlled instance returned an invalid attachment ${n} response: ${s.error.issues.map(e=>`${e.path.join(".")||"response"}: ${e.message}`).join("; ")}`),{statusCode:502,code:"AI_SESSION_ATTACHMENT_PROTOCOL_INVALID"})}function Dg(e){const{app:t,service:i,events:r,appSessionAggregator:o,aiSessionAggregator:a,aiSessionUnread:c,chatGateway:l,aiSessionAttachments:p,aiSessionAttachmentCache:u,nodeAgentTunnel:h,nodeEventSubscriber:g,errorPayload:y}=e;!function({app:e,service:t,events:n}){e.get("/api/projects",async()=>({data:t.listProjects()})),e.post("/api/projects",async(e,s)=>{const i=t.createProject(e.body);return n.publish("project.created",{projectId:i.id}),s.code(201).send({data:i})}),e.get("/api/projects/:id",async e=>({data:t.requireProject(eg.parse(e.params).id)})),e.patch("/api/projects/:id",async e=>{const s=t.updateProject(eg.parse(e.params).id,e.body);return n.publish("project.updated",{projectId:s.id}),{data:s}}),e.delete("/api/projects/:id",async e=>{const s=eg.parse(e.params).id,i=t.deleteProject(s);return n.publish("project.deleted",{projectId:s,deleted:i}),{data:{deleted:i}}}),e.get("/api/models",async(e,n)=>hg(e,n,async n=>{const s=yg.parse(e.query);return{data:await t.listFederatedModels(n,"true"===s.progressive)}})),e.post("/api/models",async(e,s)=>{const i=await t.createModel(e.body);return n.publish("model.created",{modelId:i.id}),s.code(201).send({data:i})}),e.post("/api/models/discover",async e=>({data:await t.discoverModels(e.body)})),e.post("/api/models/test",async e=>({data:await t.testModel(e.body)})),e.post("/api/models/reorder",async e=>{const s=mg.parse(e.body),i=await t.reorderModels(s.ids);return n.publish("model.reordered",{ids:s.ids}),{data:i}}),e.get("/api/models/:id",async e=>({data:t.requireModel(eg.parse(e.params).id)})),e.patch("/api/models/:id",async e=>{const s=await t.updateModel(eg.parse(e.params).id,e.body);return n.publish("model.updated",{modelId:s.id}),{data:s}}),e.delete("/api/models/:id",async e=>{const s=eg.parse(e.params).id,i=await t.deleteModel(s);return n.publish("model.deleted",{modelId:s,deleted:i}),{data:{deleted:i}}}),e.post("/api/nodes/:nodeId/models",async(e,s)=>{const{nodeId:i}=gg.parse(e.params),r=await t.createNodeModel(i,e.body);return n.publish("model.created",{modelId:r.id,nodeId:i}),s.code(201).send({data:r})}),e.post("/api/nodes/:nodeId/models/discover",async e=>{const{nodeId:n}=gg.parse(e.params);return{data:await t.discoverNodeModels(n,e.body)}}),e.post("/api/nodes/:nodeId/models/test",async e=>{const{nodeId:n}=gg.parse(e.params);return{data:await t.testNodeModel(n,e.body)}}),e.patch("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:s,modelId:i}=gg.parse(e.params),r=await t.updateNodeModel(s,i,e.body);return n.publish("model.updated",{modelId:i,nodeId:s}),{data:r}}),e.delete("/api/nodes/:nodeId/models/:modelId",async e=>{const{nodeId:s,modelId:i}=gg.parse(e.params),r=await t.deleteNodeModel(s,i);return n.publish("model.deleted",{modelId:i,nodeId:s,deleted:r.deleted}),{data:r}}),e.get("/api/market/catalog",async()=>({data:t.getMarketCatalog()})),e.post("/api/market/refresh",async()=>{const e=await t.refreshMarketCatalog();return n.publish("market.catalog.updated",{revision:e.catalog.revision,source:e.catalog.source}),{data:e}}),e.get("/api/image-options",async()=>({data:t.listImageOptions()})),e.get("/api/images",async()=>({data:t.listImages()})),e.post("/api/images",async(e,s)=>{const i=t.createImage(e.body);return n.publish("image.created",{imageId:i.id}),s.code(201).send({data:i})}),e.get("/api/images/:id",async e=>({data:t.requireImage(eg.parse(e.params).id)})),e.patch("/api/images/:id",async e=>{const s=t.updateImage(eg.parse(e.params).id,e.body);return n.publish("image.updated",{imageId:s.id}),{data:s}}),e.delete("/api/images/:id",async e=>{const s=eg.parse(e.params).id,i=await t.deleteImage(s);return n.publish("image.deleted",{imageId:s,deleted:i}),{data:{deleted:i}}})}({app:t,service:i,events:r}),function({app:e,service:t,events:n,nodeAgentTunnel:s,nodeEventSubscriber:i,errorPayload:r}){const o=e=>{if(!e||"object"!=typeof e||Array.isArray(e)||!("target"in e))return;const t=e.target;if(!t||"object"!=typeof t||Array.isArray(t)||"controlled-instance"!==t.component)return;const n=new Error("Independent controlled-instance updates were retired; update the Node rollout instead.");throw Object.assign(n,{statusCode:404,code:"LEGACY_INSTANCE_UPDATE_RETIRED"}),n};e.get("/api/nodes",async e=>({data:"directory"===Tg.parse(e.query).projection?t.listNodes().map(e=>function(e){const t=e.proxyState?.lastError;return rc.parse({id:e.id,name:e.name,status:e.status,health:e.health,connectionMode:e.connectionMode,connectionPhase:e.connectionPhase,lastSeenAt:e.lastSeenAt,observedAt:e.updatedAt,capabilities:Object.keys(e.capabilities).sort(),error:t?{code:t.code,message:"Node connection failed. Use the desktop Control Plane for diagnostics."}:void 0})}(t.projectNodeConnection(e))):t.listPublicNodes()})),e.post("/api/nodes/local/sync",async()=>{const e=await t.syncLocalNodeConnection();return i.syncNow(),n.publish("node.local-synced",{nodeId:e.id}),{data:t.requirePublicNode(e.id)}}),e.post("/api/nodes",async(e,s)=>{const r=await t.createNode(e.body);return i.syncNow(),n.publish("node.created",{nodeId:r.id}),s.code(201).send({data:t.requirePublicNode(r.id)})}),e.post("/api/nodes/:id/check",async e=>{const s=await t.checkNode(eg.parse(e.params).id);return n.publish("node.checked",{nodeId:s.id},{topic:"node.state",scope:{nodeId:s.id}}),{data:s}}),e.get("/api/nodes/:id/updates/jobs",async e=>({data:await t.listNodeUpdateJobs(eg.parse(e.params).id)})),e.get("/api/nodes/:id/settings/external-listener",async e=>({data:await t.getLocalNodeExternalListener(eg.parse(e.params).id)})),e.patch("/api/nodes/:id/settings/external-listener",async e=>{const s=eg.parse(e.params).id,i=await t.updateLocalNodeExternalListener(s,e.body);return n.publish("node.external-listener.updated",{nodeId:s,bindScope:i.bindScope,port:i.port}),{data:i}}),e.post("/api/nodes/:id/updates/check",async e=>{o(e.body);const s=eg.parse(e.params).id,i=await t.checkNodeUpdate(s,Li.parse(e.body));return n.publish("node.update.checked",{nodeId:s,availableVersion:i.availableVersion,impact:i.impact}),{data:i}}),e.post("/api/nodes/:id/updates/apply",async(e,s)=>{o(e.body);const i=eg.parse(e.params).id,r=await t.applyNodeUpdate(i,Bi.parse(e.body));return n.publish("node.update.queued",{nodeId:i,updateJobId:r.id,desiredVersion:r.toVersion,impact:r.impact}),s.code(202).send({data:r})}),e.post("/api/nodes/:id/pairing/invites",async(e,s)=>{const i=eg.parse(e.params),r=await t.createNodePairingInvite(i.id,e.body);return n.publish("node.pairing-invite.created",{nodeId:i.id}),s.code(201).send({data:r})}),e.post("/api/nodes/:id/control-plane-connections",async e=>{const s=eg.parse(e.params),i=await t.connectNodeToControlPlane(s.id,e.body);return n.publish("node.remote-connect.requested",{nodeId:s.id}),{data:i}}),e.get("/api/nodes/:id/control-plane-pairings",async e=>{const n=eg.parse(e.params);return{data:await t.listNodeControlPlanePairings(n.id)}}),e.delete("/api/nodes/:id/control-plane-pairings/:keyId",async e=>{const s=tg.parse(e.params),i=await t.deleteNodeControlPlanePairing(s.id,s.keyId);return n.publish("node.control-plane-pairing.deleted",{nodeId:s.id,keyId:s.keyId}),{data:i}}),e.get("/api/nodes/:id/control-plane-connections",async e=>{const n=eg.parse(e.params);return{data:await t.listNodeControlPlaneConnections(n.id)}}),e.delete("/api/nodes/:id/control-plane-connections/:connectionId",async e=>{const s=ng.parse(e.params),i=await t.deleteNodeControlPlaneConnection(s.id,s.connectionId);return n.publish("node.control-plane-connection.deleted",{nodeId:s.id,connectionId:s.connectionId}),{data:i}}),e.post("/api/node-join/invites",async(e,s)=>{const i=t.createNodeJoinInvite(e.body);return n.publish("node-join.invite.created",{inviteId:i.id}),s.code(201).send({data:i})}),e.post("/api/node-join/complete",{config:em},async(e,s)=>{const r=t.completeNodeJoin(e.body);return i.syncNow(),n.publish("node.joined",{nodeId:r.id}),s.code(201).send({data:t.requirePublicNode(r.id)})}),e.get("/api/nodes/:id/runtimes",async e=>({data:await t.listNodeRuntimes(eg.parse(e.params).id)})),e.post("/api/nodes/:id/runtimes",async(e,s)=>{const i=eg.parse(e.params),r=await t.createNodeRuntime(i.id,e.body);return n.publish("node.runtime.created",{nodeId:i.id,runtimeId:r.id}),s.code(201).send({data:r})}),e.patch("/api/nodes/:id/runtimes/:runtimeId",async e=>{const s=sg.parse(e.params),i=await t.updateNodeRuntime(s.id,s.runtimeId,e.body);return n.publish("node.runtime.updated",{nodeId:s.id,runtimeId:i.id}),{data:i}}),e.delete("/api/nodes/:id/runtimes/:runtimeId",async e=>{const s=sg.parse(e.params),i=await t.deleteNodeRuntime(s.id,s.runtimeId);return n.publish("node.runtime.deleted",{nodeId:s.id,runtimeId:s.runtimeId}),{data:i}}),e.post("/api/nodes/:id/runtimes/:runtimeId/check",async e=>{const s=sg.parse(e.params),i=await t.checkNodeRuntime(s.id,s.runtimeId);return n.publish("node.runtime.checked",{nodeId:s.id,runtimeId:i.id}),{data:i}}),e.get("/api/nodes/:id/docker/images",async e=>({data:await t.listNodeDockerImages(eg.parse(e.params).id)})),e.get("/api/nodes/:id/image-options",async e=>({data:await t.listNodeImageAvailability(eg.parse(e.params).id)})),e.get("/api/nodes/:id/local-folders",async(e,n)=>hg(e,n,async n=>({data:await t.listNodeLocalFolders(eg.parse(e.params).id,n)}))),e.get("/api/nodes/:id/folders/places",async e=>({data:await t.listNodeFolderPlaces(eg.parse(e.params).id)})),e.get("/api/nodes/:id/folders/tree",async e=>{const n=eg.parse(e.params),s=ug.parse(e.query);return{data:await t.listNodeFolderTree(n.id,{path:s.path,depth:s.depth})}}),e.post("/api/nodes/:id/local-folders",async(e,s)=>{const i=eg.parse(e.params),r=await t.createNodeLocalFolder(i.id,e.body);return n.publish("node.local-folder.created",{nodeId:i.id,folderId:r.id}),s.code(201).send({data:r})}),e.patch("/api/nodes/:id/local-folders/:folderId",async e=>{const s=ig.parse(e.params),i=await t.updateNodeLocalFolder(s.id,s.folderId,e.body);return n.publish("node.local-folder.updated",{nodeId:s.id,folderId:s.folderId}),{data:i}}),e.delete("/api/nodes/:id/local-folders/:folderId",async e=>{const s=ig.parse(e.params),i=await t.deleteNodeLocalFolder(s.id,s.folderId);return n.publish("node.local-folder.deleted",{nodeId:s.id,folderId:s.folderId}),{data:i}}),e.get("/api/nodes/:id",async e=>({data:t.requirePublicNode(eg.parse(e.params).id)})),e.patch("/api/nodes/:id",async e=>{const r=t.updateNode(eg.parse(e.params).id,e.body);return r.connectionEnabled||s.disconnect(r.id),i.syncNow(),n.publish("node.updated",{nodeId:r.id}),{data:t.requirePublicNode(r.id)}}),e.delete("/api/nodes/:id",async e=>{const s=eg.parse(e.params).id,r=kg.parse(e.query),o=await t.deleteNodeWithProxyLifecycle(s,"true"===r.force);return i.syncNow(),n.publish("node.deleted",{nodeId:s,deleted:o.deleted,revoke:o.revoke}),{data:o}}),e.get("/api/node-runtimes",async(e,n)=>hg(e,n,async n=>{const s=Cg.parse(e.query),i=await t.listNodeRuntimesWithDiagnostics(n,"true"===s.progressive);return{data:i.items,meta:{nodeErrors:i.nodeErrors,nodeStates:i.nodeStates}}})),function(e){const{app:t,service:n,nodeAgentTunnel:s,errorPayload:i}=e,r=new um(s),o=e=>{if(!1===e.connectionEnabled){const e=new Error("Node agent connection is disabled locally.");throw Object.assign(e,{statusCode:409,code:"NODE_AGENT_CONNECTION_DISABLED"}),e}};t.get(Ad,{websocket:!0,config:sm},(e,t)=>{try{const s=bm.parse(t.query),i=n.requireNode(s.nodeId);Am(i,t),o(i),r.attachMain(i.id,e)}catch(t){const n=i(t);e.send(JSON.stringify({type:"control-plane.error",code:n.code,message:n.message})),e.close(1008,n.message)}}),t.get(`${Ad}/streams/:streamId`,{websocket:!0,config:sm},(e,t)=>{try{const s=bm.parse(t.query),i=n.requireNode(s.nodeId);Am(i,t),o(i);const a=t.params.streamId;r.attachAuxiliary(i.id,a,e)}catch(t){const n=i(t);e.close(1008,n.message)}}),t.get(`${Ad}/channels/:channelId`,{websocket:!0,config:sm},(e,t)=>{try{const s=bm.parse(t.query),i=n.requireNode(s.nodeId);Am(i,t),o(i);const a=t.params.channelId;r.attachAuxiliary(i.id,a,e)}catch(t){const n=i(t);e.close(1008,n.message)}}),t.get(`${Ad}/http-streams/:streamId`,{websocket:!0,config:sm},(e,t)=>{try{const s=bm.parse(t.query),i=n.requireNode(s.nodeId);Am(i,t),o(i);const a=t.params.streamId;r.attachAuxiliary(i.id,a,e)}catch(t){const n=i(t);e.close(1008,n.message)}})}({app:e,service:t,nodeAgentTunnel:s,errorPayload:r})}({app:t,service:i,events:r,nodeAgentTunnel:h,nodeEventSubscriber:g,errorPayload:y}),function({app:e,service:t,events:n}){e.get("/api/controlled-instances",async()=>({data:await t.listControlledInstances()})),e.post("/api/controlled-instances",async(e,s)=>{const i=await t.createControlledInstance(e.body);return n.publish("instance.created",{instanceId:i.id}),s.code(201).send({data:i})}),e.get("/api/controlled-instances/:id",async e=>({data:await t.requireControlledInstance(eg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/metrics",async e=>({data:await t.instanceResourceMetrics(eg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/apps/management",async e=>({data:await t.instanceAppManagement(eg.parse(e.params).id)})),e.post("/api/controlled-instances/:id/apps/:appId/install",async e=>{const n=vg.parse(e.params),s=Ei.parse(e.body||{});return{data:await t.requestInstanceAppOperation(n.id,n.appId,"install",s)}}),e.post("/api/controlled-instances/:id/apps/:appId/uninstall",async e=>{const n=vg.parse(e.params),s=Ei.parse(e.body||{});return{data:await t.requestInstanceAppOperation(n.id,n.appId,"uninstall",s)}}),e.get("/api/controlled-instances/:id/apps/jobs/:jobId",async e=>{const n=Sg.parse(e.params);return{data:await t.instanceAppManagementJob(n.id,n.jobId)}}),e.patch("/api/controlled-instances/:id",async e=>{const s=await t.updateControlledInstance(eg.parse(e.params).id,e.body);return n.publish("instance.updated",{instanceId:s.id}),{data:s}}),e.delete("/api/controlled-instances/:id",async e=>{const s=eg.parse(e.params).id,i=await t.deleteControlledInstance(s,ii.parse(e.body));return i.completed&&n.publish("instance.deleted",{instanceId:s,result:i}),{data:i}}),e.post("/api/controlled-instances/:id/start",async e=>{const s=await t.startControlledInstance(eg.parse(e.params).id);return n.publish("instance.started",{instanceId:s.id}),{data:s}}),e.post("/api/controlled-instances/:id/stop",async e=>{const s=await t.stopControlledInstance(eg.parse(e.params).id);return n.publish("instance.stopped",{instanceId:s.id}),{data:s}}),e.post("/api/controlled-instances/:id/restart",async e=>{const s=await t.restartControlledInstance(eg.parse(e.params).id);return n.publish("instance.restarted",{instanceId:s.id}),{data:s}}),e.post("/api/controlled-instances/:id/image-provisioning/retry",async e=>{const s=await t.retryControlledInstanceImageProvisioning(eg.parse(e.params).id);return n.publish("instance.image-provisioning-retried",{instanceId:s.id}),{data:s}}),e.get("/api/controlled-instances/:id/config-sync",async e=>({data:await t.instanceConfigSyncState(eg.parse(e.params).id)})),e.get("/api/controlled-instances/:id/config-sync/folders",async e=>({data:await t.listInstanceConfigSyncFolders(eg.parse(e.params).id,bg.parse(e.query))})),e.post("/api/controlled-instances/:id/config-sync",async e=>{const s=eg.parse(e.params).id,i=await t.syncInstanceConfigs(s,e.body);return n.publish("instance.config-synced",{instanceId:s}),{data:i}}),e.get("/api/instance-board",async(e,n)=>hg(e,n,async n=>{const s=wg.parse(e.query),i=await t.boardWithDiagnostics(n,"true"===s.progressive);return{data:(s.instanceId?i.items.filter(e=>e.id===s.instanceId):i.items).map(e=>"directory"===s.projection?function(e){const t=e.runtimeVersion?.error,n=e.imageProvisioning?.error,s=e.workspace.error,i=t?{code:t.code,message:"Instance runtime convergence failed. Use the desktop Control Plane for diagnostics."}:n?{code:"IMAGE_PROVISIONING_FAILED",message:"Instance image provisioning failed. Use the desktop Control Plane for diagnostics."}:s?{code:"WORKSPACE_FAILED",message:"Instance workspace preparation failed. Use the desktop Control Plane for diagnostics."}:void 0,r=e.node?.capabilities.agent,o=r&&"object"==typeof r&&!Array.isArray(r)?r:void 0,a="string"==typeof o?.protocolVersion?o.protocolVersion:void 0,d=!a||a===ks,c=[e.protocolCompatible?void 0:`Instance protocol ${e.protocolVersion||"unknown"} differs from this Control Plane.`,d?void 0:`Node protocol ${a} differs from this Control Plane.`].filter(e=>Boolean(e)),l="running"===e.status||"online"===e.connectionStatus||"reachable"===e.access.status,p=!["failed","stopped","stopping","unhealthy"].includes(e.status)&&"online"!==e.connectionStatus&&["provisioning","starting","registering","registered"].includes(e.status),u=[l||["provisioning","starting","registering","registered","stopping"].includes(e.status)?void 0:"start",["failed","stopped","stopping","unhealthy"].includes(e.status)||!l&&!p?void 0:"stop",l?"restart":void 0,"failed"===e.status&&"failed"===e.imageProvisioning?.phase?"retry-image":void 0].filter(e=>Boolean(e));return ac.parse({id:e.id,name:e.name,nodeId:e.nodeId,status:e.status,health:e.health,connectionStatus:e.connectionStatus,ready:e.ready,capabilities:{aiSessionTimeline:e.capabilities.features.aiSessionTimeline,aiSessionConversationAttachments:e.capabilities.features.aiSessionConversationAttachments},config:{defaultCodexPermissionMode:e.config.defaultCodexPermissionMode},lastHeartbeatAt:e.lastHeartbeatAt,heartbeatAgeMs:e.heartbeatAgeMs,observedAt:e.updatedAt,runtime:{id:e.runtimeId,name:e.runtime?.name,type:e.runtime?.type},workspace:{status:e.workspace.status,path:e.workspace.path},protocol:{version:e.protocolVersion,compatible:e.protocolCompatible&&d,warning:c.length?c.join(" "):void 0},aiSessions:e.aiSessions,availableActions:u,availableApps:(e.appInventory?.items||[]).filter(e=>"available"===e.availability).map(e=>({id:e.id,name:e.name,kind:e.kind,supportsCwdSelection:e.capabilities.supportsCwdSelection})),availableAgents:(e.appInventory?.items||[]).filter(e=>"available"===e.availability&&("codex"===e.id||"claude"===e.id)).map(e=>({id:e.id,name:e.name,kind:e.kind,supportsCwdSelection:e.capabilities.supportsCwdSelection})),error:i})}(e):e),meta:{nodeErrors:i.nodeErrors,nodeStates:i.nodeStates}}}))}({app:t,service:i,events:r}),function(e,t,n){e.get("/api/nodes/:id/environment-templates",async e=>({data:await t.listEnvironmentTemplates(Ag.parse(e.params).id)})),e.get("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const n=zg.parse(e.params);return{data:await t.getEnvironmentTemplate(n.nodeId,n.templateId)}}),e.post("/api/controlled-instances/:id/environment-templates",async(e,s)=>{const i=Ag.parse(e.params).id,r=await t.createEnvironmentTemplate(i,e.body);return n.publish("environment-template.updated",{templateId:r.id,nodeId:r.nodeId,status:r.status}),s.code(201).send({data:r})}),e.delete("/api/nodes/:nodeId/environment-templates/:templateId",async e=>{const s=zg.parse(e.params),i=await t.deleteEnvironmentTemplate(s.nodeId,s.templateId);return n.publish("environment-template.deleted",i),{data:i}})}(t,i,r),function({app:e,service:t,events:i,appSessionAggregator:r,aiSessionAggregator:o,aiSessionUnread:a,aiSessionAttachments:c,aiSessionAttachmentCache:l}){e.get("/api/app-sessions",async e=>{const t=d.z.object({refresh:d.z.string().optional(),instanceId:d.z.string().trim().min(1).optional(),streamId:d.z.string().trim().min(1).optional(),sinceRevision:d.z.string().optional()}).parse(e.query||{});if(void 0!==t.sinceRevision){const e=Number(t.sinceRevision);if(!Number.isInteger(e)||e<0){const e=new Error("sinceRevision must be a non-negative integer.");throw Object.assign(e,{statusCode:400,code:"APP_SESSION_DELTA_INVALID"}),e}if(!t.streamId){const e=new Error("streamId is required with sinceRevision.");throw Object.assign(e,{statusCode:400,code:"APP_SESSION_DELTA_INVALID"}),e}return{data:await r.delta({instanceId:t.instanceId,streamId:t.streamId,sinceRevision:e})}}const n=await r.list({refresh:"true"===t.refresh||"1"===t.refresh});return{data:t.instanceId?{...n,instances:n.instances.filter(e=>e.instanceId===t.instanceId)}:n}}),e.post("/api/controlled-instances/:id/apps/sessions",async e=>{const n=eg.parse(e.params),s=xg.parse(e.body),r=await t.launchAppSession(n.id,s.appId,{...s.options,...s.cwdFolderId?{cwdFolderId:s.cwdFolderId}:{}});return i.publish("instance.app-session.launched",{instanceId:n.id,sessionId:"string"==typeof r.id?r.id:void 0,appId:s.appId}),{data:r}}),e.post("/api/controlled-instances/:id/apps/sessions/:sessionId/stop",async e=>{const n=rg.parse(e.params),s=await t.stopAppSession(n.id,n.sessionId);return i.publish("instance.app-session.stopped",{instanceId:n.id,sessionId:n.sessionId}),{data:s}}),e.patch("/api/controlled-instances/:id/apps/sessions/:sessionId",async e=>{const n=rg.parse(e.params),s=Ng.parse(e.body),r=await t.renameAppSession(n.id,n.sessionId,s.title);return i.publish("instance.app-session.renamed",{instanceId:n.id,sessionId:n.sessionId,title:s.title}),{data:r}}),e.post("/api/controlled-instances/:id/apps/sessions/:sessionId/access",async e=>{const n=rg.parse(e.params);Og.parse(e.body||{});const s=await t.createAppSessionAccessToken({instanceId:n.id,sessionId:n.sessionId});return{data:{mode:s.mode,url:`/apps/access/${s.mode}?token=${encodeURIComponent(s.token)}`,token:s.token,expiresAt:s.expiresAt}}}),e.delete("/api/controlled-instances/:id/apps/sessions/:sessionId/access",async e=>{const n=rg.parse(e.params),s=Rg.parse(e.body||{});return t.revokeAppSessionAccessToken(s.token,{instanceId:n.id,sessionId:n.sessionId}),{data:{revoked:!0}}}),e.get("/api/controlled-instances/:id/app-sessions",async e=>{const t=eg.parse(e.params),n=(await r.list()).instances.find(e=>e.instanceId===t.id);return{data:n?.appSessions||{runningCount:0,problemCount:0,sessions:[],updatedAt:(new Date).toISOString()}}}),e.get("/api/controlled-instances/:id/ai-sessions/history",async e=>{const n=eg.parse(e.params);return{data:await t.listAiSessionHistory(n.id)}}),e.get("/api/controlled-instances/:id/ai-sessions/history/:sessionId",async e=>{const n=rg.parse(e.params);return{data:await t.getAiSessionHistoryDetail(n.id,n.sessionId)}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId",async e=>{const n=rg.parse(e.params);return{data:await t.getAiSessionDetail(n.id,n.sessionId)}}),e.post("/api/controlled-instances/:id/ai-session-attachments/drafts",{bodyLimit:22020096},async(e,n)=>{const i=eg.parse(e.params),r=H.parse(e.query),o=`cia_${s.randomUUID().replace(/-/g,"").slice(0,24)}`,a="/api/ai-session-attachments/draft-streams",d=new AbortController,p=()=>d.abort();e.raw.once("aborted",p),n.raw.once("close",p);const u=l.beginBestEffortWrite({instanceId:i.id,scopeType:r.scopeType,scopeId:r.scopeId,attachmentId:o,kind:r.kind,name:r.name,mime:r.mime,size:r.size,cacheUntil:Date.now()+864e5});let h=0;try{const s=jg(V,await Pg(await t.proxyInstanceHttp(i.id,a,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(G.parse({attachmentId:o,...r})),signal:d.signal})),"start");if(s.attachmentId!==o||0!==s.offset)throw Object.assign(new Error("Controlled instance returned an invalid attachment upload offset."),{statusCode:502,code:"AI_SESSION_ATTACHMENT_OFFSET_MISMATCH"});for await(const n of e.body){const e=Buffer.isBuffer(n)?n:Buffer.from(n);for(let n=0;n<e.length;n+=O){const s=e.subarray(n,Math.min(n+O,e.length));u?.offer(s);const r=jg(V,await Pg(await t.proxyInstanceHttp(i.id,`${a}/${encodeURIComponent(o)}?offset=${h}`,{method:"PUT",headers:{"content-type":"application/octet-stream","content-length":String(s.length)},body:s,signal:d.signal})),"chunk"),c=h+s.length;if(r.attachmentId!==o||r.offset!==c)throw Object.assign(new Error("Controlled instance returned an invalid attachment upload offset."),{statusCode:502,code:"AI_SESSION_ATTACHMENT_OFFSET_MISMATCH"});h=r.offset}}const c=jg(K,await Pg(await t.proxyInstanceHttp(i.id,`${a}/${encodeURIComponent(o)}/complete`,{method:"POST",headers:{"content-type":"application/json"},body:"{}",signal:d.signal})),"completion");return u?.finish(),n.code(201).send({data:c})}catch(s){if(u?.abort(),t.proxyInstanceHttp(i.id,`${a}/${encodeURIComponent(o)}`,{method:"DELETE"}).catch(()=>{}),0===h&&s&&"object"==typeof s&&"statusCode"in s&&404===s.statusCode&&(!("code"in s)||"AI_SESSION_NOT_FOUND"!==s.code)){const t=[];let s=0;for await(const n of e.body){const e=Buffer.isBuffer(n)?n:Buffer.from(n);if(s+=e.length,s>r.size)throw Object.assign(new Error("Attachment content exceeded its declared size."),{statusCode:400,code:"AI_SESSION_ATTACHMENT_SIZE_MISMATCH"});t.push(e)}if(s!==r.size)throw Object.assign(new Error("Attachment content did not match its declared size."),{statusCode:400,code:"AI_SESSION_ATTACHMENT_SIZE_MISMATCH"});return n.code(201).send({data:c.upload({instanceId:i.id,sessionId:r.scopeId,kind:r.kind,name:r.name,mime:r.mime,data:Buffer.concat(t).toString("base64")})})}throw s}finally{e.raw.off("aborted",p),n.raw.off("close",p)}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/messages/:messageId/attachments/:attachmentId/content",async(e,s)=>{const i=ag.parse(e.params),r=l.get({instanceId:i.id,sessionId:i.sessionId,messageId:i.messageId,attachmentId:i.attachmentId});if(r)return s.header("Content-Type",r.mime),s.header("Content-Length",String(r.size)),r.etag&&s.header("ETag",r.etag),s.header("Cache-Control","private, max-age=0, must-revalidate"),s.header("X-Content-Type-Options","nosniff"),s.header("Accept-Ranges","none"),s.header("Content-Disposition",r.disposition||`${"image"===r.kind?"inline":"attachment"}; filename*=UTF-8''${encodeURIComponent(r.name)}`),r.etag&&e.headers["if-none-match"]===r.etag?s.code(304).send():s.send(n.createReadStream(r.path));const o=new AbortController;s.raw.once("close",()=>o.abort());const a=await t.proxyInstanceHttp(i.id,`/api/ai-sessions/${encodeURIComponent(i.sessionId)}/messages/${encodeURIComponent(i.messageId)}/attachments/${encodeURIComponent(i.attachmentId)}/content`,{method:"GET",signal:o.signal}),d=a.headers["x-task-handoff-attachment-cache-until"],c=a.headers["x-task-handoff-attachment-size"];for(const[e,t]of Object.entries(a.headers))["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade","x-task-handoff-attachment-cache-until","x-task-handoff-attachment-size"].includes(e.toLowerCase())||s.header(e,t);if(!a.body)return s.code(a.status).send();const p=m.Readable.fromWeb(a.body),u=Number(c||a.headers["content-length"]);200===a.status&&Number.isInteger(u)&&u>0&&s.header("Content-Length",String(u));const h=Number(d),g=a.headers["content-type"]||"application/octet-stream",y=a.headers["content-disposition"],f=200===a.status&&Number.isInteger(u)&&u>0&&Number.isFinite(h)?l.beginBestEffortWrite({instanceId:i.id,scopeType:"session",scopeId:i.sessionId,attachmentId:i.attachmentId,sessionId:i.sessionId,messageId:i.messageId,kind:J(g)?"image":"file",name:_g(y,i.attachmentId),mime:g,size:u,...y?{disposition:y}:{},...a.headers.etag?{etag:a.headers.etag}:{},cacheUntil:h}):void 0,I=new m.Transform({transform(e,t,n){f?.offer(e),n(null,e)},flush(e){f?.finish(),e()}});return s.raw.once("close",()=>{p.destroy(),p.readableEnded||f?.abort()}),s.code(a.status).send(p.pipe(I))}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/timeline",async e=>{const n=rg.parse(e.params);return{data:await t.getAiSessionTimeline(n.id,n.sessionId)}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/turns/:turnId/timeline",async e=>{const n=og.parse(e.params);return{data:await t.getAiSessionTurnTimeline(n.id,n.sessionId,n.turnId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/resume",async e=>{const n=rg.parse(e.params);Og.parse(e.body||{});const s=await t.resumeAiSession(n.id,n.sessionId);return i.publish("instance.ai-session.resumed",{instanceId:n.id,sessionId:s.aiSessionId,providerSessionId:s.providerSessionId,appSessionId:s.appSessionId,disposition:s.disposition}),{data:s}}),e.get("/api/controlled-instances/:id/ai-sessions/workspace",async e=>{const n=eg.parse(e.params),s=Eg.parse(e.query||{});return{data:await t.inspectAiSessionWorkspace(n.id,s.cwdFolderId)}}),e.post("/api/controlled-instances/:id/ai-sessions",async e=>{const n=eg.parse(e.params),s=Be.parse(e.body||{}),r=s.attachments.filter(e=>"upload-ref"!==e.source.type||!e.id.startsWith("cia_")),o=c.resolveRefs(r,n.id,s.clientRequestId),a=new Map(o.map(e=>[e.id,e])),d=s.attachments.map(e=>"upload-ref"===e.source.type&&e.id.startsWith("cia_")?e:a.get(e.id)).filter(Boolean),p=await t.createAiSession(n.id,{...s,attachments:d}),u=new Set(s.attachments.filter(e=>"upload-ref"===e.source.type&&e.id.startsWith("cia_")).map(e=>e.id));if(u.size){const e=(await t.requireControlledInstance(n.id,!0)).config.aiSessionAttachmentRetentionDays??30;t.getAiSessionDetail(n.id,p.aiSessionId).then(t=>{const i=t.turns?.flatMap(e=>e.userMessages||[]).find(e=>e.attachments.some(e=>u.has(e.id)))?.id;if(i)for(const t of u)l.bind({instanceId:n.id,attachmentId:t,scopeId:s.clientRequestId,sessionId:p.aiSessionId,messageId:i,cacheUntil:Date.now()+24*e*60*60*1e3})}).catch(()=>{})}return i.publish("instance.ai-session.created",{instanceId:n.id,sessionId:p.aiSessionId,providerSessionId:p.providerSessionId,clientRequestId:s.clientRequestId}),{data:p}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/open-app",async e=>{const n=rg.parse(e.params),s=Ge.parse(e.body||{}),r=await t.openAiSessionApp(n.id,n.sessionId,s.clientRequestId);return i.publish("instance.ai-session.app-opened",{instanceId:n.id,sessionId:n.sessionId,appSessionId:r.appSessionId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/fork",async e=>{const n=rg.parse(e.params),s=He.parse(e.body||{}),r=await t.forkAiSession(n.id,n.sessionId,s);return i.publish("instance.ai-session.forked",{instanceId:n.id,sourceSessionId:n.sessionId,sessionId:r.aiSessionId,providerSessionId:r.providerSessionId,clientRequestId:s.clientRequestId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/close",async e=>{const n=rg.parse(e.params),s=Ke.parse(e.body||{}),r=await t.closeAiSession(n.id,n.sessionId,s.clientRequestId);return i.publish("instance.ai-session.closed",{instanceId:n.id,sessionId:n.sessionId,providerSessionId:r.providerSessionId}),{data:r}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/messages",async(e,n)=>{const s=performance.now(),r=function(e,t){const n=Array.isArray(e)?e[0]:e,s="string"==typeof n?n.trim():"";return/^[A-Za-z0-9._:-]{1,128}$/.test(s)?s:t}(e.headers[ba],String(e.id));let o;const a=t=>{const i=performance.now()-s,a=Sa(o?.serverTiming,va("control_plane",i));n.header(ba,r),n.header("server-timing",a),e.log.info({traceId:r,instanceId:e.params.id,sessionId:e.params.sessionId,outcome:t,controlPlaneMs:i,nodeTransportMs:o?.nodeTransportMs,serverTiming:a},"AI session message request timing")},d=rg.parse(e.params),p=Me.parse(e.body||{}),u=p.attachments.filter(e=>"upload-ref"!==e.source.type||!e.id.startsWith("cia_")),h=c.resolveRefs(u,d.id,d.sessionId),m=new Map(h.map(e=>[e.id,e])),g=p.attachments.map(e=>"upload-ref"===e.source.type&&e.id.startsWith("cia_")?e:m.get(e.id)).filter(Boolean);let y;try{y=await t.sendAiSessionMessage(d.id,d.sessionId,p.message,p.mode,g,p.references,p.permissionMode,{traceId:r,onTiming:e=>{o=e}})}catch(e){throw a("failed"),e}const f=new Set(p.attachments.filter(e=>"upload-ref"===e.source.type&&e.id.startsWith("cia_")).map(e=>e.id)),I=y.session.turns?.flatMap(e=>e.userMessages||[]).find(e=>e.attachments.some(e=>f.has(e.id)))?.id||y.session.queue.items.find(e=>e.id===y.queueId)?.messageId;if(f.size&&I){const e=(await t.requireControlledInstance(d.id,!0)).config.aiSessionAttachmentRetentionDays??30,n=Date.now()+24*e*60*60*1e3;for(const e of f)l.bind({instanceId:d.id,attachmentId:e,scopeId:d.sessionId,sessionId:d.sessionId,messageId:I,cacheUntil:n})}return i.publish("instance.ai-session.message-sent",{instanceId:d.id,sessionId:d.sessionId}),a("completed"),{data:y}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/mentions",async e=>{const n=rg.parse(e.params);return{data:await t.aiSessionMentionCatalog(n.id,n.sessionId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/mentions/files",async e=>{const n=rg.parse(e.params),s=_e.parse(e.body||{});return{data:await t.searchAiSessionMentionFiles(n.id,n.sessionId,s.query)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/commands",async e=>{const n=rg.parse(e.params),s=ze.parse(e.body||{}),r=await t.executeAiSessionCommand(n.id,n.sessionId,s);return i.publish("instance.ai-session.command-executed",{instanceId:n.id,sessionId:n.sessionId,command:s.command}),{data:r}}),e.get("/api/controlled-instances/:id/ai-sessions/:sessionId/queue",async e=>{const n=rg.parse(e.params);return{data:await t.aiSessionQueue(n.id,n.sessionId)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId/steer",async e=>{const n=dg.parse(e.params),s=await t.steerAiSessionQueuedMessage(n.id,n.sessionId,n.queueId);return i.publish("instance.ai-session.message-sent",{instanceId:n.id,sessionId:n.sessionId}),{data:s}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId/retry",async e=>{const n=dg.parse(e.params);return{data:await t.retryAiSessionQueuedMessage(n.id,n.sessionId,n.queueId)}}),e.delete("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId",async e=>{const n=dg.parse(e.params);return{data:await t.removeAiSessionQueuedMessage(n.id,n.sessionId,n.queueId)}}),e.patch("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/:queueId",async e=>{const n=dg.parse(e.params),s=Xe.parse(e.body||{});return{data:await t.editAiSessionQueuedMessage(n.id,n.sessionId,n.queueId,s)}}),e.patch("/api/controlled-instances/:id/ai-sessions/:sessionId/queue/reorder",async e=>{const n=rg.parse(e.params),s=Qe.parse(e.body||{});return{data:await t.reorderAiSessionQueuedMessages(n.id,n.sessionId,s)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/interrupt",async e=>{const n=rg.parse(e.params),s=await t.interruptAiSession(n.id,n.sessionId);return i.publish("instance.ai-session.interrupted",{instanceId:n.id,sessionId:n.sessionId}),{data:s}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/approval",async e=>{const n=rg.parse(e.params),s=Ye.parse(e.body||{}),r=await t.resolveAiSessionApproval(n.id,n.sessionId,s.decision);return i.publish("instance.ai-session.approval-resolved",{instanceId:n.id,sessionId:n.sessionId,decision:s.decision}),{data:r}}),e.get("/api/ai-sessions",async(e,t)=>{const n=e.query;if(void 0!==n.sinceRevision){const e=Number(n.sinceRevision);if(!Number.isInteger(e)||e<0)return t.code(400).send({error:"invalid_since_revision"});try{return n.streamId?{data:await o.delta({instanceId:n.instanceId,streamId:n.streamId,sinceRevision:e})}:t.code(400).send({error:"stream_id_required"})}catch(e){if("AI_SESSION_DELTA_INSTANCE_ID_REQUIRED"===e.message)return t.code(400).send({error:"instance_id_required"});throw e}}const s=await o.list({refresh:"true"===n.refresh||"1"===n.refresh}),i=n.instanceId?{...s,instances:s.instances.filter(e=>e.instanceId===n.instanceId)}:s;for(const e of i.instances)a.reconcile(e.instanceId,e.aiSessions);return{data:{...i,instances:i.instances.map(e=>({...e,aiSessions:a.decorate(e.instanceId,e.aiSessions)}))}}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/read",async(e,t)=>{const n=rg.parse(e.params),s=d.z.object({sessionUpdatedAt:d.z.string().datetime()}).strict().parse(e.body||{}),r=(await o.list()).instances.find(e=>e.instanceId===n.id),c=r?.aiSessions.sessions.find(e=>e.id===n.sessionId);if(!r||!c)return t.code(404).send({error:{code:"AI_SESSION_NOT_FOUND",message:"AI session was not found."}});a.reconcile(n.id,r.aiSessions);const l=a.markRead(n.id,n.sessionId,s.sessionUpdatedAt);return l?(i.publish(q,l,{topic:"ai.sessions",scope:{instanceId:n.id,sessionId:n.sessionId}}),{data:l}):t.code(404).send({error:{code:"AI_SESSION_NOT_FOUND",message:"AI session was not found."}})})}({app:t,service:i,events:r,appSessionAggregator:o,aiSessionAggregator:a,aiSessionUnread:c,aiSessionAttachments:p,aiSessionAttachmentCache:u}),function({app:e,service:t,events:n}){e.get("/api/triggers",async()=>({data:await t.listTriggers()})),e.post("/api/triggers",async(e,s)=>{const i=t.createTrigger(e.body);return n.publish("trigger.created",{configHash:i.configHash}),s.code(201).send({data:i})}),e.put("/api/triggers/:configHash",async e=>{const s=cg.parse(e.params),i=await t.updateTrigger(s.configHash,e.body);return n.publish("trigger.updated",{previousConfigHash:s.configHash,configHash:i.trigger.configHash}),{data:i}}),e.delete("/api/triggers/:configHash",async e=>{const s=cg.parse(e.params),i=await t.deleteTrigger(s.configHash);return n.publish("trigger.deleted",{configHash:s.configHash}),{data:i}}),e.post("/api/triggers/:configHash/apply",async e=>{const s=cg.parse(e.params),i=await t.applyTrigger(s.configHash,e.body||{});return n.publish("trigger.applied",{configHash:s.configHash}),{data:i}}),e.get("/api/controlled-instances/:id/triggers",async e=>{const n=eg.parse(e.params);return{data:await t.listInstanceTriggers(n.id)}}),e.post("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers",async e=>{const s=rg.parse(e.params),i=await t.bindAiSessionTrigger(s.id,s.sessionId,e.body||{});return n.publish("trigger.deployment.bound",{instanceId:s.id,sessionId:s.sessionId},{topic:"triggers",scope:{instanceId:s.id}}),{data:i}}),e.delete("/api/controlled-instances/:id/ai-sessions/:sessionId/triggers/:configHash",async e=>{const s=pg.parse(e.params),i=await t.unbindAiSessionTrigger(s.id,s.sessionId,s.configHash);return n.publish("trigger.deployment.unbound",{instanceId:s.id,sessionId:s.sessionId,configHash:s.configHash},{topic:"triggers",scope:{instanceId:s.id}}),{data:i}}),e.post("/api/controlled-instances/:id/triggers/:configHash/run",async e=>{const s=lg.parse(e.params),i=await t.runInstanceTrigger(s.id,s.configHash,e.body||{});return n.publish("trigger.run.requested",{instanceId:s.id,configHash:s.configHash},{topic:"triggers",scope:{instanceId:s.id}}),{data:i}})}({app:t,service:i,events:r}),function({app:e,service:t,chatGateway:n}){e.get("/api/chat/sessions",async()=>({data:t.listChatSessions()})),e.get("/api/chat/sessions/:id",async e=>({data:t.requireChatSession(eg.parse(e.params).id)})),e.get("/api/chat-gateway/status",async()=>({data:n.status()})),e.post("/api/chat-gateway/poll-ai-sessions",async()=>({data:await n.pollAiSessionsNow()})),e.get("/api/chat-gateway/bridges",async()=>({data:t.listChatBridges()})),e.post("/api/chat-gateway/bridges",async e=>({data:t.createChatBridge(e.body)})),e.patch("/api/chat-gateway/bridges/:id",async s=>{const i=eg.parse(s.params).id,r=t.requireChatBridge(i),o=Nc.parse(s.body),a=t.updateChatBridge(i,s.body),d="boolean"==typeof o.enabled?o.enabled:void 0;return e.log.info({component:"control-plane-chat-gateway",action:"bridge-patch",bridgeId:i,hasEnabled:void 0!==d,requestedEnabled:d,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(i).enabled},"chat gateway bridge state changed"),void 0!==d&&d!==r.enabled&&(d?n.startBridge(i):n.stopBridge(i)),{data:a}}),e.post("/api/chat-gateway/bridges/:id/start",async s=>{const i=eg.parse(s.params).id,r=t.requireChatBridge(i);return t.updateChatBridge(i,{enabled:!0}),e.log.info({component:"control-plane-chat-gateway",action:"bridge-start-request",bridgeId:i,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(i).enabled},"chat gateway bridge state changed"),{data:n.startBridge(i)}}),e.post("/api/chat-gateway/bridges/:id/stop",async s=>{const i=eg.parse(s.params).id,r=t.requireChatBridge(i);return t.updateChatBridge(i,{enabled:!1}),e.log.info({component:"control-plane-chat-gateway",action:"bridge-stop-request",bridgeId:i,previousEnabled:r.enabled,updatedEnabled:t.requireChatBridge(i).enabled},"chat gateway bridge state changed"),{data:n.stopBridge(i)}}),e.delete("/api/chat-gateway/bridges/:id",async e=>{const s=eg.parse(e.params).id;return n.stopBridge(s),{data:{deleted:t.deleteChatBridge(s)}}}),e.post("/api/chat-gateway/messages",{bodyLimit:67108864},async e=>({data:await t.handleChatGatewayMessage(co.parse(e.body))})),e.post("/api/chat-gateway/actions",async e=>({data:await t.handleChatGatewayAction(Ig(e.body))})),e.get("/api/pending-routes",async()=>({data:await t.listPendingRoutes()}))}({app:t,service:i,chatGateway:l})}const Mg=new Set(["connection","content-length","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]);function Lg(e){const t=Object.entries(e).find(([e])=>"sec-websocket-protocol"===e.toLowerCase()),n=t?.[1],s=(Array.isArray(n)?n.join(","):"string"==typeof n?n:"").split(",").map(e=>e.trim()).filter(Boolean);return s.length?s:void 0}const qg=new Set(["content-encoding"]),$g=new Set(["host",...E]);function Bg(e){return Object.fromEntries(Object.entries(e).flatMap(([e,t])=>{const n=e.toLowerCase();if(Mg.has(n)||"authorization"===n||void 0===t)return[];const s=Array.isArray(t)?t.join(", "):String(t);if("cookie"!==n)return[[e,s]];const i=function(e){return e.split(";").map(e=>e.trim()).filter(e=>e&&e.slice(0,e.indexOf("=")).trim()!==qo).join("; ")}(s);return i?[[e,i]]:[]}))}function Fg(e){return function(e,t={}){return Object.fromEntries(Object.entries(e).flatMap(([e,n])=>{const s=e.toLowerCase();return void 0===n||t.blockedHeaders?.has(s)||s.startsWith("sec-websocket-")&&"sec-websocket-origin"!==s?[]:[[e,Array.isArray(n)?n.join(", "):String(n)]]}))}(Bg(e),{blockedHeaders:$g})}function Ug(e,t,n,s,i={}){const r=new AbortController;return t.raw.once("close",()=>r.abort()),e.proxyInstanceHttp(n,s,{...i,signal:r.signal})}function Hg(e,t,n){for(const[n,s]of Object.entries(t.headers)){const t=n.toLowerCase();Mg.has(t)||qg.has(t)||e.header(n,s)}if(!t.body)return e.code(t.status).send();const s=m.Readable.fromWeb(t.body);return e.raw.once("close",()=>s.destroy()),e.code(t.status).send(n?s.pipe(n):s)}function Wg(e){return`/instances/${encodeURIComponent(e)}`}function Gg(e,t,n,s){const i=function(e,t){const n=e.split("?",1)[0]||"/";return t.toLowerCase().includes("text/html")&&!n.startsWith("/api/")}(s,Object.entries(t.headers).find(([e])=>"content-type"===e.toLowerCase())?.[1]||"")?function(e){const t=[];let n=0,s=!1;const i=(i,r=!1)=>{if(s)return;const o=Buffer.concat(t,n).toString("utf8");!/<head(\s[^>]*)?>/i.exec(o)&&!r&&n<65536||(s=!0,i.push(function(e,t){if(e.includes("__TASK_HANDOFF_PUBLIC_BASE__"))return e;const n=`<script>window.__TASK_HANDOFF_PUBLIC_BASE__=${JSON.stringify(t)};<\/script>`;return/<head(\s[^>]*)?>/i.test(e)?e.replace(/<head(\s[^>]*)?>/i,e=>`${e}\n${n}`):`${n}\n${e}`}(o,e)),t.length=0,n=0)};return new m.Transform({transform(e,r,o){s?this.push(e):(t.push(Buffer.from(e)),n+=e.length,i(this)),o()},flush(e){i(this,!0),e()}})}(Wg(n)):void 0;return Hg(e,t,i)}function Vg(e){return Buffer.isBuffer(e)?e:e instanceof Uint8Array?Buffer.from(e):e instanceof URLSearchParams?e.toString():"string"==typeof e?e:null==e?void 0:JSON.stringify(e)}function Kg(e,t){if("string"!=typeof t||!e.hasContentTypeParser(t))try{e.addContentTypeParser(t,{parseAs:"buffer"},(e,t,n)=>n(null,t))}catch(e){if(e instanceof Error&&/Content type parser .* already present/i.test(e.message))return;throw e}}function Jg(e){return new URL(e,"http://control-plane.local").searchParams.get("token")||""}function Yg(e,t,n){const s=encodeURIComponent(e),i=encodeURIComponent(t),r=`apps/access/vnc/${s}/proxy`,o=n.vnc&&"object"==typeof n.vnc?n.vnc:{};return"kasmvnc"===("string"==typeof o.backend?o.backend:"")?`/${r}/api/apps/sessions/${i}/web/`:`/${r}/api/novnc/vnc.html?path=${encodeURIComponent(`${r}/api/apps/sessions/${i}/vnc`)}&autoconnect=1&resize=scale`}class Qg{snapshots=new Map;history=new Map;advertisedStreams=new Map;recoveries=new Map;listeners=new Set;bootstrap;logger;recoverDelta;recoverSnapshot;onRecoveredEvent;recoveryCount=0;counters={streamResets:0,gaps:0,deltaRecoveries:0,snapshotRecoveries:0,recoveryFailures:0};constructor(e){this.bootstrap=e.bootstrap,this.logger=e.logger,this.recoverDelta=e.recoverDelta,this.recoverSnapshot=e.recoverSnapshot,this.onRecoveredEvent=e.onRecoveredEvent}handleEvent(e){if(e.type===M||e.type===L){const t=ra(e.type===M?At:zt,e.payload);return!!t.success||(this.logger?.warn?.({eventType:e.type,issues:t.error.issues,errorCode:"AI_SESSION_TRANSIENT_EVENT_INVALID"},"ai-session.aggregator.transient-event.invalid"),!1)}const t=e.type===P?vt:e.type===j?St:e.type===D?wt:void 0;if(!t)return!1;const n=ra(t,e.payload);return n.success?e.type===P?this.applySnapshot(n.data):e.type===j?this.applyPatch(n.data):this.applyRemoved(n.data):(this.logger?.warn?.({eventType:e.type,issues:n.error.issues,errorCode:"AI_SESSION_EVENT_INVALID"},"ai-session.aggregator.event.invalid"),!1)}onSnapshot(e){return this.listeners.add(e),()=>this.listeners.delete(e)}applySnapshot(e){const t=this.advertisedStreams.get(e.meta.instanceId)?.streamId;return t&&t!==e.meta.streamId?(this.logger?.warn?.({instanceId:e.meta.instanceId,advertisedStreamId:t,streamId:e.meta.streamId,revision:e.meta.revision},"ai-session.aggregator.snapshot.obsolete-stream"),!1):this.apply({type:P,payload:e})}advertiseStream(e,t){return this.advertisedStreams.set(e,t),this.recoverStream(e,t.streamId,t.latestRevision).catch(n=>{this.counters.recoveryFailures+=1,this.logger?.warn?.({instanceId:e,streamId:t.streamId,error:n instanceof Error?n.message:String(n)},"ai-session.aggregator.recovery.failed")})}diagnostics(){return{...this.counters,recoveriesStarted:this.recoveryCount,activeRecoveries:this.recoveries.size}}removeInstance(e){this.snapshots.delete(e),this.history.delete(e),this.advertisedStreams.delete(e)}applyPatch(e){return this.apply({type:j,payload:e})}applyRemoved(e){return this.apply({type:D,payload:e})}async list(e={}){return(e.refresh||0===this.snapshots.size)&&await this.bootstrapFromInstances(),this.view()}async streamDescriptors(){return 0===this.snapshots.size&&await this.bootstrapFromInstances(),[...this.snapshots.entries()].map(([e,t])=>({topic:"ai.sessions",instanceId:e,streamId:t.streamId,latestRevision:t.revision,earliestRetainedRevision:this.history.get(e)?.[0]?.payload.meta.revision??t.revision+1}))}async delta(e){0===this.snapshots.size&&await this.bootstrapFromInstances();const t=this.resolveDeltaInstanceId(e.instanceId);this.pruneHistory(t);const n=this.snapshots.get(t)?.revision??0,s=this.snapshots.get(t)?.streamId||"unavailable",i=this.history.get(t)?.[0]?.payload.meta.revision??n+1;if(e.streamId!==s||e.sinceRevision>n)return kt.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!0,events:[]});if(e.sinceRevision===n)return kt.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!1,events:[]});const r=(this.history.get(t)??[]).filter(t=>t.payload.meta.revision>e.sinceRevision),o=!r.length||r[0].payload.meta.revision!==e.sinceRevision+1;return kt.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:o,events:o?[]:r.map(({type:e,payload:t})=>({type:e,payload:t}))})}apply(e,t=!1){const{meta:n}=e.payload,s=this.advertisedStreams.get(n.instanceId)?.streamId;if(s&&s!==n.streamId)return this.logger?.warn?.({instanceId:n.instanceId,advertisedStreamId:s,streamId:n.streamId,revision:n.revision},"ai-session.aggregator.event.obsolete-stream"),!1;const i=this.recoveries.get(n.instanceId);if(i&&!t)return i.streamId===n.streamId&&(i.highWater=Math.max(i.highWater,n.revision)),!1;const r=this.snapshots.get(n.instanceId);e.type===P&&r&&r.streamId!==n.streamId&&(this.counters.streamResets+=1,this.logger?.info?.({instanceId:n.instanceId,previousStreamId:r.streamId,streamId:n.streamId,previousRevision:r.revision,revision:n.revision,traceId:n.traceId,resetCount:this.counters.streamResets},"ai-session.aggregator.stream-reset"));const o=function(e,t){const{meta:n}=t.payload;if(t.type===P)return e?.streamId===n.streamId&&n.revision===e.revision?{kind:"duplicate",projection:e}:e?.streamId===n.streamId&&n.revision<e.revision?{kind:"stale",projection:e}:{kind:"applied",projection:gt.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:t.payload.snapshot})};if(!e||e.streamId!==n.streamId)return{kind:"snapshot-required",projection:e,streamId:n.streamId};if(n.revision===e.revision)return{kind:"duplicate",projection:e};if(n.revision<e.revision)return{kind:"stale",projection:e};if(n.revision!==e.revision+1||n.previousRevision!==e.revision)return{kind:"gap",projection:e,expectedRevision:e.revision+1,receivedRevision:n.revision};const s=new Map(e.snapshot.sessions.map(e=>[e.id,e]));if(t.type===j){for(const e of t.payload.upserted)s.set(e.id,e);for(const e of t.payload.removed)s.delete(e)}else for(const e of t.payload.sessionIds)s.delete(e);const i=[...s.values()],r=mt.parse({runningCount:i.filter(e=>"running"===e.status).length,waitingCount:i.filter(e=>"waiting"===e.status).length,staleCount:e.snapshot.staleCount,sessions:i,updatedAt:n.generatedAt});return{kind:"applied",projection:gt.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:r})}}(r,e);if("applied"!==o.kind)return this.logger?.warn?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,currentRevision:r?.revision,revision:n.revision,outcome:o.kind},`ai-session.aggregator.event.${o.kind}`),"gap"!==o.kind&&"snapshot-required"!==o.kind||("gap"===o.kind&&(this.counters.gaps+=1),this.recoverStream(n.instanceId,n.streamId,n.revision).catch(e=>{this.logger?.warn?.({instanceId:n.instanceId,streamId:n.streamId,revision:n.revision,error:e instanceof Error?e.message:String(e)},"ai-session.aggregator.recovery.failed")})),!1;const a=o.projection;this.snapshots.set(n.instanceId,a),this.rememberEvent(n.instanceId,e);const d={instanceId:n.instanceId,streamId:a.streamId,aiSessions:a.snapshot,revision:a.revision,lastEventAt:a.lastEventAt};for(const e of this.listeners)try{e(d)}catch{this.listeners.delete(e)}return this.logger?.info?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,revision:n.revision,reason:n.reason,sessionCount:a.snapshot.sessions.length},"ai-session.aggregator.event.accepted"),!0}async bootstrapFromInstances(){this.logger?.info?.({},"ai-session.aggregator.bootstrap");const e=new Map(this.snapshots),t=await this.bootstrap(),n=new Set(t.instances.map(e=>e.instanceId));for(const[t,s]of e)n.has(t)||this.snapshots.get(t)!==s||(this.snapshots.delete(t),this.history.delete(t),this.advertisedStreams.delete(t));for(const n of t.instances){const t=this.snapshots.get(n.instanceId);if(t!==e.get(n.instanceId))continue;const s=this.advertisedStreams.get(n.instanceId)?.streamId;s&&s!==n.streamId||t?.streamId===n.streamId&&t.revision>=n.revision||(t?.streamId!==n.streamId&&this.history.delete(n.instanceId),this.snapshots.set(n.instanceId,{streamId:n.streamId,snapshot:n.aiSessions,revision:n.revision,lastEventAt:n.lastEventAt}))}}recoverStream(e,t,n){const s=this.recoveries.get(e);if(s)return s.streamId===t?s.highWater=Math.max(s.highWater,n):(s.streamId=t,s.highWater=n),s.promise;if(!this.recoverDelta||!this.recoverSnapshot)return Promise.resolve();const i={promise:Promise.resolve(),streamId:t,highWater:n},r=++this.recoveryCount;return this.logger?.info?.({instanceId:e,highWater:n,recoveryNumber:r},"ai-session.aggregator.recovery.started"),i.promise=(async()=>{for(;;){const t=this.advertisedStreams.get(e);if(!t)return;i.streamId!==t.streamId&&(i.streamId=t.streamId,i.highWater=t.latestRevision);const n=this.snapshots.get(e);if(n&&n.streamId===t.streamId){if(n.revision<Math.max(t.latestRevision,i.highWater)){const t=await this.recoverDelta(e,n.streamId,n.revision);if(this.advertisedStreams.get(e)?.streamId!==t.streamId||i.streamId!==t.streamId)continue;if(t.syncRequired){const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:P,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`ais_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot-fallback"},"ai-session.aggregator.recovery.snapshot")}else{for(const e of t.events)this.apply(e,!0)&&this.onRecoveredEvent?.(e);this.counters.deltaRecoveries+=1,i.highWater=Math.max(i.highWater,t.latestRevision),this.logger?.info?.({instanceId:e,streamId:t.streamId,sinceRevision:t.sinceRevision,latestRevision:t.latestRevision,eventCount:t.events.length,recoveryNumber:r,outcome:"delta"},"ai-session.aggregator.recovery.delta")}}}else{const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:P,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`ais_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot"},"ai-session.aggregator.recovery.snapshot")}const s=this.snapshots.get(e),o=this.advertisedStreams.get(e);if(s&&o&&s.streamId===o.streamId&&s.revision>=Math.max(o.latestRevision,i.highWater))return void this.logger?.info?.({instanceId:e,streamId:s.streamId,revision:s.revision,recoveryNumber:r,outcome:"success"},"ai-session.aggregator.recovery.completed")}})().finally(()=>this.recoveries.delete(e)),this.recoveries.set(e,i),i.promise}rememberEvent(e,t){const n=this.history.get(e)??[],s=n.length&&n[0].payload.meta.streamId!==t.payload.meta.streamId?[]:n;s.push({...t,createdAtMs:Date.now()}),this.history.set(e,s),this.pruneHistory(e)}pruneHistory(e){const t=this.history.get(e);if(!t?.length)return;const n=t.filter(e=>e.createdAtMs>=Date.now()-36e5);n.length?this.history.set(e,n):this.history.delete(e)}resolveDeltaInstanceId(e){if(e)return e;const t=[...this.snapshots.keys()];if(1===t.length)return t[0];throw new Error("AI_SESSION_DELTA_INSTANCE_ID_REQUIRED")}view(){return{updatedAt:(new Date).toISOString(),instances:[...this.snapshots.entries()].map(([e,t])=>({instanceId:e,streamId:t.streamId,aiSessions:t.snapshot,revision:t.revision,lastEventAt:t.lastEventAt}))}}}const Xg=d.z.object({id:d.z.string().trim().min(1),instanceId:d.z.string().trim().min(1).max(160),sessionId:d.z.string().trim().min(1).max(120),unread:d.z.boolean(),lastStatus:d.z.enum(["running","waiting","idle","failed"]),sessionUpdatedAt:d.z.string().datetime(),createdAt:d.z.string().datetime(),updatedAt:d.z.string().datetime()}).strict();class Zg{records;bySession=new Map;listener;constructor(e,t={}){this.records=new Do(e.aiSessionUnreadDir,{schema:Xg}),this.listener=t.onChanged}init(){this.records.init(),this.bySession.clear();for(const e of this.records.list())this.bySession.set(ty(e.instanceId,e.sessionId),e)}reconcile(e,t){const n=new Set;for(const s of t.sessions)n.add(s.id),this.reconcileSession(e,s);for(const t of[...this.bySession.values()])t.instanceId!==e||n.has(t.sessionId)||this.deleteRecord(t)}decorate(e,t){return{...t,sessions:t.sessions.map(t=>({...t,unread:this.bySession.get(ty(e,t.id))?.unread||!1}))}}markRead(e,t,n){const s=this.bySession.get(ty(e,t));return s&&s.sessionUpdatedAt===n&&s.unread?ey(this.store({...s,unread:!1,updatedAt:(new Date).toISOString()},!1)):s?ey(s):void 0}removeInstance(e){for(const t of[...this.bySession.values()])t.instanceId===e&&this.deleteRecord(t)}reconcileSession(e,t){const n=ty(e,t.id),s=this.bySession.get(n),i=(new Date).toISOString();if(!s)return void this.store({id:ny(e,t.id),instanceId:e,sessionId:t.id,unread:!1,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,createdAt:i,updatedAt:i},!1);const r=function(e,t,n){return"running"!==n&&"waiting"!==n&&("running"===t||"waiting"===t||e)}(s.unread,s.lastStatus,t.status),o=r!==s.unread;(o||s.lastStatus!==t.status||s.sessionUpdatedAt!==t.updatedAt)&&this.store({...s,unread:r,lastStatus:t.status,sessionUpdatedAt:t.updatedAt,updatedAt:i},o)}store(e,t){const n=this.records.put(e);return this.bySession.set(ty(n.instanceId,n.sessionId),n),t&&this.listener?.(ey(n)),n}deleteRecord(e){this.records.delete(e.id),this.bySession.delete(ty(e.instanceId,e.sessionId))}}function ey(e){return te.parse({instanceId:e.instanceId,sessionId:e.sessionId,unread:e.unread,sessionUpdatedAt:e.sessionUpdatedAt,updatedAt:e.updatedAt})}function ty(e,t){return`${e}\0${t}`}function ny(e,t){return`ais_unread_${s.createHash("sha256").update(ty(e,t)).digest("hex").slice(0,32)}`}class sy{snapshots=new Map;history=new Map;advertisedStreams=new Map;recoveries=new Map;bootstrap;logger;recoverDelta;recoverSnapshot;onRecoveredEvent;recoveryCount=0;counters={streamResets:0,gaps:0,deltaRecoveries:0,snapshotRecoveries:0,recoveryFailures:0};constructor(e){this.bootstrap=e.bootstrap,this.logger=e.logger,this.recoverDelta=e.recoverDelta,this.recoverSnapshot=e.recoverSnapshot,this.onRecoveredEvent=e.onRecoveredEvent}handleEvent(e){const t=e.type===Nt?Ft:e.type===Rt?Ut:e.type===Ot?Ht:void 0;if(!t)return!1;const n=ra(t,e.payload);return n.success?e.type===Nt?this.applySnapshot(n.data):e.type===Rt?this.applyPatch(n.data):this.applyRemoved(n.data):(this.logger?.warn?.({eventType:e.type,issues:n.error.issues,errorCode:"APP_SESSION_EVENT_INVALID"},"app-session.aggregator.event.invalid"),!1)}applySnapshot(e){const t=this.advertisedStreams.get(e.meta.instanceId)?.streamId;return t&&t!==e.meta.streamId?(this.logger?.warn?.({instanceId:e.meta.instanceId,advertisedStreamId:t,streamId:e.meta.streamId,revision:e.meta.revision},"app-session.aggregator.snapshot.obsolete-stream"),!1):this.apply({type:Nt,payload:e})}advertiseStream(e,t){return this.advertisedStreams.set(e,t),this.recoverStream(e,t.streamId,t.latestRevision).catch(n=>{this.counters.recoveryFailures+=1,this.logger?.warn?.({instanceId:e,streamId:t.streamId,error:n instanceof Error?n.message:String(n)},"app-session.aggregator.recovery.failed")})}diagnostics(){return{...this.counters,recoveriesStarted:this.recoveryCount,activeRecoveries:this.recoveries.size}}removeInstance(e){this.snapshots.delete(e),this.history.delete(e),this.advertisedStreams.delete(e)}applyPatch(e){return this.apply({type:Rt,payload:e})}applyRemoved(e){return this.apply({type:Ot,payload:e})}async list(e={}){return(e.refresh||0===this.snapshots.size)&&await this.bootstrapFromInstances(),this.view()}async streamDescriptors(){return 0===this.snapshots.size&&await this.bootstrapFromInstances(),[...this.snapshots.entries()].map(([e,t])=>({topic:"app.sessions",instanceId:e,streamId:t.streamId,latestRevision:t.revision,earliestRetainedRevision:this.history.get(e)?.[0]?.payload.meta.revision??t.revision+1}))}async delta(e){0===this.snapshots.size&&await this.bootstrapFromInstances();const t=this.resolveDeltaInstanceId(e.instanceId);this.pruneHistory(t);const n=this.snapshots.get(t)?.revision??0,s=this.snapshots.get(t)?.streamId||"unavailable",i=this.history.get(t)?.[0]?.payload.meta.revision??n+1;if(e.streamId!==s||e.sinceRevision>n)return Wt.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!0,events:[]});if(e.sinceRevision===n)return Wt.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:!1,events:[]});const r=(this.history.get(t)??[]).filter(t=>t.payload.meta.revision>e.sinceRevision),o=!r.length||r[0].payload.meta.revision!==e.sinceRevision+1;return Wt.parse({streamId:s,instanceId:t,sinceRevision:e.sinceRevision,latestRevision:n,earliestRetainedRevision:i,syncRequired:o,events:o?[]:r.map(({type:e,payload:t})=>({type:e,payload:t}))})}apply(e,t=!1){const{meta:n}=e.payload,s=this.advertisedStreams.get(n.instanceId)?.streamId;if(s&&s!==n.streamId)return this.logger?.warn?.({instanceId:n.instanceId,advertisedStreamId:s,streamId:n.streamId,revision:n.revision},"app-session.aggregator.event.obsolete-stream"),!1;const i=this.recoveries.get(n.instanceId);if(i&&!t)return i.streamId===n.streamId&&(i.highWater=Math.max(i.highWater,n.revision)),!1;const r=this.snapshots.get(n.instanceId);e.type===Nt&&r&&r.streamId!==n.streamId&&(this.counters.streamResets+=1,this.logger?.info?.({instanceId:n.instanceId,previousStreamId:r.streamId,streamId:n.streamId,previousRevision:r.revision,revision:n.revision,traceId:n.traceId,resetCount:this.counters.streamResets},"app-session.aggregator.stream-reset"));const o=function(e,t){const{meta:n}=t.payload;if(t.type===Nt)return e?.streamId===n.streamId&&n.revision===e.revision?{kind:"duplicate",projection:e}:e?.streamId===n.streamId&&n.revision<e.revision?{kind:"stale",projection:e}:{kind:"applied",projection:qt.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:Vt(t.payload.snapshot.sessions,t.payload.snapshot.updatedAt)})};if(!e||e.streamId!==n.streamId)return{kind:"snapshot-required",projection:e,streamId:n.streamId};if(n.revision===e.revision)return{kind:"duplicate",projection:e};if(n.revision<e.revision)return{kind:"stale",projection:e};if(n.revision!==e.revision+1||n.previousRevision!==e.revision)return{kind:"gap",projection:e,expectedRevision:e.revision+1,receivedRevision:n.revision};const s=[...e.snapshot.sessions];if(t.type===Rt){const e=s.findIndex(e=>e.id===t.payload.session.id);Yt(t.payload.session.status)?e<0?s.push(t.payload.session):s[e]=t.payload.session:e>=0&&s.splice(e,1)}else{const e=s.findIndex(e=>e.id===t.payload.sessionId);e>=0&&s.splice(e,1)}const i=Gt(s,n.generatedAt);return{kind:"applied",projection:qt.parse({streamId:n.streamId,revision:n.revision,lastEventAt:n.generatedAt,snapshot:i})}}(r,e);if("applied"!==o.kind)return this.logger?.warn?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,currentRevision:r?.revision,revision:n.revision,outcome:o.kind},`app-session.aggregator.event.${o.kind}`),"gap"!==o.kind&&"snapshot-required"!==o.kind||("gap"===o.kind&&(this.counters.gaps+=1),this.recoverStream(n.instanceId,n.streamId,n.revision).catch(e=>{this.logger?.warn?.({instanceId:n.instanceId,streamId:n.streamId,revision:n.revision,error:e instanceof Error?e.message:String(e)},"app-session.aggregator.recovery.failed")})),!1;const a=o.projection;return this.snapshots.set(n.instanceId,a),this.rememberEvent(n.instanceId,e),this.logger?.info?.({traceId:n.traceId,streamId:n.streamId,instanceId:n.instanceId,revision:n.revision,reason:n.reason,sessionCount:a.snapshot.sessions.length,runningCount:a.snapshot.runningCount,problemCount:a.snapshot.problemCount},"app-session.aggregator.event.accepted"),!0}async bootstrapFromInstances(){this.logger?.info?.({},"app-session.aggregator.bootstrap");const e=new Map(this.snapshots),t=await this.bootstrap(),n=new Set(t.instances.map(e=>e.instanceId));for(const[t,s]of e)n.has(t)||this.snapshots.get(t)!==s||(this.snapshots.delete(t),this.history.delete(t),this.advertisedStreams.delete(t));for(const n of t.instances){const t=this.snapshots.get(n.instanceId);if(t!==e.get(n.instanceId))continue;const s=this.advertisedStreams.get(n.instanceId)?.streamId;s&&s!==n.streamId||t?.streamId===n.streamId&&t.revision>=n.revision||(t?.streamId!==n.streamId&&this.history.delete(n.instanceId),this.snapshots.set(n.instanceId,{streamId:n.streamId,snapshot:Vt(n.appSessions.sessions,n.appSessions.updatedAt),revision:n.revision,lastEventAt:n.lastEventAt}))}}recoverStream(e,t,n){const s=this.recoveries.get(e);if(s)return s.streamId===t?s.highWater=Math.max(s.highWater,n):(s.streamId=t,s.highWater=n),s.promise;if(!this.recoverDelta||!this.recoverSnapshot)return Promise.resolve();const i={promise:Promise.resolve(),streamId:t,highWater:n},r=++this.recoveryCount;return this.logger?.info?.({instanceId:e,highWater:n,recoveryNumber:r},"app-session.aggregator.recovery.started"),i.promise=(async()=>{for(;;){const t=this.advertisedStreams.get(e);if(!t)return;i.streamId!==t.streamId&&(i.streamId=t.streamId,i.highWater=t.latestRevision);const n=this.snapshots.get(e);if(n&&n.streamId===t.streamId){if(n.revision<Math.max(t.latestRevision,i.highWater)){const t=await this.recoverDelta(e,n.streamId,n.revision);if(this.advertisedStreams.get(e)?.streamId!==t.streamId||i.streamId!==t.streamId)continue;if(t.syncRequired){const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:Nt,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`aps_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot-fallback"},"app-session.aggregator.recovery.snapshot")}else{for(const e of t.events)this.apply(e,!0)&&this.onRecoveredEvent?.(e);this.counters.deltaRecoveries+=1,i.highWater=Math.max(i.highWater,t.latestRevision),this.logger?.info?.({instanceId:e,streamId:t.streamId,sinceRevision:t.sinceRevision,latestRevision:t.latestRevision,eventCount:t.events.length,recoveryNumber:r,outcome:"delta"},"app-session.aggregator.recovery.delta")}}}else{const t=await this.recoverSnapshot(e);if(this.advertisedStreams.get(e)?.streamId!==t.streamId)continue;const n={type:Nt,payload:{meta:{streamId:t.streamId,instanceId:e,revision:t.revision,traceId:`aps_recovery_${Date.now().toString(36)}`,generatedAt:t.lastEventAt,reason:"startup"},snapshot:t.snapshot}};this.apply(n,!0)&&this.onRecoveredEvent?.(n),this.counters.snapshotRecoveries+=1,this.logger?.info?.({instanceId:e,streamId:t.streamId,revision:t.revision,recoveryNumber:r,outcome:"snapshot"},"app-session.aggregator.recovery.snapshot")}const s=this.snapshots.get(e),o=this.advertisedStreams.get(e);if(s&&o&&s.streamId===o.streamId&&s.revision>=Math.max(o.latestRevision,i.highWater))return void this.logger?.info?.({instanceId:e,streamId:s.streamId,revision:s.revision,recoveryNumber:r,outcome:"success"},"app-session.aggregator.recovery.completed")}})().finally(()=>this.recoveries.delete(e)),this.recoveries.set(e,i),i.promise}rememberEvent(e,t){const n=this.history.get(e)??[],s=n.length&&n[0].payload.meta.streamId!==t.payload.meta.streamId?[]:n;s.push({...t,createdAtMs:Date.now()}),this.history.set(e,s),this.pruneHistory(e)}pruneHistory(e){const t=this.history.get(e);if(!t?.length)return;const n=t.filter(e=>e.createdAtMs>=Date.now()-36e5);n.length?this.history.set(e,n):this.history.delete(e)}resolveDeltaInstanceId(e){if(e)return e;const t=[...this.snapshots.keys()];if(1===t.length)return t[0];throw new Error("APP_SESSION_DELTA_INSTANCE_ID_REQUIRED")}view(){return{updatedAt:(new Date).toISOString(),instances:[...this.snapshots.entries()].map(([e,t])=>({instanceId:e,streamId:t.streamId,appSessions:t.snapshot,revision:t.revision,lastEventAt:t.lastEventAt}))}}}function iy(e){return e.raw[0].replace(/\\\$\{/g,"${")}class ry{states=new Map;events;constructor(e){this.events=e}handle(e){if(e.type===eo){const t=ra(to,e.payload);return void(t.success&&this.reconcileLifecycle(t.data))}if("instance.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";return void(t&&this.deleteState(t))}if(e.type===wr){const t=ra(kr,e.payload);return void(t.success&&this.applyOutput(t.data))}if(e.type===Ar){const t=ra(Tr,e.payload);t.success&&this.applyFinished(t.data)}}snapshots(){return[...this.states.values()].filter(e=>e.progress).map(e=>Cr.parse({...e.progress,terminalTail:e.terminalTail,...e.terminalTruncated?{terminalTruncated:!0}:{}}))}close(){for(const e of this.states.values())e.timer&&clearTimeout(e.timer);this.states.clear()}deleteState(e){const t=this.states.get(e);t?.timer&&clearTimeout(t.timer),this.states.delete(e)}reconcileLifecycle(e){const t=this.states.get(e.instanceId),n=e.imageProvisioning;t&&(!n||n.generation>t.identity.generation||n.generation===t.identity.generation&&"ready"===n.phase)&&this.deleteState(e.instanceId)}applyOutput(e){const t=this.states.get(e.instanceId);if(t&&e.generation<t.identity.generation)return;if(t&&e.generation===t.identity.generation&&!e.replay&&e.sequence<=t.sequence)return;const n=this.requireState(e);e.replay&&(n.terminal=new cy,n.terminalTail="",n.layers.clear(),n.terminalTruncated=!1),n.sequence=Math.max(n.sequence,e.sequence),n.observedAt=e.observedAt,n.terminal.write(e.data);const s=`${n.terminalTail}${e.data}`;n.terminalTruncated||=s.length>262144,n.terminalTail=s.slice(-262144),function(e,t){for(const n of t.split("\n")){const t=n.trim().match(/^([a-f0-9]{6,64}):\s+(.+)$/i);if(!t)continue;const[,s,i]=t,r=i.toLowerCase(),o=["pull complete","already exists","download complete","pulling fs layer","waiting","downloading","extracting"].find(e=>r.startsWith(e));if(!o)continue;const a=e.get(s)||{status:o},d=ay(i);e.set(s,{...a,status:o,...d||{}})}}(n.layers,n.terminal.text()),n.progress=oy(n),this.schedule(n)}applyFinished(e){const t=this.states.get(e.instanceId);if(t&&e.generation<t.identity.generation)return;if(t&&e.generation===t.identity.generation&&e.sequence<=t.sequence)return;const n=this.requireState(e);n.sequence=Math.max(n.sequence,e.sequence),n.observedAt=e.observedAt,n.outcome=e.outcome,n.progress=oy(n),this.publish(n,!0)}requireState(e){const t=this.states.get(e.instanceId);if(t&&t.identity.generation===e.generation)return t;t?.timer&&clearTimeout(t.timer);const n={identity:{instanceId:e.instanceId,generation:e.generation,requestedReference:e.requestedReference},sequence:e.sequence,observedAt:e.observedAt,terminal:new cy,terminalTail:"",terminalTruncated:!1,layers:new Map};return this.states.set(e.instanceId,n),n}schedule(e){e.timer||(e.timer=setTimeout(()=>this.publish(e,!1),250),e.timer.unref?.())}publish(e,t){e.timer&&clearTimeout(e.timer),e.timer=void 0,e.progress&&(e.progress=oy(e),this.events.publish("image.pull.progress",e.progress,{topic:"instances",scope:{instanceId:e.identity.instanceId}}),t&&(e.progress=oy(e)))}}function oy(e){const t=[...e.layers.values()],n=t.filter(e=>["pull complete","already exists"].includes(e.status)).length,s=t.filter(e=>"download complete"===e.status).length,i=t.filter(e=>"downloading"===e.status).length,r=t.filter(e=>"extracting"===e.status).length;let o=0,a=0;for(const e of t)e.total&&(a+=e.total,o+=["pull complete","already exists","download complete"].includes(e.status)?e.total:Math.min(e.current||0,e.total));const d="failed"===e.outcome?"failed":"succeeded"===e.outcome?"complete":r>0?"extracting":t.length>0?"pulling":"connecting",c=t.filter(e=>"already exists"!==e.status),l=c.length>0&&c.every(e=>Boolean(e.total)),p=l&&a>0?Math.max(0,Math.min(100,o/a*100)):void 0,u="failed"===d?"Image pull failed":"complete"===d?"Image pull complete":t.length?`${n}/${t.length} layers ready${void 0===p?"":` · ${Math.round(p)}%`}`:"Connecting to image registry";return Cr.parse({...e.identity,sequence:e.sequence,observedAt:e.observedAt,status:d,layers:{total:t.length,completed:n,downloaded:s,downloading:i,extracting:r},...l&&a>0?{bytes:{current:o,total:a},percent:p}:{},message:u})}function ay(e){const t=e.match(/([\d.]+)\s*([kmgt]?i?b)\s*\/\s*([\d.]+)\s*([kmgt]?i?b)/i);if(t)return{current:dy(t[1],t[2]),total:dy(t[3],t[4])}}function dy(e,t){return Number(e)*1024**({b:0,kb:1,kib:1,mb:2,mib:2,gb:3,gib:3,tb:4,tib:4}[t.toLowerCase()]||0)}class cy{lines=[[]];row=0;col=0;pending="";write(e){const t=`${this.pending}${e}`;this.pending="";for(let e=0;e<t.length;){const n=t[e];if(""===n&&"["===t[e+1]){let n=e+2;for(;n<t.length&&!/[\x40-\x7e]/.test(t[n]);)n+=1;if(n>=t.length){this.pending=t.slice(e);break}this.csi(t.slice(e+2,n),t[n]),e=n+1;continue}"\r"===n?this.col=0:"\n"===n?(this.row+=1,this.col=0,this.ensureLine()):"\b"===n?this.col=Math.max(0,this.col-1):n>=" "&&(this.ensureLine(),this.lines[this.row][this.col]=n,this.col+=1),e+=1}this.trim()}text(){return this.lines.map(e=>e.join("").trimEnd()).join("\n")}csi(e,t){const n=e.replace(/^\?/,"").split(";").map(e=>Number(e||1)),s=n[0]||1;"A"===t?this.row=Math.max(0,this.row-s):"B"===t?(this.row+=s,this.ensureLine()):"C"===t?this.col+=s:"D"===t?this.col=Math.max(0,this.col-s):"G"===t?this.col=Math.max(0,s-1):"H"===t||"f"===t?(this.row=Math.max(0,s-1),this.col=Math.max(0,(n[1]||1)-1),this.ensureLine()):"K"===t?(this.ensureLine(),2===(n[0]||0)?this.lines[this.row]=[]:this.lines[this.row].splice(this.col)):"J"===t&&2===(n[0]||0)&&(this.lines=[[]],this.row=0,this.col=0)}ensureLine(){for(;this.lines.length<=this.row;)this.lines.push([])}trim(){if(this.lines.length<=500)return;const e=this.lines.length-500;this.lines.splice(0,e),this.row=Math.max(0,this.row-e)}}const ly=hs.extend({credentialHash:d.z.string().trim().min(32).max(256)}).strict(),py=d.z.object({revision:d.z.number().int().nonnegative(),invites:d.z.array(d.z.unknown()).length(0).default([]),bindings:d.z.array(ly)}).strict(),uy={binding:new Set(Object.keys(ly.shape))};function hy(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e;return Object.fromEntries([...t].filter(e=>e in n).map(e=>[e,n[e]]))}function my(e){const{tokenHash:t,...n}=e;return cs.parse(n)}function gy(e){const{credentialHash:t,...n}=e;return hs.parse(n)}class yy{authority;constructor(e,t){this.authority=new Mo(e,()=>({revision:0,invites:[],bindings:[]}),{schema:py,sanitize:e=>function(e,t){if(!e||"object"!=typeof e||Array.isArray(e))return e;const n=e,s=new Set(["revision","invites","bindings"]),i=Object.keys(n).filter(e=>!s.has(e));return i.length>0&&t?.({kind:"authority",fields:i}),{...void 0===n.revision?{}:{revision:n.revision},invites:[],bindings:Array.isArray(n.bindings)?n.bindings.map(e=>function(e,t,n){if(!t||"object"!=typeof t||Array.isArray(t))return t;const s=t,i=uy[e],r=Object.keys(s).filter(e=>!i.has(e));r.length>0&&n?.({kind:e,fields:r});const o=hy(s,i);return o.lastError&&(o.lastError=hy(o.lastError,Object.keys(as.shape))),o}("binding",e,t)).filter(e=>!e||"object"!=typeof e||"revoked"!==e.status):n.bindings}}(e,e=>t?.("unknown stored control-plane proxy fields were ignored",e)),logger:t,directoryMode:448,fileMode:384})}init(){this.authority.init();const e=this.authority.get();this.authority.put(e)}snapshot(){return this.authority.get()}transaction(e){const t=this.authority.get(),n=structuredClone(t),s=e(n);return JSON.stringify(n)!==JSON.stringify(t)&&this.authority.put({...n,revision:t.revision+1}),s}listBindings(){return this.snapshot().bindings}getBinding(e){return this.snapshot().bindings.find(t=>t.id===e)}}class fy extends Error{code;statusCode;retryable;details;constructor(e,t,n,s=!1,i={}){super(t),this.name="ControlPlaneProxyServiceError",this.code=e,this.statusCode=n,this.retryable=s,this.details=i}}const Iy=e=>s.createHash("sha256").update(e).digest("base64url"),by=()=>s.randomBytes(32).toString("base64url");function vy(e,t,n,s=!1,i={}){throw new fy(e,t,n,s,i)}class Sy{store;targets;configuredProxyOrigin;proxyOriginProvider;now;createTokenValue;invites=new il;constructor(e,t,n){this.store=e,this.targets=t,this.configuredProxyOrigin=n.proxyOrigin,this.proxyOriginProvider=n.proxyOriginProvider,this.now=n.now??(()=>new Date),this.createTokenValue=n.createToken??by}init(){this.store.init()}createInvite(e,t){const n=this.resolveProxyOrigin();n||vy(rs.Unavailable,"Configure an externally reachable HTTPS control-plane proxy origin before creating an invite.",409,!1);const s=ls.parse(e);this.requireManageableTarget(s.targetNodeId);const i=this.createTokenValue(),r=this.nowIso(),o={id:Po("proxy_invite"),targetNodeId:s.targetNodeId,tokenHash:Iy(i),status:"active",createdBy:t,expiresAt:new Date(this.now().getTime()+Math.min(1e3*s.expiresInSeconds,6e5)).toISOString(),createdAt:r,updatedAt:r},a=ps.parse({invite:my(o),token:i,proxyOrigin:n,protocolVersion:Wn});return this.invites.put(o.tokenHash,o,this.now().getTime()),a}resolveProxyOrigin(){const e=this.configuredProxyOrigin??this.proxyOriginProvider?.();if(!e)return;const t=Qn.safeParse(e);return t.success?t.data:void 0}listInvites(){return this.invites.list(this.now().getTime()).map(my)}revokeInvite(e){const t=this.listInviteRecords().find(t=>t.id===e);t||vy(rs.InviteInvalid,"Proxy invite is unknown.",404,!1,{inviteId:e});const n=this.nowIso(),s={...t,status:"revoked",revokedAt:n,updatedAt:n};return this.invites.delete(t.tokenHash,this.now().getTime()),my(s)}claimInvite(e){const t=ms.parse(e);this.requireCurrentProtocol(t.protocolVersion);const n=Iy(t.credential),s=this.store.listBindings().find(e=>e.claimId===t.claimId);if(s)return this.requireRecoveredIdentity(s,t,n),this.claimResult(s,this.requireKnownTarget(s.targetNodeId));t.inviteToken||vy(rs.InviteInvalid,"Proxy invite token is required for the first claim.",401);const i=Iy(t.inviteToken),r=this.invites.peek(i,this.now().getTime());r||vy(rs.InviteInvalid,"Proxy invite is invalid or expired.",401),t.targetNodeId&&t.targetNodeId!==r.targetNodeId&&vy(rs.TargetMismatch,"Proxy invite is bound to a different target.",409,!1,{inviteId:r.id,targetNodeId:t.targetNodeId});const o=this.requireManageableTarget(r.targetNodeId),a=this.store.transaction(e=>{const s=(i=r.id,`proxy_binding_${Iy(i).slice(0,32)}`);var i;const a=this.nowIso(),d={id:s,claimId:t.claimId,sourceControlPlaneId:t.sourceControlPlaneId,targetNodeId:r.targetNodeId,bindingKeyId:t.bindingKeyId,credentialHash:n,status:"active",revision:1,createdAt:a,updatedAt:a};return e.bindings.push(d),this.claimResult(d,o)});return this.invites.delete(i,this.now().getTime()),a}listBindings(){return this.store.listBindings().map(gy)}authenticateBinding(e,t){const n=gs.parse(t),i=this.store.getBinding(e);return i||vy(rs.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),"active"!==i.status&&vy(rs.BindingRevoked,"Proxy binding is revoked.",403,!1,{bindingId:e}),i.sourceControlPlaneId===n.sourceControlPlaneId&&i.bindingKeyId===n.bindingKeyId&&function(e,t){const n=Iy(t),i=Buffer.from(e),r=Buffer.from(n);return i.length===r.length&&s.timingSafeEqual(i,r)}(i.credentialHash,n.credential)||vy(rs.AuthenticationFailed,"Proxy binding authentication failed.",401,!1,{bindingId:e}),gy(i)}revokeBinding(e){const t=this.requireBinding(e);if("revoked"===t.status)return gy(t);const n=this.nowIso(),s={...t,status:"revoked",revision:t.revision+1,revokedAt:n,updatedAt:n};return this.store.transaction(t=>{t.bindings=t.bindings.filter(t=>t.id!==e)}),gy(s)}revokeTarget(e){return this.store.transaction(t=>{const n=this.nowIso(),s=t.bindings.filter(t=>t.targetNodeId===e&&"active"===t.status).map(e=>gy({...e,status:"revoked",revision:e.revision+1,revokedAt:n,updatedAt:n}));return t.bindings=t.bindings.filter(t=>t.targetNodeId!==e),{bindings:s,invites:this.revokeTargetInvites(e,n)}})}nowIso(){return this.now().toISOString()}requireCurrentProtocol(e){e!==Wn&&vy(rs.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:e,supportedVersion:Wn})}requireKnownTarget(e){const t=this.targets.get(e);return t||vy(rs.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:e}),t}requireManageableTarget(e){const t=this.requireKnownTarget(e);return t.manageable&&"online"===t.status||vy(rs.TargetUnavailable,"Proxy target is not currently manageable.",503,!0,{targetNodeId:e}),t}requireBinding(e){const t=this.store.getBinding(e);return t||vy(rs.BindingUnknown,"Proxy binding is unknown.",404,!1,{bindingId:e}),t}requireRecoveredIdentity(e,t,n){(e.claimId!==t.claimId||e.sourceControlPlaneId!==t.sourceControlPlaneId||void 0!==t.targetNodeId&&e.targetNodeId!==t.targetNodeId||e.bindingKeyId!==t.bindingKeyId||e.credentialHash!==n)&&vy(rs.BindingIdentityConflict,"Proxy claim conflicts with an existing binding identity.",409,!1,{claimId:t.claimId})}claimResult(e,t){const{manageable:n,...s}=t;return ws.parse({protocolVersion:Wn,binding:gy(e),target:s})}listInviteRecords(){return this.invites.list(this.now().getTime())}revokeTargetInvites(e,t){const n=this.listInviteRecords().filter(t=>t.targetNodeId===e);for(const e of n)this.invites.delete(e.tokenHash,this.now().getTime());return n.map(e=>my({...e,status:"revoked",revokedAt:t,updatedAt:t}))}}class wy extends Error{statusCode=429;code=rs.ResourceLimit;retryable=!0;details;constructor(e,t){super(e),this.name="NodeProxyRuntimeError",this.details=t}}class Ay{maxRequestBodyBytes;maxConcurrentHttpPerBinding;maxConcurrentStreamsPerBinding;maxHttpRequestsPerMinutePerBinding;maxConcurrentWebSocketsPerBinding;maxHttpResponseBytes;httpStreamIdleTimeoutMs;maxWebSocketFrameBytes;maxWebSocketBytes;webSocketIdleTimeoutMs;httpRequestWindowMs;bindings=new Map;requestWindows=new Map;requestWindowTimers=new Map;constructor(e={}){this.maxConcurrentHttpPerBinding=e.maxConcurrentHttpPerBinding??32,this.maxConcurrentStreamsPerBinding=e.maxConcurrentStreamsPerBinding??16,this.maxHttpRequestsPerMinutePerBinding=e.maxHttpRequestsPerMinutePerBinding??600,this.maxConcurrentWebSocketsPerBinding=e.maxConcurrentWebSocketsPerBinding??16,this.maxRequestBodyBytes=e.maxRequestBodyBytes??8388608,this.maxHttpResponseBytes=e.maxHttpResponseBytes??268435456,this.httpStreamIdleTimeoutMs=e.httpStreamIdleTimeoutMs??12e4,this.maxWebSocketFrameBytes=e.maxWebSocketFrameBytes??8388608,this.maxWebSocketBytes=e.maxWebSocketBytes??268435456,this.webSocketIdleTimeoutMs=e.webSocketIdleTimeoutMs??3e5,this.httpRequestWindowMs=e.httpRequestWindowMs??6e4}reserveHttp(e){this.consumeRequestRate(e);const t=this.activity(e);if(t.controllers.size>=this.maxConcurrentHttpPerBinding)throw this.deleteIfEmpty(e,t),this.limit("Proxy HTTP concurrency limit exceeded.",e,"http-concurrency",this.maxConcurrentHttpPerBinding);const n=new AbortController;t.controllers.add(n);let s,i=!1,r=!1,o=0;const a=()=>{r&&!i&&(s&&clearTimeout(s),s=setTimeout(()=>{n.abort(Object.assign(new Error("Proxy HTTP stream idle timeout."),{code:rs.ResourceLimit}))},this.httpStreamIdleTimeoutMs),s.unref?.())};return{controller:n,acceptRequestBody:t=>{if(t>this.maxRequestBodyBytes)throw this.limit("Proxy request body limit exceeded.",e,"request-body",this.maxRequestBodyBytes)},beginResponseStream:()=>{if(!i&&!r){if(t.streams.size>=this.maxConcurrentStreamsPerBinding)throw this.limit("Proxy HTTP stream concurrency limit exceeded.",e,"stream-concurrency",this.maxConcurrentStreamsPerBinding);r=!0,t.streams.add(n),a()}},acceptResponseChunk:t=>{if(!i){if(o+=zy(t),o>this.maxHttpResponseBytes){const t=this.limit("Proxy HTTP response byte limit exceeded.",e,"response-bytes",this.maxHttpResponseBytes);throw n.abort(t),t}a()}},release:()=>{i||(i=!0,s&&clearTimeout(s),t.controllers.delete(n),t.streams.delete(n),this.deleteIfEmpty(e,t))}}}openHttp(e,t){const n=this.reserveHttp(e);try{return n.acceptRequestBody(t),n}catch(e){throw n.release(),e}}openWebSocket(e,t,n){const s=this.activity(e);if(s.sockets.size>=this.maxConcurrentWebSocketsPerBinding)throw this.limit("Proxy WebSocket concurrency limit exceeded.",e,"websocket-concurrency",this.maxConcurrentWebSocketsPerBinding);let i,r=!1,o=0;const a=()=>{r||(r=!0,i&&clearTimeout(i),s.sockets.delete(p),this.deleteIfEmpty(e,s),n?.())},d=e=>{a(),t.close(1009,e)},c=()=>{i&&clearTimeout(i),i=setTimeout(()=>{a(),t.close(1001,"Proxy WebSocket idle timeout.")},this.webSocketIdleTimeoutMs),i.unref?.()},l=e=>{const t=zy(e);return t>this.maxWebSocketFrameBytes?(d("Proxy WebSocket frame limit exceeded."),!1):(o+=t,o>this.maxWebSocketBytes?(d("Proxy WebSocket byte limit exceeded."),!1):(c(),!0))};c();const p={get readyState(){return t.readyState},send:e=>{!r&&l(e)&&t.send(e)},close:(e,n)=>{a(),t.close(e,n)},on:(e,n)=>{"message"!==e?"close"!==e&&"error"!==e?t.on(e,n):t.on(e,(...e)=>{a(),n(...e)}):t.on(e,(e,...t)=>{!r&&l(e)&&n(e,...t)})}};return s.sockets.add(p),p}closeBinding(e,t="Proxy binding was revoked."){const n=this.bindings.get(e);if(!n)return this.clearRequestWindow(e),{abortedRequests:0,closedSockets:0};const s=[...n.controllers],i=[...n.sockets],r=[...n.cleanup];this.bindings.delete(e);for(const e of s)e.abort(Object.assign(new Error(t),{code:rs.BindingRevoked}));for(const e of r)e();for(const e of i)e.close(1008,t);return n.controllers.clear(),n.streams.clear(),n.sockets.clear(),n.cleanup.clear(),this.clearRequestWindow(e),{abortedRequests:s.length,closedSockets:i.length}}diagnostics(e){if(e){const t=this.bindings.get(e);return{bindingId:e,activeHttp:t?.controllers.size??0,activeStreams:t?.streams.size??0,activeWebSockets:t?.sockets.size??0}}return[...this.bindings].map(([e,t])=>({bindingId:e,activeHttp:t.controllers.size,activeStreams:t.streams.size,activeWebSockets:t.sockets.size}))}registerBindingCleanup(e,t){const n=this.activity(e);return n.cleanup.add(t),()=>{n.cleanup.delete(t),this.deleteIfEmpty(e,n)}}activity(e){const t=this.bindings.get(e);if(t)return t;const n={controllers:new Set,streams:new Set,sockets:new Set,cleanup:new Set};return this.bindings.set(e,n),n}deleteIfEmpty(e,t){0===t.controllers.size&&0===t.streams.size&&0===t.sockets.size&&0===t.cleanup.size&&this.bindings.get(e)===t&&this.bindings.delete(e)}limit(e,t,n,s){return new wy(e,{bindingId:t,resource:n,limit:s})}consumeRequestRate(e){const t=Date.now(),n=t-this.httpRequestWindowMs,s=(this.requestWindows.get(e)||[]).filter(e=>e>n);if(s.length>=this.maxHttpRequestsPerMinutePerBinding)throw this.limit("Proxy HTTP request rate limit exceeded.",e,"request-rate",this.maxHttpRequestsPerMinutePerBinding);s.push(t),this.requestWindows.set(e,s),this.scheduleRequestWindowCleanup(e)}scheduleRequestWindowCleanup(e){const t=this.requestWindowTimers.get(e);t&&clearTimeout(t);const n=this.requestWindows.get(e);if(!n?.length)return this.requestWindows.delete(e),void this.requestWindowTimers.delete(e);const s=Math.max(1,n[0]+this.httpRequestWindowMs-Date.now()+1),i=setTimeout(()=>{this.requestWindowTimers.delete(e);const t=Date.now()-this.httpRequestWindowMs,n=(this.requestWindows.get(e)||[]).filter(e=>e>t);n.length?(this.requestWindows.set(e,n),this.scheduleRequestWindowCleanup(e)):this.requestWindows.delete(e)},s);i.unref?.(),this.requestWindowTimers.set(e,i)}clearRequestWindow(e){this.requestWindows.delete(e);const t=this.requestWindowTimers.get(e);t&&clearTimeout(t),this.requestWindowTimers.delete(e)}}function zy(e){return Buffer.isBuffer(e)||e instanceof ArrayBuffer||ArrayBuffer.isView(e)?e.byteLength:Buffer.byteLength("string"==typeof e?e:String(e),"utf8")}class ky{streams=new Map;historyLimit;maxEventBytes;maxHistoryBytes;createStreamId;projectTarget;unsubscribeBus;constructor(e,t){this.historyLimit=Math.max(1,t.historyLimit??256),this.maxEventBytes=Math.max(1024,t.maxEventBytes??524288),this.maxHistoryBytes=Math.max(this.maxEventBytes,t.maxHistoryBytes??16777216),this.createStreamId=t.createStreamId??(e=>`proxy_events_${e}_${s.randomUUID().replace(/-/g,"").slice(0,16)}`),this.projectTarget=t.projectTarget,this.unsubscribeBus=e.on(e=>this.accept(e))}stop(){this.unsubscribeBus();for(const e of this.streams.values())e.subscribers.clear();this.streams.clear()}cursor(e){const t=this.stream(e);return{streamId:t.streamId,revision:t.revision,earliestRetainedRevision:Ty(t)}}subscribe(e,t,n,s=()=>{}){const{bindingId:i,sourceControlPlaneId:r,targetNodeId:o}=e,a=this.stream(o),d=Ty(a);if(t>a.revision||t<d-1)return n(vs.parse({type:"control-plane-proxy.snapshot-required",protocolVersion:Wn,streamId:a.streamId,bindingId:i,sourceControlPlaneId:r,targetNodeId:o,sinceRevision:t,latestRevision:a.revision,earliestRetainedRevision:d,error:{code:rs.SnapshotRequired,message:"Proxy target event history cannot continue from the requested revision; fetch a new snapshot.",retryable:!0,details:{targetNodeId:o}}})),{kind:"snapshot-required",close:()=>{}};n(bs.parse({type:"control-plane-proxy.events.ready",protocolVersion:Wn,streamId:a.streamId,bindingId:i,sourceControlPlaneId:r,targetNodeId:o,latestRevision:a.revision,earliestRetainedRevision:d}));for(const e of a.history)e.event.revision>t&&n(Cy(e.event,i,r));const c={bindingId:i,sourceControlPlaneId:r,send:n,onDeliveryFailure:s};a.subscribers.add(c);let l=!1;return{kind:"subscribed",close:()=>{l||(l=!0,a.subscribers.delete(c))}}}diagnostics(e){const t=this.stream(e);return{targetNodeId:e,streamId:t.streamId,revision:t.revision,earliestRetainedRevision:Ty(t),historySize:t.history.length,historyBytes:t.historyBytes,subscribers:t.subscribers.size,subscriberBindings:[...t.subscribers].map(({bindingId:e,sourceControlPlaneId:t})=>({bindingId:e,sourceControlPlaneId:t}))}}accept(e){const t=e.scope?.nodeId;if("string"!=typeof t||!t)return;let n;try{n=this.projectTarget(t)}catch{return}if(!n)return;const s=this.stream(t),i=s.revision+1,r=Is.safeParse({type:"control-plane-proxy.event",protocolVersion:Wn,streamId:s.streamId,bindingId:"proxy_projection",sourceControlPlaneId:"proxy_projection",targetNodeId:t,revision:i,source:{id:e.id,seq:e.seq},target:n,event:{type:e.type,topic:e.topic,createdAt:e.createdAt}});if(!r.success)return;const{bindingId:o,sourceControlPlaneId:a,...d}=r.data,c=Ey(d);if(!(void 0===c||c>this.maxEventBytes-512)){for(s.revision=i,s.history.push({event:d,bytes:c}),s.historyBytes+=c;s.history.length>this.historyLimit||s.historyBytes>this.maxHistoryBytes;){const e=s.history.shift();e&&(s.historyBytes-=e.bytes)}for(const e of[...s.subscribers])try{const t=Cy(d,e.bindingId,e.sourceControlPlaneId),n=Ey(t);if(void 0===n||n>this.maxEventBytes)throw new Error("Proxy event byte limit exceeded.");e.send(t)}catch{s.subscribers.delete(e);try{e.onDeliveryFailure()}catch{}}}}stream(e){const t=this.streams.get(e);if(t)return t;const n={streamId:this.createStreamId(e),revision:0,history:[],historyBytes:0,subscribers:new Set};return this.streams.set(e,n),n}}function Ty(e){return e.history[0]?.event.revision??e.revision+1}function Cy(e,t,n){return Is.parse({...e,bindingId:t,sourceControlPlaneId:n})}function Ey(e){try{return Buffer.byteLength(JSON.stringify(e),"utf8")}catch{return}}function xy(e,t){const n=new WeakSet;let s=t,i=0;const r=e=>{if(s-=Buffer.byteLength(e,"utf8"),s<0)throw Ny("Proxy target projection byte limit exceeded.",{resource:"target-projection-bytes",limit:t})},o=(e,t)=>{if(i+=1,i>16384||t>24)throw Ny("Proxy target projection complexity limit exceeded.");if(null===e||"boolean"==typeof e)return e;if("string"==typeof e)return r(e),e;if("number"==typeof e)return Number.isFinite(e)?e:null;if("object"!=typeof e)return;if(n.has(e))throw Ny("Proxy target projection contains a cycle.",void 0,!1);if(n.add(e),Array.isArray(e)){const s=e.map(e=>o(e,t+1)??null);return n.delete(e),s}const s={};for(const[n,i]of Object.entries(e)){if("__proto__"===n||"constructor"===n||"prototype"===n)continue;r(n);const e=o(i,t+1);void 0!==e&&(s[n]=e)}return n.delete(e),s};return o(e,0)}function Ny(e,t,n=!0){return Object.assign(new Error(e),{code:"CONTROL_PLANE_PROXY_RESOURCE_LIMIT",statusCode:429,retryable:n,...t?{details:t}:{}})}function Ry(e){const{manageable:t,...n}=e;return n}const Oy=d.z.object({bindingId:d.z.string().trim().min(1).max(160)}).passthrough(),_y=d.z.object({route:Xn}).strict(),Py=d.z.object({sinceRevision:d.z.coerce.number().int().nonnegative()}).strict(),jy=new Set(["connection","cookie","host","keep-alive","proxy-authorization","te","trailer","transfer-encoding","upgrade"]),Dy=524288;function My(e,t,n){const s=Hy(n.headers,ts);if(s!==Wn)throw Uy(rs.ProtocolUnsupported,"Control-plane proxy protocol version is unsupported.",426,!1,{requestedVersion:s,supportedVersion:Wn});const i=Hy(n.headers,ns),r=Hy(n.headers,ss),o=Hy(n.headers,is);if(!i||!r||!o)throw Uy(rs.AuthenticationFailed,"Proxy binding authentication headers are incomplete.",401);return e.authenticateBinding(t,{sourceControlPlaneId:i,bindingKeyId:r,credential:o})}function Ly(e,t,n){const s=My(e,t.id,n);if(s.id!==t.id||s.revision!==t.revision||s.sourceControlPlaneId!==t.sourceControlPlaneId||s.targetNodeId!==t.targetNodeId||s.bindingKeyId!==t.bindingKeyId||"active"!==s.status)throw Uy(rs.BindingIdentityConflict,"Proxy binding changed while the request was being established.",409,!0,{bindingId:t.id,expectedRevision:t.revision,actualRevision:s.revision})}function qy(e,t){if(t.id!==e.targetNodeId)throw Uy(rs.TargetMismatch,"Proxy target resolver returned another node.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}function $y(e){for(const t of Object.keys(e)){const e=t.toLowerCase();if(e.startsWith("x-taskhandoff-node-")||e.startsWith("x-task-handoff-node-"))throw Uy(rs.HeaderInvalid,"Caller-supplied node transport authentication headers are forbidden.",400,!1,{header:e})}const t=Object.fromEntries([...Zn].flatMap(t=>{if(jy.has(t))return[];const n=e[t];return void 0===n?[]:[[t,Array.isArray(n)?n.join(", "):String(n)]]}));if(void 0!==t["x-request-id"]){const e=Yn.safeParse(t["x-request-id"]);if(!e.success)throw Uy(rs.HeaderInvalid,"Proxy request correlation id is invalid.",400,!1,{header:"x-request-id"});t["x-request-id"]=e.data}if(void 0!==t[ba]){const e=Yn.safeParse(t[ba]);if(!e.success)throw Uy(rs.HeaderInvalid,"Proxy trace id is invalid.",400,!1,{header:ba});t[ba]=e.data}return t}function By(e,t,n){const s=Fy(t),i=Wy(n?.headers);return i&&e.header("x-request-id",i),e.code(s.statusCode).send({error:{code:s.code,message:s.message,retryable:s.retryable,...s.details?{details:s.details}:{}}})}function Fy(e){const t=e&&"object"==typeof e?e:{},n="number"==typeof t.statusCode?t.statusCode:502;return{statusCode:n,code:("string"==typeof t.code?t.code:void 0)||rs.TransportFailed,message:e instanceof Error?e.message:"Control-plane proxy transport failed.",retryable:"boolean"==typeof t.retryable?t.retryable:n>=500,details:t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?t.details:void 0}}function Uy(e,t,n,s=!1,i){return Object.assign(new Error(t),{code:e,statusCode:n,retryable:s,...i?{details:i}:{}})}function Hy(e,t){const n=e[t];return Array.isArray(n)?n.join(","):"string"==typeof n?n:""}function Wy(e){if(!e)return;const t=Yn.safeParse(Hy(e,"x-request-id"));return t.success?t.data:void 0}function Gy(e){let t="";for(const n of e){if(Buffer.byteLength(t+n)>123)break;t+=n}return t}const Vy=e=>as.parse({code:rs.Unavailable,message:e,retryable:!0});class Ky{service;subscriptions=new Map;fetchImpl;openWebSocket;onStateChanged;logger;running=!1;constructor(e,t={}){this.service=e,this.fetchImpl=t.fetchImpl??fetch,this.openWebSocket=t.openWebSocket??((e,t)=>new p.WebSocket(e,{headers:t})),this.onStateChanged=t.onStateChanged??(()=>{}),this.logger=t.logger}start(){this.running||(this.running=!0,this.syncNow())}syncNow(){if(!this.running)return;const e=new Map(this.service.listNodes().filter(e=>"control-plane-proxy"===e.connectionMode&&!1!==e.connectionEnabled).map(e=>[e.id,e]));for(const t of this.subscriptions.keys())e.has(t)||this.remove(t);for(const t of e.values()){const e=this.subscriptionIdentity(t),n=this.subscriptions.get(t.id);if(n?.identity===e)continue;n&&this.remove(t.id);const s={generation:1,identity:e,retry:new rm};this.subscriptions.set(t.id,s),this.connect(t.id,s.generation)}}stop(){this.running=!1;for(const e of[...this.subscriptions.keys()])this.remove(e)}remove(e){const t=this.subscriptions.get(e);t&&(t.generation+=1,t.reconnect&&clearTimeout(t.reconnect),t.socket?.close(),this.subscriptions.delete(e))}async connect(e,t){if(!this.current(e,t))return;const n=this.service.proxyPrivateStore.nodeCredential(e);if(n)try{const s=await this.fetchImpl(function(e){return new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/snapshot`,e.proxyOrigin)}(n),{headers:qd(n)});if(!this.current(e,t))return;const i=await s.json().catch(()=>{});if(!s.ok){const n=ra(as,i?.error),r=n.success?n.data:Vy(`Proxy snapshot failed with HTTP ${s.status}.`);return r.code===rs.BindingRevoked||r.code===rs.BindingUnknown?void this.onStateChanged(this.service.markProxyBindingRevoked(e,r)):void this.fail(e,t,r,r.retryable)}const r=oa(fs,i?.data);if(this.validateIdentity(n,r.binding.id,r.binding.targetNodeId),this.onStateChanged(this.service.applyProxyTargetSnapshot(e,r)),"revoked"===r.binding.status)return void this.onStateChanged(this.service.markProxyBindingRevoked(e,{code:rs.BindingRevoked,message:"Control-plane proxy binding was revoked.",retryable:!1}));this.openEvents(e,t,n,r)}catch(n){if(!this.current(e,t))return;this.logger?.warn?.({nodeId:e,error:Jy(n)},"control-plane proxy state bootstrap failed"),this.fail(e,t,Vy("Trusted control-plane proxy is unavailable."),!0)}else this.fail(e,t,Vy("Control-plane proxy credential is unavailable."),!1)}openEvents(e,t,n,s){const i=this.current(e,t);if(!i)return;const r=this.openWebSocket(function(e,t){const n=new URL(`/api/node-proxy/bindings/${encodeURIComponent(e.proxyBindingId)}/events`,e.proxyOrigin);return n.protocol="wss:",n.searchParams.set("sinceRevision",String(t)),n.toString()}(n,s.revision),qd(n));i.socket=r;let o=!1;const a=n=>{o||(o=!0,this.fail(e,t,Vy(n),!0))};r.on("message",r=>{if(this.current(e,t))try{const o=oa(Ss,JSON.parse(String(r)));if(o.bindingId!==n.proxyBindingId||o.sourceControlPlaneId!==n.sourceControlPlaneId||o.targetNodeId!==n.targetNodeId||o.streamId!==s.streamId)throw new Error("Proxy event stream identity changed.");if("control-plane-proxy.snapshot-required"===o.type)return void this.restart(e,t);if("control-plane-proxy.events.ready"===o.type)return void i.retry.reset();this.onStateChanged(this.service.applyProxyTargetEvent(e,o))}catch(n){this.logger?.warn?.({nodeId:e,error:Jy(n)},"control-plane proxy event requires a new snapshot"),this.restart(e,t)}}),r.on("error",()=>a("Control-plane proxy event stream failed.")),r.on("close",()=>a("Control-plane proxy event stream disconnected."))}restart(e,t){const n=this.current(e,t);n&&(n.generation+=1,n.socket?.close(),n.socket=void 0,this.connect(e,n.generation))}fail(e,t,n,s){const i=this.current(e,t);if(!i)return;if(this.onStateChanged(this.service.markProxyUnavailable(e,n)),!s)return i.generation+=1,i.socket?.close(),void this.subscriptions.delete(e);i.generation+=1,i.socket?.close(),i.socket=void 0;const r=i.retry.next();i.reconnect=setTimeout(()=>{i.reconnect=void 0,this.connect(e,i.generation)},r.delay),i.reconnect.unref?.()}current(e,t){const n=this.subscriptions.get(e);return this.running&&n?.generation===t?n:void 0}validateIdentity(e,t,n){if(t!==e.proxyBindingId||n!==e.targetNodeId){const e=new Error("Proxy snapshot identity does not match the private binding credential.");throw Object.assign(e,{code:rs.BindingIdentityConflict}),e}}subscriptionIdentity(e){const t=this.service.proxyPrivateStore.nodeCredential(e.id);return JSON.stringify({connectionMode:e.connectionMode,connectionPath:e.connectionPath,credential:t&&{id:t.id,proxyOrigin:t.proxyOrigin,proxyBindingId:t.proxyBindingId,targetNodeId:t.targetNodeId,sourceControlPlaneId:t.sourceControlPlaneId,bindingKeyId:t.bindingKeyId,updatedAt:t.updatedAt}})}}function Jy(e){const t=e&&"object"==typeof e?e:{};return{name:e instanceof Error?e.name:"Error",message:e instanceof Error?e.message:String(e),..."string"==typeof t.code?{code:t.code}:{}}}const Yy=d.z.object({id:d.z.string().trim().min(1).max(160)}).strict(),Qy=d.z.object({}).strict(),Xy=d.z.object({force:d.z.enum(["true","false"]).optional()}).strict(),Zy=d.z.object({algorithm:d.z.literal("Ed25519"),publicKey:d.z.string().regex(/^[A-Za-z0-9_-]{43}$/),privateKeyPkcs8:d.z.string().regex(/^[A-Za-z0-9_-]{64}$/)}).strip();function ef(){const{publicKey:e,privateKey:t}=s.generateKeyPairSync("ed25519"),n=e.export({format:"jwk"});if(!n.x)throw new Error("Generated Control Plane identity did not contain an Ed25519 public key.");return{algorithm:"Ed25519",publicKey:n.x,privateKeyPkcs8:t.export({format:"der",type:"pkcs8"}).toString("base64url")}}function tf(e){return`sha256:${s.createHash("sha256").update(Buffer.from(e,"base64url")).digest("base64url")}`}function nf(e){return Array.isArray(e)?`[${e.map(nf).join(",")}]`:e&&"object"==typeof e?`{${Object.entries(e).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${JSON.stringify(e)}:${nf(t)}`).join(",")}}`:JSON.stringify(e)}class sf{identity;controlPlaneId;constructor(e,t,n){this.controlPlaneId=t,this.identity=new Mo(e,ef,{schema:Zy,logger:n,directoryMode:448,fileMode:384})}init(){this.identity.init(),this.privateKey()}publicDocument(e,t=Date.now()){const n=this.identity.get(),i={authentication:e,aiSessions:!0,nodes:!0,instanceBoard:!0,triggers:!0},r=wo.parse({version:1,kind:"control-plane",controlPlaneId:this.controlPlaneId(),publicKey:{algorithm:"Ed25519",encoding:"base64url",value:n.publicKey,fingerprint:tf(n.publicKey)},capabilities:i,protocolVersion:"2026-08-09",issuedAt:new Date(t).toISOString(),expiresAt:new Date(t+3e5).toISOString()}),o=s.sign(null,Buffer.from((a=r,JSON.stringify(wo.parse(a)))),this.privateKey()).toString("base64url");var a;return Ao.parse({data:{payload:r,signature:o}})}publicIdentity(){const e=this.identity.get();return{controlPlaneId:this.controlPlaneId(),algorithm:e.algorithm,publicKey:e.publicKey,fingerprint:tf(e.publicKey)}}signCloudBindingChallenge(e){return s.sign(null,Buffer.from(`task-handoff:cloud-binding-challenge:v1\n${nf(e)}`),this.privateKey()).toString("base64url")}signCloudOutboundRegistration(e){return s.sign(null,Buffer.from((t=e,`task-handoff:outbound-control-registration:v1\n${pn(wn.parse(t))}`)),this.privateKey()).toString("base64url");var t}acceptCloudAccessHandshake(e,t){return function(e){const t=An.parse(e.ticket),n=Tn.parse(e.clientHello);if(t.ticketId!==n.ticketId||t.deviceSessionId!==n.deviceSessionId||t.targetPublicKeyFingerprint!==e.controlPlaneFingerprint)throw Cn();const i=s.generateKeyPairSync("x25519"),r=function(e){const t=e.export({format:"jwk"}).x;if(!t)throw Cn();return t}(i.publicKey),o=function(e,t,n){return s.createHash("sha256").update(pn({audience:e.audience,ticketId:e.ticketId,accountId:e.accountId,deviceSessionId:e.deviceSessionId,controlPlaneId:e.controlPlaneId,bindingId:e.bindingId,bindingRevision:e.bindingRevision,nonce:e.nonce,clientEphemeralPublicKey:t,serverEphemeralPublicKey:n})).digest("base64url")}(t,n.clientEphemeralPublicKey,r);var a;const d=function(e,t){return s.createHash("sha256").update(e).update(t).update("task-handoff:control-plane-access:e2e:v1").digest()}(s.diffieHellman({privateKey:i.privateKey,publicKey:(a=n.clientEphemeralPublicKey,s.createPublicKey({key:{kty:"OKP",crv:"X25519",x:a},format:"jwk"}))}),o);return{sessionKey:d,response:{serverEphemeralPublicKey:r,transcript:o,signature:s.sign(null,Buffer.from(o),e.controlPlanePrivateKey).toString("base64url")}}}({ticket:e,clientHello:t,controlPlaneFingerprint:this.publicIdentity().fingerprint,controlPlanePrivateKey:this.privateKey()})}privateKey(){const e=this.identity.get(),t=s.createPrivateKey({key:Buffer.from(e.privateKeyPkcs8,"base64url"),format:"der",type:"pkcs8"});if(s.createPublicKey(t).export({format:"jwk"}).x!==e.publicKey)throw new Error("Stored Control Plane signing identity public and private keys do not match.");return t}}class rf{observations=new Map;listeners=new Set;begin(e,t,n="connecting"){const s=this.observations.get(e),i={nodeId:e,transport:t,generation:(s?.generation||0)+1,phase:n,changedAt:(new Date).toISOString(),consecutiveFailures:s?.transport===t?s.consecutiveFailures:0,controlReachability:s?.transport===t?s.controlReachability:"unknown",controlChangedAt:s?.transport===t?s.controlChangedAt:void 0,controlError:s?.transport===t?s.controlError:void 0};return this.observations.set(e,i),this.publish(i),i.generation}update(e,t,n,s=!0){const i=this.observations.get(e);if(!i||i.generation!==t)return!1;const r={...i,...n,changedAt:(new Date).toISOString()};return this.observations.set(e,r),s&&this.publish(r),!0}connected(e,t){const n=(new Date).toISOString();return this.update(e,t,{phase:"healthy",connectedAt:n,lastSeenAt:n,nextRetryAt:void 0,error:void 0})}pong(e,t,n={}){const s=(new Date).toISOString();return this.update(e,t,{lastSeenAt:s,lastPongAt:s,...void 0===n.pingRttMs?{}:{pingRttMs:n.pingRttMs},...void 0===n.pingRttP95Ms?{}:{pingRttP95Ms:n.pingRttP95Ms}},!1)}stable(e,t){return this.update(e,t,{consecutiveFailures:0},!1)}observedReachable(e){if("control-plane-proxy"===e.connectionMode)return!1;const t="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http",n=this.observations.get(e.id),s=n?.transport===t?n.generation:this.begin(e.id,t,"handshaking");if("direct-http"===t){const t=(new Date).toISOString();return"reachable"===n?.controlReachability?this.update(e.id,s,{lastSeenAt:t},!1):this.update(e.id,s,{controlReachability:"reachable",controlChangedAt:t,controlError:void 0,lastSeenAt:t})}return"healthy"===n?.phase?this.update(e.id,s,{lastSeenAt:(new Date).toISOString()},!1):this.connected(e.id,s)}observedFailure(e,t){if("control-plane-proxy"===e.connectionMode)return!1;const n="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http",s=this.observations.get(e.id),i=s?.transport===n?s.generation:this.begin(e.id,n,"connecting");return"direct-http"===n?"unreachable"===s?.controlReachability?this.update(e.id,i,{controlError:t},!1):this.update(e.id,i,{controlReachability:"unreachable",controlChangedAt:(new Date).toISOString(),controlError:t}):this.disconnected(e.id,i,{error:t})}disconnected(e,t,n={}){const s=this.observations.get(e);return!(!s||s.generation!==t)&&this.update(e,t,{phase:n.nextRetryAt?"reconnecting":"offline",consecutiveFailures:s.consecutiveFailures+1,closeCode:n.closeCode,error:n.error,nextRetryAt:n.nextRetryAt})}observation(e){return this.observations.get(e)}onChange(e){return this.listeners.add(e),()=>this.listeners.delete(e)}project(e){if(!1===e.connectionEnabled)return{...e,status:"offline",health:"failed",connectionPhase:"offline"};if("direct-http"!==e.connectionMode&&"reverse-wss"!==e.connectionMode&&"local-ipc"!==e.connectionMode&&"local-loopback"!==e.connectionMode)return e;const t=this.observations.get(e.id),n="reverse-wss"===e.connectionMode?"reverse-wss":"direct-http";if(!t||t.transport!==n)return"direct-http"===n?{...e,status:"unknown",health:"unknown",connectionPhase:"connecting"}:e;const s={...void 0===t.pingRttMs?{}:{pingRttMs:t.pingRttMs},...void 0===t.pingRttP95Ms?{}:{pingRttP95Ms:t.pingRttP95Ms},consecutiveReconnects:t.consecutiveFailures,...t.nextRetryAt?{nextRetryAt:t.nextRetryAt}:{}};return"direct-http"===n?"reachable"===t.controlReachability?{...e,connectionDiagnostics:s,status:"online",health:"unknown"===e.health||"failed"===e.health?"ok":e.health,lastSeenAt:t.lastSeenAt||e.lastSeenAt,connectionPhase:"healthy"}:{...e,connectionDiagnostics:s,status:"unreachable"===t.controlReachability?"offline":"unknown",health:"unreachable"===t.controlReachability?"failed":"unknown",lastSeenAt:t.lastSeenAt,connectionPhase:"unreachable"===t.controlReachability?"offline":"connecting"}:"healthy"===t.phase?{...e,connectionDiagnostics:s,status:"online",health:"unknown"===e.health?"ok":e.health,lastSeenAt:t.lastSeenAt||t.connectedAt,connectionPhase:t.phase}:"connecting"===t.phase||"handshaking"===t.phase||"reconnecting"===t.phase||"suspect"===t.phase?{...e,connectionDiagnostics:s,status:"offline",health:"degraded",lastSeenAt:t.lastSeenAt,connectionPhase:t.phase}:{...e,connectionDiagnostics:s,status:"offline",health:"failed",lastSeenAt:t.lastSeenAt,connectionPhase:t.phase}}diagnostics(){return[...this.observations.values()].map(e=>({...e}))}publish(e){for(const t of this.listeners)t({...e})}}function of(e,n){const s=t.extname(e);return`${s?e.slice(0,-s.length):e}.${n}${s}`}const af=1048576,df=52428800;function cf(e){return e instanceof Error?{name:e.name,message:e.message,stack:e.stack}:e}function lf(e){const s=[],i=e=>{if(n.existsSync(e))for(const r of n.readdirSync(e,{withFileTypes:!0})){const n=t.join(e,r.name);r.isSymbolicLink()||(r.isDirectory()?i(n):r.isFile()&&(r.name.endsWith(".log")||r.name.endsWith(".jsonl"))&&s.push(n))}};return i(e),s.sort()}function pf(e,s,i){const r=n.statSync(e),o=Math.min(r.size,af,i);if(o<=0)return 0;const a=Buffer.allocUnsafe(o),d=n.openSync(e,"r");try{n.readSync(d,a,0,o,Math.max(0,r.size-o))}finally{n.closeSync(d)}return n.mkdirSync(t.dirname(s),{recursive:!0,mode:448}),n.writeFileSync(s,a,{mode:384}),o}const uf=d.z.object({version:d.z.literal(1),serviceOrigin:d.z.string().url(),status:d.z.enum(["unbound","pending-claim","active","pending-revocation","clone-conflict"]),remoteAccessEnabled:d.z.boolean(),accountId:d.z.string().optional(),bindingId:d.z.string().optional(),bindingRevision:d.z.number().int().positive().optional(),backgroundCredential:d.z.string().min(32).optional(),updatedAt:d.z.string().datetime(),connectionEpoch:d.z.number().int().nonnegative().default(0)}).strip();class hf{state;challenges=new Map;identity;serviceOrigin;clock;constructor(e){this.identity=e.identity,this.serviceOrigin=new URL(e.serviceOrigin).origin,this.clock=e.clock??Date.now,this.state=new Mo(e.statePath,()=>({version:1,serviceOrigin:this.serviceOrigin,status:"unbound",remoteAccessEnabled:!0,updatedAt:new Date(this.clock()).toISOString(),connectionEpoch:0}),{schema:uf,directoryMode:448,fileMode:384})}init(){if(this.state.init(),this.state.get().serviceOrigin!==this.serviceOrigin)throw gf("CLOUD_SERVICE_ORIGIN_CHANGED","Cloud service origin does not match persisted binding authority.")}snapshot(){const{backgroundCredential:e,connectionEpoch:t,...n}=this.state.get();return{...n,identity:this.identity.publicIdentity(),hasBackgroundCredential:Boolean(e)}}createChallenge(){const e=this.state.get();if(["active","pending-revocation","clone-conflict"].includes(e.status))throw gf("active"===e.status?"CONTROL_PLANE_ALREADY_BOUND":"BINDING_STATE_CONFLICT","Existing cloud binding must be resolved first.");this.prune();const t=Po("binding_challenge"),n=s.randomBytes(32).toString("base64url"),i=this.challengePayload(t);return this.challenges.set(t,{digest:mf(n),payload:i,expiresAtMs:Date.parse(i.expiresAt)}),this.state.put({...e,status:"pending-claim",updatedAt:new Date(this.clock()).toISOString()}),{challengeCode:`${t}.${n}`,authorizationUrl:`${this.serviceOrigin}/bindings/authorize`,payload:i,signature:this.identity.signCloudBindingChallenge(i)}}consumeChallenge(e){const t=e.challengeCode.indexOf("."),n=e.challengeCode.slice(0,t),i=e.challengeCode.slice(t+1),r=this.challenges.get(n);if(r&&this.challenges.delete(n),!r||r.expiresAtMs<=this.clock()||(o=r.digest,a=mf(i),o.length!==a.length||!s.timingSafeEqual(o,a)))throw gf("BINDING_CHALLENGE_INVALID_OR_CONSUMED","Binding challenge is invalid, expired, or consumed.");var o,a;if(r.payload.controlPlaneId!==e.controlPlaneId||r.payload.publicKeyFingerprint!==e.fingerprint)throw gf("BINDING_IDENTITY_CONFLICT","Binding challenge identity does not match.");return r.payload}activate(e){const t=this.state.get();if("active"===t.status){if(t.accountId===e.accountId&&t.bindingId===e.bindingId&&t.bindingRevision===e.bindingRevision)return this.snapshot();throw gf("CONTROL_PLANE_ALREADY_BOUND","Control Plane is already bound to another account.")}if("pending-claim"!==t.status)throw gf("BINDING_STATE_CONFLICT","Control Plane has no pending binding claim.");return this.state.put({...t,status:"active",remoteAccessEnabled:!0,...e,updatedAt:new Date(this.clock()).toISOString()}),this.snapshot()}setRemoteAccess(e){const t=this.state.get();return this.state.put({...t,remoteAccessEnabled:e,updatedAt:new Date(this.clock()).toISOString()}),this.snapshot()}beginRevocation(){const e=this.state.get();return"unbound"===e.status||(this.challenges.clear(),this.state.put({...e,status:"pending-revocation",remoteAccessEnabled:!1,updatedAt:new Date(this.clock()).toISOString()})),this.snapshot()}confirmRevocation(){const e=this.state.get();return this.state.put({version:1,serviceOrigin:e.serviceOrigin,status:"unbound",remoteAccessEnabled:!1,updatedAt:new Date(this.clock()).toISOString(),connectionEpoch:e.connectionEpoch}),this.snapshot()}markCloneConflict(){const e=this.state.get();return this.challenges.clear(),this.state.put({...e,status:"clone-conflict",remoteAccessEnabled:!1,backgroundCredential:void 0,updatedAt:new Date(this.clock()).toISOString()}),this.snapshot()}backgroundCredential(){const e=this.state.get();return"active"===e.status&&e.remoteAccessEnabled?e.backgroundCredential:void 0}nextConnectionEpoch(){const e=this.state.get(),t=e.connectionEpoch+1;return this.state.put({...e,connectionEpoch:t,updatedAt:new Date(this.clock()).toISOString()}),t}challengePayload(e){const t=this.identity.publicIdentity(),n=this.clock();return{protocolVersion:"2026-08-10",audience:"task-handoff:binding",serviceOrigin:this.serviceOrigin,challengeId:e,controlPlaneId:t.controlPlaneId,publicKey:t.publicKey,publicKeyFingerprint:t.fingerprint,nonce:s.randomBytes(24).toString("base64url"),issuedAt:new Date(n).toISOString(),expiresAt:new Date(n+3e5).toISOString()}}prune(){const e=this.clock();for(const[t,n]of this.challenges)n.expiresAtMs<=e&&this.challenges.delete(t)}}function mf(e){return s.createHash("sha256").update(e).digest()}function gf(e,t){return Object.assign(new Error(t),{code:e,statusCode:e.includes("CONFLICT")||e.includes("BOUND")?409:400})}class yf{revision=0;options;constructor(e){this.options=e}async apply(e){if(!Number.isSafeInteger(e.bindingRevision)||e.bindingRevision<this.revision)return{applied:!1,reason:"stale-revision"};if(this.revision=e.bindingRevision,"binding-revoked"===e.type||"account-disabled"===e.type||"background-credential-revoked"===e.type)this.options.state.beginRevocation(),await Promise.all([this.options.connections.stop(e.type),this.options.dataConnections.closeAll(e.type)]),this.options.state.confirmRevocation();else if("remote-access-changed"===e.type)this.options.state.setRemoteAccess(!0===e.enabled),e.enabled||await Promise.all([this.options.connections.stop("remote-access-disabled"),this.options.dataConnections.closeAll("remote-access-disabled")]);else{if("identity-clone-detected"!==e.type)return{applied:!1,reason:"unsupported-event"};this.options.state.markCloneConflict(),await Promise.all([this.options.connections.stop(e.type),this.options.dataConnections.closeAll(e.type)])}return{applied:!0}}}class ff{connection;processInstanceId=`control_plane_process_${s.randomUUID().replaceAll("-","_")}`;backoff;options;constructor(e){this.options=e,this.backoff=e.backoff??new rm}async connectOnce(){const e=this.options.state.backgroundCredential(),t=this.options.state.snapshot();if(!t.remoteAccessEnabled||!("pending-claim"===t.status||"active"===t.status&&Boolean(e)))return{status:"disabled"};if(this.connection)return{status:"connected",reused:!0};const n=this.options.state.nextConnectionEpoch(),s=this.connection;return this.connection=await this.options.connector.connect({serviceOrigin:t.serviceOrigin,credential:e,bindingId:t.bindingId,bindingRevision:t.bindingRevision,controlPlaneId:t.identity.controlPlaneId,processInstanceId:this.processInstanceId,epoch:n,onEvent:this.options.onEvent}),await(s?.close("replaced-by-new-epoch")),this.backoff.reset(),{status:"connected",epoch:n}}reconnectDelay(){return this.backoff.next().delay}disconnected(){this.connection=void 0}async stop(e){const t=this.connection;this.connection=void 0,await(t?.close(e))}}class If{connections=new Map;options;constructor(e){this.options=e}async attach(e){const t=await this.options.verifyAllocation(e),n=this.connections.get(t.allocationId);if(n&&t.epoch<=n.epoch)throw Object.assign(new Error("Cloud connection state is invalid."),{code:"STALE_CONNECTION_EPOCH"});const s=await this.options.connector.connect({relayUrl:t.relayUrl,allocation:e,epoch:t.epoch});return await(n?.connection.close("replaced-by-new-epoch")),this.connections.set(t.allocationId,{epoch:t.epoch,connection:s}),{status:"attached",allocationId:t.allocationId,epoch:t.epoch}}async closeAll(e){const t=[...this.connections.values()];this.connections.clear(),await Promise.allSettled(t.map(({connection:t})=>t.close(e)))}}class bf{options;constructor(e){this.options=e}async disconnect(){const e=this.options.state.snapshot();if(!e.bindingId)return e;this.options.state.beginRevocation(),await this.options.connections.stop("binding-pending-revocation");try{if("revoked"===(await this.options.remote.revoke({bindingId:e.bindingId})).status)return this.options.state.confirmRevocation()}catch{}return this.options.state.snapshot()}async setRemoteAccess(e){const t=this.options.state.snapshot();if(this.options.state.setRemoteAccess(e),e||await this.options.connections.stop("remote-access-disabled"),t.bindingId)try{await this.options.remote.setRemoteAccess({bindingId:t.bindingId,enabled:e})}catch{return{...this.options.state.snapshot(),remoteResult:"unknown"}}return{...this.options.state.snapshot(),remoteResult:"confirmed"}}}class vf{options;constructor(e){this.options=e}async connect(e){const t=e.allocation,n=kn.parse(t.attach),s=An.parse(t.ticket),i=new(this.options.webSocket??p)(e.relayUrl,{followRedirects:!1,handshakeTimeout:1e4,perMessageDeflate:!1});return await function(e){return new Promise((t,n)=>{e.once("open",t),e.once("error",n),e.once("close",()=>n(zf("RELAY_SOCKET_CLOSED")))})}(i),i.send(JSON.stringify({type:"attach",capability:n})),async function(e,t,n,s,i){const r=await wf(e,e=>"frame"===e?.type&&"handshake"===e.frame?.kind);if(r.frame.channelId!==t||0!==r.frame.sequence)throw zf("RELAY_HANDSHAKE_SEQUENCE_INVALID");const o=JSON.parse(Buffer.from(r.frame.ciphertext,"base64url").toString("utf8")),a=s.acceptCloudAccessHandshake(n,o),d={...a.response,controlPlanePublicKey:s.publicIdentity().publicKey};e.send(JSON.stringify({type:"frame",frame:{protocolVersion:"2026-08-10",channelId:t,sequence:0,kind:"handshake",ciphertext:Buffer.from(JSON.stringify(d)).toString("base64url")}}));const c={type:"cloud-account",accountId:n.accountId,deviceSessionId:n.deviceSessionId,bindingId:n.bindingId,bindingRevision:n.bindingRevision},l=new Sf(e,t,a.sessionKey,c,i);return l.start(),{close:(e="normal")=>l.close(e)}}(i,(await wf(i,e=>"attached"===e?.type)).channelId,s,this.options.identity,this.options.bridge)}}class Sf{receiveSequence=1;sendSequence=1;receiveCounter=0;sendCounter=0;unsubscribe;ttys=new Map;socket;channelId;key;actor;bridge;constructor(e,t,n,s,i){this.socket=e,this.channelId=t,this.key=n,this.actor=s,this.bridge=i}start(){this.socket.on("message",e=>{this.receive(e).catch(()=>this.socket.close(4400,"encrypted-protocol-error"))}),this.socket.once("close",()=>{this.unsubscribe?.();for(const e of this.ttys.values())e.close();this.ttys.clear()})}async close(e){this.unsubscribe?.();for(const e of this.ttys.values())e.close();this.ttys.clear(),this.socket.readyState<p.CLOSING&&this.socket.close(1e3,e.slice(0,120))}async receive(e){const t=JSON.parse(e.toString()),n=t?.frame;if("frame"!==t?.type||n?.channelId!==this.channelId||n.sequence!==this.receiveSequence++)throw zf("RELAY_FRAME_SEQUENCE_INVALID");const s=w.secretbox.open(Buffer.from(n.ciphertext,"base64url"),Af(1,this.receiveCounter++),this.key);if(!s)throw zf("RELAY_E2E_DECRYPT_FAILED");const i=JSON.parse(Buffer.from(s).toString("utf8"));await this.dispatch(i)}async dispatch(e){if("request"===e.type&&e.id){try{const t=await this.bridge.request(this.actor,e.body);this.send({type:"response",id:e.id,status:t.status,body:t.body})}catch(t){this.send({type:"response",id:e.id,status:Number(t?.statusCode)||500,body:{error:{code:t?.code??"CONTROL_PLANE_ERROR",message:"Control Plane request failed."}}})}return}if("event-subscribe"===e.type){this.unsubscribe?.();const t=Array.isArray(e.body?.topics)?e.body.topics.map(String):["*"],n=yo.safeParse(e.body?.aiSessionTransient);return void(this.unsubscribe=this.bridge.subscribe(this.actor,t,e=>this.send({type:"event",event:e}),n.success?n.data:void 0))}if("tty-open"===e.type&&e.streamId&&this.bridge.openTty){const t=e.streamId,n=await this.bridge.openTty(this.actor,e.body,e=>this.send({...e,streamId:t}));return this.ttys.set(t,n),void this.send({type:"tty-opened",streamId:t})}const t=e.streamId?this.ttys.get(e.streamId):void 0;if(t&&"tty-input"===e.type)return t.send(String(e.data??""));if(t&&"tty-resize"===e.type)return t.resize(Number(e.body?.cols),Number(e.body?.rows));if(t&&"tty-close"===e.type)return t.close(),this.ttys.delete(e.streamId),void this.send({type:"tty-closed",streamId:e.streamId});if("cancel"!==e.type)throw zf("RELAY_ENVELOPE_UNSUPPORTED")}send(e){if(this.socket.readyState!==p.OPEN||this.socket.bufferedAmount>2097152)throw zf("RELAY_BACKPRESSURE_LIMIT");const t=w.secretbox(Buffer.from(JSON.stringify(e)),Af(2,this.sendCounter++),this.key);this.socket.send(JSON.stringify({type:"frame",frame:{protocolVersion:"2026-08-10",channelId:this.channelId,sequence:this.sendSequence++,kind:"cancel"===e.type?"cancel":"data",ciphertext:Buffer.from(t).toString("base64url")}}))}}function wf(e,t){return new Promise((n,s)=>{const i=e=>{try{const s=JSON.parse(e.toString());t(s)&&(o(),n(s))}catch(e){o(),s(e)}},r=()=>{o(),s(zf("RELAY_SOCKET_CLOSED"))},o=()=>{e.off("message",i),e.off("close",r)};e.on("message",i),e.once("close",r)})}function Af(e,t){const n=new Uint8Array(24);return n[0]=e,new DataView(n.buffer).setBigUint64(16,BigInt(t),!1),n}function zf(e){return Object.assign(new Error("Cloud Relay session is invalid."),{code:e,retryable:!0})}class kf{current;options;constructor(e){this.options=e}async connect(e){const t=this.options.identity.publicIdentity(),n=Date.now(),i={protocolVersion:"2026-08-10",audience:"task-handoff:coordinator-control",connectionId:`connection_${s.randomUUID().replaceAll("-","_")}`,processInstanceId:e.processInstanceId,controlPlaneId:t.controlPlaneId,publicKey:t.publicKey,publicKeyFingerprint:t.fingerprint,...e.bindingId?{bindingId:e.bindingId,bindingRevision:e.bindingRevision}:{},epoch:e.epoch,capabilities:["request","stream","websocket"],issuedAt:new Date(n).toISOString(),expiresAt:new Date(n+3e5).toISOString()},r=new URL("/api/v1/control-plane/connect",e.serviceOrigin);r.protocol="https:"===r.protocol?"wss:":"ws:";const o=new(this.options.webSocket??p)(r.href,{followRedirects:!1,handshakeTimeout:1e4});let a;return a=await function(e,t){return new Promise((n,i)=>{const r=new Map;let o,a=!1,d=!1;const c=e=>{for(const t of r.values())t.reject(e);r.clear(),a||i(e)},l={request(t,n){if(e.readyState!==p.OPEN)return Promise.reject(Cf("CLOUD_CONTROL_CONNECTION_UNAVAILABLE"));const i=`request_${s.randomUUID().replaceAll("-","_")}`;return e.send(JSON.stringify({type:"request",requestId:i,operation:t,payload:n})),new Promise((e,t)=>r.set(i,{resolve:e,reject:t}))},async close(t="normal"){d=!0,o&&clearInterval(o),e.close(1e3,t.slice(0,120))}};e.on("open",()=>e.send(JSON.stringify(t.register))),e.on("message",async s=>{let i;try{i=JSON.parse(s.toString())}catch{return e.close(1002,"invalid-json")}if("registered"===i.type)return a=!0,o=setInterval(()=>e.readyState===p.OPEN&&e.send(JSON.stringify({type:"heartbeat"})),1e4),o.unref(),n(l);if("event"===i.type)return t.onEvent(i.event);if("response"===i.type){const e=r.get(i.requestId);if(!e)return;return r.delete(i.requestId),i.error?e.reject(Object.assign(new Error(i.error.message),{code:i.error.code})):e.resolve(i.data)}if("request"===i.type&&t.onRequest)try{e.send(JSON.stringify({type:"response",requestId:i.requestId,data:await t.onRequest(i.operation,i.payload)}))}catch(t){e.send(JSON.stringify({type:"response",requestId:i.requestId,error:{code:t?.code??"REQUEST_FAILED",message:t instanceof Error?t.message:String(t)}}))}}),e.on("error",e=>c(e)),e.on("close",()=>{o&&clearInterval(o),c(Cf("CLOUD_CONTROL_CONNECTION_CLOSED")),d||t.onDisconnected()})})}(o,{register:{type:"register",registration:{...i,signature:this.options.identity.signCloudOutboundRegistration(i)},backgroundCredential:e.credential},onEvent:e.onEvent,onRequest:this.options.onRequest,onDisconnected:()=>{this.current===a&&(this.current=void 0),this.options.onDisconnected()}}),this.current=a,a}async request(e,t){if(!this.current)throw Cf("CLOUD_CONTROL_CONNECTION_UNAVAILABLE");return this.current.request(e,t)}}class Tf{lifecycle;dataConnections;connector;control;events;timer;running=!1;connecting;options;constructor(e){this.options=e,this.connector=new kf({identity:e.identity,webSocket:e.webSocket,onDisconnected:()=>{this.control.disconnected(),this.schedule()},onRequest:(e,t)=>this.handleRequest(e,t)});const t=e.relayConnector??(e.relayBridge?new vf({identity:e.identity,bridge:e.relayBridge,webSocket:e.webSocket}):{async connect(){throw Cf("CLOUD_RELAY_CONNECTOR_UNAVAILABLE")}});this.dataConnections=new If({verifyAllocation:e.verifyAllocation??(t=>function(e,t){const n=e,s=kn.parse(n?.attach),i=An.parse(n?.ticket),r=t.snapshot(),o=new URL(String(n?.relayUrl));if("relay-allocation"!==n?.type||n?.allocationId!==s.allocationId||"control-plane"!==s.role||s.ticketId!==i.ticketId||s.controlPlaneId!==i.controlPlaneId||s.accountId!==i.accountId||s.deviceSessionId!==i.deviceSessionId||s.bindingId!==i.bindingId||s.bindingRevision!==i.bindingRevision||"active"!==r.status||!r.remoteAccessEnabled||r.identity.controlPlaneId!==i.controlPlaneId||r.accountId!==i.accountId||r.bindingId!==i.bindingId||r.bindingRevision!==i.bindingRevision||i.targetPublicKeyFingerprint!==r.identity.fingerprint||Date.parse(s.expiresAt)<=Date.now())throw zf("RELAY_ALLOCATION_AUTHORITY_INVALID");if(!function(e,t){if("wss:"!==e.protocol)return!1;if("relay.thandoff.com"===e.hostname||e.hostname.endsWith(".relay.thandoff.com"))return!0;const n=new URL(t);return"cloud.thandoff.com"!==n.hostname&&e.hostname===n.hostname}(o,r.serviceOrigin))throw zf("UNTRUSTED_RELAY_URL");return{allocationId:s.allocationId,relayUrl:o.href,epoch:Date.parse(s.issuedAt),attach:s,ticket:i}}(t,e.state)),connector:t}),this.events=new yf({state:e.state,connections:{stop:e=>this.control.stop(e)},dataConnections:this.dataConnections}),this.control=new ff({state:e.state,connector:this.connector,onEvent:async e=>{await this.events.apply(e)}}),this.lifecycle=new bf({state:e.state,connections:this.control,remote:{revoke:async({bindingId:e})=>this.connector.request("revoke-binding",{bindingId:e}),setRemoteAccess:async({bindingId:e,enabled:t})=>{await this.connector.request("set-remote-access",{bindingId:e,enabled:t})}}})}start(){this.running=!0,"active"===this.options.state.snapshot().status&&this.schedule(0)}async stop(){this.running=!1,this.timer&&clearTimeout(this.timer),await Promise.all([this.control.stop("control-plane-stopping"),this.dataConnections.closeAll("control-plane-stopping")])}async publishBindingChallenge(e){await this.ensureConnected(),await this.connector.request("publish-binding-challenge",{payload:e.payload,signature:e.signature})}async request(e,t){return await this.ensureConnected(),this.connector.request(e,t)}async handleRequest(e,t){if("consume-binding-challenge"===e){const e=this.options.identity.publicIdentity();return this.options.state.consumeChallenge({challengeCode:t?.challengeCode,controlPlaneId:e.controlPlaneId,fingerprint:e.fingerprint})}if("deliver-binding-credential"===e)return this.options.state.activate(t);if("relay-allocation"===e)return this.dataConnections.attach(t);throw Cf("CLOUD_CONTROL_OPERATION_UNSUPPORTED")}async ensureConnected(){if(this.connecting||(this.connecting=this.control.connectOnce().finally(()=>{this.connecting=void 0})),"connected"!==(await this.connecting).status)throw Cf("CLOUD_CONTROL_CONNECTION_DISABLED")}schedule(e=this.control.reconnectDelay()){if(!this.running||this.timer)return;const t=this.options.state.snapshot();"active"===t.status&&t.remoteAccessEnabled&&(this.timer=setTimeout(()=>{this.timer=void 0,this.ensureConnected().catch(()=>this.schedule())},e),this.timer.unref())}}function Cf(e){return Object.assign(new Error("Cloud background connection is unavailable."),{code:e,retryable:!0})}const Ef="x-task-handoff-cloud-internal-actor",xf=d.z.object({code:d.z.string().trim().min(1),message:d.z.string(),details:d.z.record(d.z.string(),d.z.unknown()).optional(),retryable:d.z.boolean().optional()}).strict(),Nf=d.z.object({error:xf}).strict(),Rf="https://cloud.thandoff.com";function Of(e,t={}){const n=new URL(e||Rf).origin;if(n===Rf)return n;if(t.production||!0!==t.allowNonProduction)throw Object.assign(new Error("Non-production cloud service origin is not trusted by this build."),{code:"UNTRUSTED_CLOUD_SERVICE_ORIGIN"});return n}function _f(e){const t=process.env[e]?.trim();return t||void 0}const Pf=function(e,t=process.env,n=e){let s;return()=>{const i=t.TASK_HANDOFF_VERSION?.trim();return i||(s||=C(e,t,n),s)}}("@task-handoff/control-plane");function jf(){return{component:"control-plane",packageName:"@task-handoff/control-plane",packageVersion:Pf(),protocolVersion:ks,buildId:_f("TASK_HANDOFF_BUILD_ID"),builtAt:_f("TASK_HANDOFF_BUILT_AT"),gitCommit:_f("TASK_HANDOFF_GIT_COMMIT"),imageRef:_f("TASK_HANDOFF_IMAGE_REF"),imageDigest:_f("TASK_HANDOFF_IMAGE_DIGEST")}}const Df={".css":"text/css; charset=utf-8",".html":"text/html; charset=utf-8",".ico":"image/x-icon",".js":"text/javascript; charset=utf-8",".json":"application/json; charset=utf-8",".map":"application/json; charset=utf-8",".png":"image/png",".svg":"image/svg+xml",".webp":"image/webp"};function Mf(e,s){const i=t.resolve(e),r=t.resolve(i,s);if(r===i||r.startsWith(`${i}${t.sep}`))return n.existsSync(r)&&n.statSync(r).isFile()?r:void 0}function Lf(e,s,i){const r=Mf(s,i);return r?(e.header("cache-control","no-store"),e.type(Df[t.extname(r).toLowerCase()]||"application/octet-stream"),e.send(n.createReadStream(r))):e.code(404).send({error:{code:"STATIC_FILE_NOT_FOUND",message:`${i} was not found in the Control Plane UI static directory.`}})}function qf(e){if(e instanceof d.z.ZodError)return{statusCode:400,code:"VALIDATION_ERROR",message:e.issues.map(e=>`${e.path.join(".")||"body"}: ${e.message}`).join("; ")};const t=e&&"object"==typeof e?e:{};return{statusCode:"number"==typeof t.statusCode?t.statusCode:500,code:"string"==typeof t.code?t.code:"CONTROL_PLANE_ERROR",message:e instanceof Error?e.message:String(e),...t.details&&"object"==typeof t.details&&!Array.isArray(t.details)?{details:t.details}:{},..."boolean"==typeof t.retryable?{retryable:t.retryable}:{},..."number"==typeof t.retryAfterSeconds?{retryAfterSeconds:t.retryAfterSeconds}:{}}}function $f(e){const t=e.headers.authorization;if(void 0!==t){const e=/^Bearer ([^\s]+)$/.exec(t);return{token:e?.[1],clientType:"mobile"}}return{token:e.cookies[qo],clientType:"web"}}async function Bf(e,t){if(!e.enabled())return{type:"system",reason:"auth-disabled"};const n="mobile"===t.clientType?await e.userForMobileSessionToken(t.token):await e.userForSessionToken(t.token);return n?{type:"user",userId:n.id,role:n.role}:void 0}const Ff=new Set(["/api/auth/session","/api/auth/bootstrap-admin","/api/auth/login","/api/auth/logout","/api/auth/mobile/login","/api/control-plane/identity","/api/health","/api/events"]);function Uf(e,t){const n=t.split("?")[0]||"/";if(!n.startsWith("/api/"))return;if(Ff.has(n))return;const s=function(e){return"GET"===e||"HEAD"===e?"read":"POST"===e?"create":"PATCH"===e||"PUT"===e?"update":"DELETE"===e?"delete":"read"}(e);return"/api/control-plane/diagnostic-logs/export"===n?{action:"manage-settings",resource:{type:"control-plane-settings"}}:n.startsWith("/api/control-plane/settings")?{action:"GET"===e?"read":"manage-settings",resource:{type:"control-plane-settings"}}:"/api/auth/mobile/logout"===n||n.startsWith("/api/auth/mobile/sessions")||"/api/auth/password"===n?void 0:n.startsWith("/api/models")?{action:"GET"===e?"read":"manage-secrets",resource:{type:"model"}}:n.startsWith("/api/chat-gateway/bridges")?{action:"GET"===e?"read":"manage-secrets",resource:{type:"chat-bridge"}}:"/api/chat-gateway/messages"===n||"/api/chat-gateway/actions"===n?{action:"send-message",resource:{type:"ai-session"}}:"/api/chat-gateway/poll-ai-sessions"===n?{action:"manage-settings",resource:{type:"chat-bridge"}}:"/api/ai-session-attachments"===n?{action:"send-message",resource:{type:"ai-session"}}:"/api/node-join/invites"===n?{action:"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/control-plane-proxy")?{action:"GET"===e?"read":"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/nodes")?/\/(runtimes|local-folders)(\/|$)/.test(n)?{action:s,resource:{type:"runtime"}}:{action:"GET"===e?"read":"manage-node-auth",resource:{type:"node"}}:n.startsWith("/api/controlled-instances")?/\/apps\/sessions\/[^/]+\/access$/.test(n)?{action:"read",resource:{type:"instance"}}:n.includes("/ai-sessions")?n.includes("/triggers")?{action:s,resource:{type:"trigger"}}:"POST"===e&&/\/ai-sessions$/.test(n)?{action:"send-message",resource:{type:"ai-session"}}:n.endsWith("/approval")?{action:"approve",resource:{type:"ai-session"}}:n.endsWith("/interrupt")?{action:"interrupt",resource:{type:"ai-session"}}:n.endsWith("/resume")||n.endsWith("/fork")||n.endsWith("/commands")||n.includes("/messages")||n.includes("/queue/")?{action:"send-message",resource:{type:"ai-session"}}:n.endsWith("/read")||n.endsWith("/mentions/files")?{action:"read",resource:{type:"ai-session"}}:{action:s,resource:{type:"ai-session"}}:n.includes("/start")?{action:"start",resource:{type:"instance"}}:n.includes("/stop")?{action:"stop",resource:{type:"instance"}}:n.includes("/restart")?{action:"restart",resource:{type:"instance"}}:/\/config-sync(?:\/|$)/.test(n)?{action:"update",resource:{type:"instance"}}:{action:s,resource:{type:"instance"}}:n.startsWith("/api/projects")?{action:s,resource:{type:"project"}}:n.startsWith("/api/images")||n.startsWith("/api/image-options")||n.startsWith("/api/market")?{action:s,resource:{type:"runtime"}}:n.startsWith("/api/triggers")?{action:s,resource:{type:"trigger"}}:{action:s,resource:{type:"control-plane-settings"}}}async function Hf(e={}){const c=Cm(e.dataDir),l=i({logger:e.logger??!0});await l.register(r,{encodings:["br","gzip","deflate"],globalDecompression:!1,threshold:1024}),l.addContentTypeParser("application/octet-stream",(e,t,n)=>n(null,t));const p=new Mh,u=e.cloudConnectivityEnabled??"0"!==process.env.TASK_HANDOFF_CLOUD_CONNECTIVITY_ENABLED;let h=(g=process.env.TASK_HANDOFF_DIAGNOSTIC_LOGS,["1","true","yes","on"].includes(String(g||"").trim().toLowerCase()));var g;const y=function(e,s,i,r={}){const o=(o,a,d)=>{if(s()){i[o]?.(a,d);try{!function(e,s,i=10485760,r=2){const o=Buffer.isBuffer(s)?s:Buffer.from(s),a=o.byteLength>i?o.subarray(o.byteLength-i):o;if(n.mkdirSync(t.dirname(e),{recursive:!0,mode:448}),n.existsSync(e)){const t=n.lstatSync(e);if(!t.isFile()||t.isSymbolicLink())throw new Error(`Managed log path must be a regular file: ${e}`);t.size+a.byteLength>i&&(function(e,t){if(!(t<=0)){n.rmSync(of(e,t),{force:!0});for(let s=t-1;s>=1;s-=1){const t=of(e,s);n.existsSync(t)&&n.renameSync(t,of(e,s+1))}}}(e,r),r>0?t.size>i?(n.writeFileSync(of(e,1),function(e,t){const s=n.statSync(e),i=Math.min(s.size,t),r=Buffer.allocUnsafe(i),o=n.openSync(e,"r");let a=0;try{for(;a<i;){const e=n.readSync(o,r,a,i-a,s.size-i+a);if(0===e)break;a+=e}}finally{n.closeSync(o)}return a===i?r:r.subarray(0,a)}(e,i),{mode:384}),n.rmSync(e,{force:!0})):n.renameSync(e,of(e,1)):n.rmSync(e,{force:!0}))}n.appendFileSync(e,a,{mode:384}),n.chmodSync(e,384)}(t.join(e,"control-plane.log"),`${JSON.stringify({time:(new Date).toISOString(),level:o,message:d,data:cf(a)},(e,t)=>cf(t))}\n`,r.maxBytes??10485760,r.backupCount??2)}catch{}}};return{info:(e,t)=>o("info",e,t),warn:(e,t)=>o("warn",e,t),error:(e,t)=>o("error",e,t)}}(c.logsDir,()=>h,l.log),I=new rf;I.onChange(e=>p.publish("node.connection.updated",e,{topic:"node.state",scope:{nodeId:e.nodeId}}));const b=new Op(c,{...e.service,logger:y,nodeConnectionRuntime:I,onFleetStateChanged:t=>{e.service?.onFleetStateChanged?.(t),p.publish("node.fleet.updated",t,{topic:"instances"===t.resource?"instances":"models"===t.resource?"models":"node.runtime",scope:{nodeId:t.nodeId}})}}),v=new ia(c,e.auth),S=new sf(c.identitySigningPath,()=>b.proxyPrivateStore.controlPlaneId(),(e,t)=>l.log.warn(t,e)),w=new hf({statePath:c.cloudConnectivityPath,identity:S,serviceOrigin:Of(e.cloudServiceOrigin||process.env.TASK_HANDOFF_CLOUD_SERVICE_ORIGIN,{production:"production"===process.env.NODE_ENV,allowNonProduction:!0===e.allowNonProductionCloudOrigin||"staging"===process.env.TASK_HANDOFF_CLOUD_ENV})}),A=new Map,k=new Tf({state:w,identity:S,relayBridge:{async request(e,t){const n=String(t?.method||"GET").toUpperCase(),i=String(t?.path||""),r=Uf(n,i);if(!i.startsWith("/api/")||!r||Ff.has(i.split("?")[0]))throw Object.assign(new Error("Cloud access route is not available."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});Qm(e,r.action,r.resource);const o=s.randomBytes(32).toString("base64url");A.set(o,e);try{const e=Object.fromEntries(Object.entries(t.headers??{}).filter(([e])=>{const t=e.toLowerCase();return!function(e){return E.has(e.toLowerCase())}(t)&&!["host","connection","upgrade",Ef].includes(t)}).map(([e,t])=>[e,String(t)])),s=await l.inject({method:n,url:i,headers:{...e,[Ef]:o},...void 0===t.body?{}:{payload:t.body}});let r;try{r=s.json()}catch{r=s.body}return{status:s.statusCode,body:r}}finally{A.delete(o)}},subscribe(e,t,n,s){if("cloud-account"!==e.type)throw Object.assign(new Error("Cloud account actor required."),{code:"CLOUD_ACTOR_REQUIRED"});const i=new Set(t);if(!i.size)return()=>{};const r=p.on(e=>{(i.has("*")||i.has(e.topic)||i.has(e.type))&&fo(s,e)&&n(e)}),o=s?p.registerAiSessionTransientDemand(s):p.registerLegacyAiSessionTransientDemand(i);return()=>{r(),o()}},async openTty(e,t,n){const s=String(t?.instanceId||""),i=String(t?.sessionId||"");if(Qm(e,"proxy",{type:"instance",id:s}),!s||!i)throw Object.assign(new Error("TTY target is required."),{code:"TTY_TARGET_REQUIRED",statusCode:400});const r=new Map,o=(e,...t)=>{for(const n of r.get(e)??[])n(...t)};let a=!1;const d={readyState:1,on(e,t){const n=r.get(e)??new Set;n.add(t),r.set(e,n)},send(e){try{const t=JSON.parse(String(e));if("snapshot"===t.type){const e=xt.parse(t);n(Sn.parse({type:"tty-snapshot",data:e.data,pendingEscape:e.pendingEscape,cols:e.cols,rows:e.rows}))}else"output"===t.type?n({type:"tty-output",data:t.data}):"resize"===t.type?n({type:"tty-resize",body:{cols:t.cols,rows:t.rows}}):"exit"===t.type?n({type:"tty-exit",code:t.code,signal:t.signal}):"error"===t.type&&n({type:"tty-error"})}catch{n({type:"tty-error"})}},close(){a||(a=!0,o("close"),n({type:"tty-closed"}))}};return await b.proxyInstanceWebSocket(s,d,`/api/apps/sessions/${encodeURIComponent(i)}/tty`,[],{}),{send(e){a||o("message",Buffer.from(JSON.stringify({type:"input",data:e})))},resize(e,t){!a&&Number.isInteger(e)&&Number.isInteger(t)&&e>0&&t>0&&o("message",Buffer.from(JSON.stringify({type:"resize",cols:e,rows:t})))},close(){d.close()}}}}}),T=e.cloudConnectivityLifecycle?.(w)??k.lifecycle,C=e.publishCloudBindingChallenge??(e=>k.publishBindingChallenge(e)),x=new ry(p),N=new Zg(c,{onChanged:e=>queueMicrotask(()=>p.publish(q,e,{topic:"ai.sessions",scope:{instanceId:e.instanceId,sessionId:e.sessionId}}))});N.init();const R=new Qg({bootstrap:()=>b.bootstrapAiSessionsFromInstances(),logger:y,recoverDelta:(e,t,n)=>b.recoverAiSessionDelta(e,t,n),recoverSnapshot:e=>b.recoverAiSessionSnapshot(e),onRecoveredEvent:e=>p.publish(e.type,e.payload)});R.onSnapshot(e=>N.reconcile(e.instanceId,e.aiSessions));const O=new sy({bootstrap:()=>b.bootstrapAppSessionsFromInstances(),logger:y,recoverDelta:(e,t,n)=>b.recoverAppSessionDelta(e,t,n),recoverSnapshot:e=>b.recoverAppSessionSnapshot(e),onRecoveredEvent:e=>p.publish(e.type,e.payload)});b.setAppSessionSnapshotProvider(e=>O.list(e)),b.setAiSessionSnapshotProvider(e=>R.list(e));const _=new Qh(c.dataDir,{onWarning:e=>l.log.warn(e)});p.on(e=>{if(x.handle(e),"instance.deleted"===e.type||"instance.updated"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";t&&("instance.deleted"===e.type&&(O.removeInstance(t),R.removeInstance(t),N.removeInstance(t)),_.removeInstance(t))}});const P=new Kh;l.addHook("onClose",async()=>{P.dispose()});const j=new km(p,{connectionRuntime:I,validateInstanceScope:(e,t)=>b.nodeOwnsInstance(e,t),onStreamsHello:(e,t)=>{for(const n of t.streams)"ai.sessions"===n.topic&&R.advertiseStream(e,n),"app.sessions"===n.topic&&O.advertiseStream(e,n)},onSessionEvent:e=>e.type.startsWith("app-session.")?O.handleEvent(e):R.handleEvent(e)}),D=e.proxyOrigin||process.env.TASK_HANDOFF_CONTROL_PLANE_PROXY_ORIGIN,M=e=>{const t=b.nodes.get(e);return t?function(e,t){const n="reverse-wss"===e.connectionMode&&t,s=n?"online":e.status;return{id:e.id,name:e.name||e.id,status:s,health:e.health,...e.lastSeenAt?{lastSeenAt:e.lastSeenAt}:{},capabilities:xy(e.capabilities||{},262144),manageable:!1!==e.connectionEnabled&&(n||"online"===s)}}(t,j.connected(t.id)):void 0},L=new Sy(new yy(c.proxyAuthorityPath,(e,t)=>l.log.warn(t,e)),{get:M},{proxyOrigin:D,proxyOriginProvider:()=>b.getSettings().publicBaseUrl}),$=new Ay,B=new ky(p,{projectTarget:e=>{const t=M(e);return t?Ry(t):void 0}}),F=new Ky(b,{fetchImpl:e.service?.fetchImpl,logger:y,onStateChanged:e=>p.publish("node.proxy-state.updated",{nodeId:e.id,proxyState:e.proxyState},{topic:"node.state",scope:{nodeId:e.id}})});let U,H,W;p.on(e=>{if("node.created"!==e.type&&"node.updated"!==e.type&&"node.deleted"!==e.type||F.syncNow(),"instance.created"===e.type||"instance.updated"===e.type||"instance.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"instanceId"in e.payload?String(e.payload.instanceId||""):"";t&&j.invalidateInstanceScope({instanceId:t})}if("node.deleted"===e.type){const t=e.payload&&"object"==typeof e.payload&&"nodeId"in e.payload?String(e.payload.nodeId||""):"";if(t){j.invalidateInstanceScope({nodeId:t});const e=L.revokeTarget(t);for(const n of e.bindings)$.closeBinding(n.id,"Proxy target was deleted."),p.publish("control-plane-proxy.binding.updated",{binding:n},{topic:"control-plane-proxy",scope:{nodeId:t}})}}}),b.setNodeAgentTransport(j),b.init(),h=b.diagnosticLogsEnabled(),S.init(),w.init(),u&&k.start();const G=()=>{if(U)return U;const e=b.recoverPendingPairingRevokes().then(()=>{});return U=e,e.then(()=>{U===e&&(U=void 0)},()=>{U===e&&(U=void 0)}),e};await G().catch(e=>l.log.warn({error:e},"pending node pairing recovery failed")),L.init(),F.start(),await b.syncLocalNodeConnection().catch(()=>{}),v.init();const V=new oh(b,e.service?.fetchImpl,{aiSessions:R,logger:y,diagnosticLogsEnabled:()=>h});V.startEnabled();const K=new Tm(b,j,{safetyIntervalMs:Number(process.env.TASK_HANDOFF_EVENT_CONNECTION_SAFETY_INTERVAL_MS)||void 0,logger:y,connectionRuntime:I}),J=p.onAiSessionTransientDemand(e=>{K.setAiSessionTransientDemand(e)});K.start(),await l.register(o),await l.register(a),l.addHook("onClose",async()=>{await k.stop(),H&&clearInterval(H),W&&clearInterval(W),await(U?.catch(()=>{})),x.close(),B.stop(),F.stop(),K.stop(),J(),V.stopAll(),b.dispose()}),l.setErrorHandler((e,t,n)=>{const s=qf(e);void 0!==s.retryAfterSeconds&&n.header("retry-after",String(s.retryAfterSeconds)),(h||s.statusCode>=500)&&(s.statusCode>=500?l.log.error.bind(l.log):l.log.warn.bind(l.log))({method:t.method,url:t.url,statusCode:s.statusCode,errorCode:s.code,error:s.message},"control plane request failed"),n.code(s.statusCode).send(Nf.parse({error:{code:s.code,message:s.message,...s.details?{details:s.details}:{},...void 0!==s.retryable?{retryable:s.retryable}:{}}}))}),l.addHook("preHandler",async(e,t)=>{const n=e.routeOptions.url,s=n&&"*"!==n?n:e.url,i=e.routeOptions.config.controlPlaneAuthBoundary,r=e.headers[Ef],o="string"==typeof r?A.get(r):void 0;if(o){A.delete(r);const t=Uf(e.method,s);if(!t)throw Object.assign(new Error("Cloud access route is not authorized."),{code:"CLOUD_ROUTE_FORBIDDEN",statusCode:403});return void Qm(o,t.action,t.resource)}if("proxy-binding"===i||"node-tunnel"===i)return;const a="public"===i||"public-ui"===i&&function(e){const t=e.split("?")[0]||"/";return!t.startsWith("/api/")&&"/api"!==t&&!t.startsWith("/instances/")&&"/instances"!==t}(e.url);if(!v.enabled()||a){const t=await Bf(v,$f(e)),n=Uf(e.method,s);return void(n&&Qm(t||{type:"system",reason:"auth-disabled"},n.action,n.resource))}const d=await Bf(v,$f(e));if(!d)return t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access the Control Plane."}});const c=Uf(e.method,s);c&&Qm(d,c.action,c.resource)});const Y=t.resolve(e.staticDir||process.env.TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR||t.resolve(process.cwd(),"packages","control-plane-ui","dist"));n.existsSync(Y)&&(l.get("/assets/*",{config:em},async(e,n)=>{const s=e.params["*"];return Lf(n,Y,t.join("assets",s||""))}),l.get("/favicon.ico",{config:em},async(e,t)=>Mf(Y,"favicon.ico")?Lf(t,Y,"favicon.ico"):t.code(204).send())),l.get("/api/health",{config:em},async()=>Ri.parse({data:{ok:!0,role:"control-plane",protocolVersion:ks,build:jf(),serverTime:(new Date).toISOString()}})),l.get("/api/control-plane/identity",{config:em},async()=>S.publicDocument(v.enabled()?"required":"disabled"));const Q=async e=>{if(!u)throw Object.assign(new Error("Cloud connectivity is disabled by feature flag."),{code:"CLOUD_CONNECTIVITY_DISABLED",statusCode:503});Qm(await Bf(v,$f(e))||{type:"system",reason:"auth-disabled"},"manage-settings",{type:"control-plane-settings"})};return l.get("/api/cloud-connectivity",async e=>(await Q(e),{data:w.snapshot()})),l.post("/api/cloud-connectivity/challenges",async(e,t)=>{await Q(e),t.header("cache-control","no-store");const n=w.createChallenge();return await C(n),{data:n}}),l.post("/api/cloud-connectivity/remote-access",async e=>{await Q(e);const t=d.z.object({enabled:d.z.boolean()}).strict().parse(e.body);return{data:T?await T.setRemoteAccess(t.enabled):w.setRemoteAccess(t.enabled)}}),l.post("/api/cloud-connectivity/disconnect",async e=>(await Q(e),{data:T?await T.disconnect():w.beginRevocation()})),l.get("/api/session-streams/diagnostics",async()=>({data:{aiSessions:R.diagnostics(),aiSessionActions:b.aiSessionActionDiagnostics(),appSessions:O.diagnostics(),nodeConnections:{...K.diagnostics(),runtime:I.diagnostics()}}})),l.get("/install-node-agent.sh",{config:em},async(e,t)=>(t.header("cache-control","no-store"),t.type("text/x-shellscript; charset=utf-8"),iy`#!/bin/sh
|
|
2
2
|
set -eu
|
|
3
3
|
|
|
4
4
|
CONTROL_PLANE_URL=""
|
|
@@ -220,4 +220,4 @@ fi
|
|
|
220
220
|
echo "TaskHandoff node-agent is installed and running."
|
|
221
221
|
echo "Service: task-handoff-node-agent.service"
|
|
222
222
|
echo "Pairing token: sudo task-handoff-node-agent invite --ipc-path $IPC_PATH"
|
|
223
|
-
`)),c.get("/api/events",{websocket:!0},async(e,t)=>{const n=t.query,i="string"==typeof n.instanceId?n.instanceId.trim():"",s=[];let r=!1;const o={get readyState(){return e.readyState},OPEN:e.OPEN,send(t){r?e.send(t):s.push(t)},on(t,n){e.on(t,n)}};l.connect(o,{instanceIds:i?[i]:void 0});const[a,d]=await Promise.all([x.streamDescriptors(),N.streamDescriptors()]);l.send(e,"streams.hello",{protocolVersion:1,streams:[...a,...d].filter(e=>!i||e.instanceId===i)}),r=!0;for(const t of s)e.send(t);for(const t of E.snapshots().filter(e=>!i||e.instanceId===i))l.send(e,"image.pull.snapshot",t,{topic:"instances",scope:{instanceId:t.instanceId}})}),c.get("/api/auth/session",{config:vm},async e=>{const t=Vy(e);return{data:await b.currentSession(t.token,t.clientType)}}),c.post("/api/auth/bootstrap-admin",{config:vm},async(e,t)=>{const n=await b.bootstrapAdmin(e.body);return t.code(201).send({data:n})}),c.post("/api/auth/login",{config:vm},async(e,t)=>{const n=await b.login(e.body,{sourceId:e.ip});return t.setCookie(vo,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),c.post("/api/auth/mobile/login",{config:vm},async e=>({data:await b.loginMobile(e.body,{sourceId:e.ip})})),c.patch("/api/auth/password",async(e,t)=>{const n=await b.changePassword(e.cookies[vo],e.body,{sourceId:e.ip});return t.setCookie(vo,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),c.post("/api/auth/mobile/logout",async e=>{const t=Vy(e);return{data:b.logout("mobile"===t.clientType?t.token:void 0)}}),c.get("/api/auth/mobile/sessions",async(e,t)=>{const n=b.mobileSessions(Vy(e).token);return n?{data:n}:t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access mobile sessions."}})}),c.delete("/api/auth/mobile/sessions/:id",async(e,t)=>{const n=a.z.object({id:a.z.string().trim().min(1)}).parse(e.params),i=b.revokeMobileSession(Vy(e).token,n.id);return void 0===i?t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to revoke mobile sessions."}}):{data:{revoked:i}}}),c.post("/api/auth/logout",{config:vm},async(e,t)=>{const n=b.logout(e.cookies[vo]);return t.clearCookie(vo,{path:"/"}),{data:n}}),c.get("/api/control-plane/status",async()=>({data:{protocolVersion:ui,build:Uy(),storage:d}})),c.get("/api/control-plane/settings",async()=>({data:I.getSettings()})),c.patch("/api/control-plane/settings",async e=>{const t=I.updateSettings(e.body||{});return u=t.diagnosticLogs,{data:t}}),c.get("/api/control-plane/diagnostic-logs/export",async(e,i)=>{const s=await async function(e){const i=n.mkdtempSync(t.join(y.tmpdir(),"task-handoff-diagnostic-logs-")),s=t.resolve(e.nodeAgentDataDir||t.join(e.dataDir,"node-agent")),r=t.join(s,"local-instances"),o=n.existsSync(r)?n.readdirSync(r,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.isSymbolicLink()).map(e=>({label:t.join("local-instances",e.name),root:t.join(r,e.name,"logs")})):[],a=[{label:"control-plane",root:t.join(e.dataDir,"logs")},{label:"desktop",root:t.join(e.dataDir,"log")},{label:"node-agent",root:t.join(s,"logs")},...o],d=[];let c=0;for(const e of a)for(const s of yy(e.root)){if(c>=gy)break;const r=t.relative(e.root,s);if(!r||r.startsWith("..")||t.isAbsolute(r))continue;const o=t.join("logs",e.label,r),a=n.statSync(s).size,l=fy(s,t.join(i,o),gy-c);l&&(c+=l,d.push({source:s,archivePath:o,bytes:l,originalBytes:a}))}n.writeFileSync(t.join(i,"manifest.json"),`${JSON.stringify({createdAt:(new Date).toISOString(),diagnosticLogsEnabled:e.diagnosticLogsEnabled,limits:{perFileBytes:my,totalBytes:gy},files:d.map(({archivePath:e,bytes:t,originalBytes:n})=>({archivePath:e,bytes:t,originalBytes:n,truncated:t<n}))},null,2)}\n`,{mode:384});const l=["manifest.json",...n.existsSync(t.join(i,"logs"))?["logs"]:[]],p=A.create({cwd:i,gzip:!0,portable:!0,noMtime:!0},l),u=()=>n.rmSync(i,{recursive:!0,force:!0});return p.once("close",u),p.once("error",u),{filename:`task-handoff-diagnostic-logs-${(new Date).toISOString().replace(/[:.]/g,"-")}.tar.gz`,stream:p}}({dataDir:d.dataDir,nodeAgentDataDir:process.env.TASK_HANDOFF_DESKTOP_NODE_AGENT_DATA_DIR||process.env.TASK_HANDOFF_NODE_AGENT_DATA_DIR,diagnosticLogsEnabled:u});return i.header("content-type","application/gzip"),i.header("content-disposition",`attachment; filename="${s.filename}"`),i.send(s.stream)}),c.post("/api/ai-session-attachments",{bodyLimit:33554432},async(e,t)=>{try{return t.code(201).send({data:O.upload(e.body)})}catch(e){return t.code(400).send({error:{code:"AI_SESSION_ATTACHMENT_INVALID",message:e instanceof Error?e.message:String(e)}})}}),Fg({app:c,service:I,events:l,appSessionAggregator:N,aiSessionAggregator:x,aiSessionUnread:C,chatGateway:H,aiSessionAttachments:O,nodeAgentTunnel:_,nodeEventSubscriber:W,errorPayload:Gy}),function(e){const{app:t,authority:n,resolveTarget:i,projectTarget:s,eventHub:r}=e,o=e.runtime??new Oh,a=new WeakMap,d=(e,t)=>{const n=a.get(e);n&&(a.delete(e),n.tracked.release(),e.raw.removeListener("aborted",n.abort),t.raw.removeListener("close",n.abort))};t.all("/api/node-proxy/bindings/:bindingId/http/*",{config:Sm,bodyLimit:o.maxRequestBodyBytes,logLevel:"silent",async onRequest(e,t){try{const i=$h.parse(e.params).bindingId,s=Wh(n,i,e),r=function(e){const t=e.raw.url||e.url,n=/^\/api\/node-proxy\/bindings\/[^/]+\/http(\/[^#]*)$/.exec(t);if(!n||/%(?:2f|5c)/i.test(n[1]))throw Qh(Hn.RouteInvalid,"Proxy route is invalid.",400);const i=Mn.safeParse(n[1]);if(!i.success)throw Qh(Hn.RouteInvalid,i.error.issues[0]?.message||"Proxy route is invalid.",400);return i.data}(e),c=Kh(e.headers),l=o.reserveHttp(s.id),p=()=>{l.controller.abort(Object.assign(new Error("Proxy HTTP consumer disconnected."),{name:"AbortError",code:"ABORT_ERR"})),d(e,t)};a.set(e,{binding:s,route:r,forwardedHeaders:c,tracked:l,abort:p}),e.raw.once("aborted",p),t.raw.once("close",p)}catch(n){return Jh(t,n,e)}},async onError(e,t){d(e,t);const n=Zh(e.headers);n&&t.header("x-request-id",n)},async onResponse(e,t){d(e,t)}},async(e,t)=>{try{const r=a.get(e);if(!r)throw Qh(Hn.TransportFailed,"Proxy request context is unavailable.",500,!0);const{binding:o,route:c,forwardedHeaders:l,tracked:p,abort:u}=r;!function(e,t,n){const i=new URL(t,"https://node-agent.invalid").searchParams,s=[i.get("nodeId"),i.get("targetNodeId")];if(n&&"object"==typeof n&&!Array.isArray(n)){const e=n;"string"==typeof e.nodeId&&s.push(e.nodeId),"string"==typeof e.targetNodeId&&s.push(e.targetNodeId)}const r=s.find(t=>null!==t&&t!==e.targetNodeId);if(void 0!==r)throw Qh(Hn.TargetMismatch,"Proxy request attempts to select a target outside its binding.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}(o,c,e.body);const g=null==(s=e.body)?void 0:Buffer.isBuffer(s)?s:s instanceof Uint8Array||"string"==typeof s?Buffer.from(s):Buffer.from(JSON.stringify(s));p.acceptRequestBody(g?.byteLength??0);try{const{node:s,transport:r}=await i(o.targetNodeId);return Gh(n,o,e),Vh(o,s),function(e,t,n,i,s,r){t.body&&n.beginResponseStream();for(const[n,i]of Object.entries(function(e,t){const n=Object.fromEntries([...qn].flatMap(t=>{const n=e.headers.get(t);return null===n?[]:[[t,n]]}));return t&&(n["x-request-id"]=t),n}(t,r)))e.header(n,i);const o=()=>{n.release(),s.raw.removeListener("aborted",i),e.raw.removeListener("close",i)};if(!t.body)return o(),e.code(t.status).send();const a=m.Readable.fromWeb(t.body);return n.controller.signal.addEventListener("abort",()=>{const e=n.controller.signal.reason;a.destroy(e instanceof Error?e:new Error("Proxy HTTP stream aborted."))},{once:!0}),a.on("data",e=>{try{n.acceptResponseChunk(e)}catch(e){a.destroy(e)}}),a.once("end",o),a.once("error",o),a.once("close",o),e.raw.once("close",()=>a.destroy()),e.code(t.status).send(a)}(t,await r.requestStream(s,c,{method:e.method,headers:l,...g?{body:g}:{},signal:p.controller.signal}),p,u,e,l["x-request-id"])}catch(n){throw d(e,t),n}}catch(n){return d(e,t),Jh(t,n,e)}var s}),t.get("/api/node-proxy/bindings/:bindingId/websocket",{websocket:!0,logLevel:"silent",config:Sm},async(e,t)=>{let s;try{const r=$h.parse(t.params).bindingId,a=Wh(n,r,t),d=Bh.parse(t.query).route,{node:c,transport:l}=await i(a.targetNodeId);Gh(n,a,t),Vh(a,c),s=o.openWebSocket(a.id,e),l.proxyWebSocket(c,s,d,function(e){const t=Xh(e,"sec-websocket-protocol").split(",").map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}(t.headers),Kh(t.headers))}catch(t){const n=Yh(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,ey(n.message))}}),t.get("/api/node-proxy/bindings/:bindingId/snapshot",{config:Sm},async(e,t)=>{try{const t=$h.parse(e.params).bindingId,a=Wh(n,t,e),{node:d}=await i(a.targetNodeId);Gh(n,a,e),Vh(a,d);const c=s(a.targetNodeId);if(!c)throw Qh(Hn.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:a.targetNodeId});const l=r.cursor(a.targetNodeId),p=si.parse({protocolVersion:Nn,binding:a,streamId:l.streamId,revision:l.revision,observedAt:(new Date).toISOString(),target:qh(c)});if(o=p,Buffer.byteLength(JSON.stringify(o),"utf8")>Hh)throw Qh(Hn.ResourceLimit,"Proxy target snapshot byte limit exceeded.",429,!0,{bindingId:a.id,resource:"snapshot-bytes",limit:Hh});return{data:p}}catch(n){return Jh(t,n,e)}var o}),t.get("/api/node-proxy/bindings/:bindingId/events",{websocket:!0,logLevel:"silent",config:Sm},async(e,t)=>{let s,a,d;try{const c=$h.parse(t.params).bindingId,l=Wh(n,c,t),p=Uh.parse(t.query),{node:u}=await i(l.targetNodeId);Gh(n,l,t),Vh(l,u),s=o.openWebSocket(l.id,e,()=>a?.()),s.on("message",()=>s?.close(1008,"Proxy event streams do not accept client messages."));const m=r.subscribe({bindingId:l.id,sourceControlPlaneId:l.sourceControlPlaneId,targetNodeId:l.targetNodeId},p.sinceRevision,e=>{s?.send(JSON.stringify(e))},()=>{s?.close(1011,"Proxy event delivery failed.")});a=m.close,d=o.registerBindingCleanup(l.id,a);const g=()=>{a?.(),d?.()};s.on("close",g),s.on("error",g),"snapshot-required"===m.kind?(a(),s.close(1008,"Proxy target snapshot is required.")):1!==s.readyState&&a()}catch(t){a?.(),d?.();const n=Yh(t);s?.close(1008,n.message),s||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,ey(n.message))}}),t.delete("/api/node-proxy/bindings/:bindingId",{config:Sm},async(t,i)=>{try{const i=$h.parse(t.params).bindingId;Wh(n,i,t);const s=n.revokeBinding(i),r=o.closeBinding(i);return e.onBindingRevoked?.(s),{data:{binding:s,closed:r}}}catch(e){return Jh(i,e,t)}})}({app:c,authority:D,resolveTarget:e=>{const t=I.requireNode(e);return{node:t,transport:I.resolveNodeAgentTransport(t)}},projectTarget:P,runtime:M,eventHub:L,onBindingRevoked:e=>l.publish("control-plane-proxy.binding.updated",{binding:e,audit:{action:"binding.revoke",actor:`control-plane:${e.sourceControlPlaneId}`}},{topic:"control-plane-proxy",scope:{nodeId:e.targetNodeId}})}),function(e){const{app:t,service:n,proxy:i,runtime:s,events:r,actorId:o}=e;t.get("/api/control-plane-proxy/invites",async()=>({data:i.listInvites()})),t.post("/api/control-plane-proxy/invites",async(e,t)=>{const n=await o(e),s=i.createInvite(e.body,n);return r.publish("control-plane-proxy.invite.created",{invite:s.invite,audit:{action:"invite.create",actor:n}},{topic:"control-plane-proxy",scope:{nodeId:s.invite.targetNodeId}}),t.code(201).send({data:s})}),t.delete("/api/control-plane-proxy/invites/:id",async e=>{const t=await o(e),n=i.revokeInvite(sy.parse(e.params).id);return r.publish("control-plane-proxy.invite.updated",{invite:n,audit:{action:"invite.revoke",actor:t}},{topic:"control-plane-proxy",scope:{nodeId:n.targetNodeId}}),{data:n}}),t.get("/api/control-plane-proxy/bindings",async()=>({data:i.listBindings()})),t.delete("/api/control-plane-proxy/bindings/:id",async e=>{const t=await o(e),n=sy.parse(e.params).id,a=i.revokeBinding(n),d=s.closeBinding(n);return r.publish("control-plane-proxy.binding.updated",{binding:a,audit:{action:"binding.revoke",actor:t}},{topic:"control-plane-proxy",scope:{nodeId:a.targetNodeId}}),{data:{binding:a,closed:d}}}),t.get("/api/control-plane-proxy/diagnostics",async()=>({data:s.diagnostics()})),t.post("/api/node-proxy/claims",{config:vm},async(e,t)=>{const n=i.claimInvite(e.body);return r.publish("control-plane-proxy.binding.created",{binding:n.binding,audit:{action:"binding.claim",actor:`control-plane:${n.binding.sourceControlPlaneId}`}},{topic:"control-plane-proxy",scope:{nodeId:n.binding.targetNodeId}}),t.code(201).send({data:n})}),t.get("/api/control-plane-proxy/pending-claims",async()=>({data:n.listPendingProxyClaims()})),t.post("/api/control-plane-proxy/claims",async(e,t)=>{const i=await n.claimProxyNode(e.body);return r.publish("node.created",{nodeId:i.node.id}),t.code(201).send({data:i})}),t.post("/api/control-plane-proxy/pending-claims/:id/resume",async e=>{const t=sy.parse(e.params).id;ry.parse(e.body||{});const i=await n.resumeProxyClaim(t);return r.publish("node.created",{nodeId:i.node.id}),{data:i}}),t.delete("/api/control-plane-proxy/pending-claims/:id",async e=>({data:await n.cancelProxyClaim(sy.parse(e.params).id)}))}({app:c,service:I,proxy:D,runtime:M,events:l,actorId:async e=>{const t=await Ky(b,Vy(e));return t?"user"===t.type?`user:${t.userId}`:"system"===t.type?`system:${t.reason}`:"cloud-account"===t.type?`cloud-account:${t.accountId}:${t.deviceSessionId}`:`chat-bridge:${t.bridgeId}`:"system:unknown"}}),function({app:e,service:t}){!function(e){for(const t of["application/octet-stream","application/x-www-form-urlencoded"])th(e,t);th(e,/^multipart\/form-data(?:;.*)?$/i)}(e),e.get("/api/app-access/session",{config:vm},async e=>{const n=nh(e.url),i="vnc"===e.query.mode?"vnc":"web"===e.query.mode?"web":"tty",s=await t.appAccessProxyTarget(n,i);return{data:{mode:i,instance:{id:s.instance.id,name:s.instance.name,projectId:s.instance.projectId,projectName:"string"==typeof s.instance.sourceSnapshot.name?s.instance.sourceSnapshot.name:void 0},session:s.session,expiresAt:s.access.expiresAt,ttySocketPath:"tty"===i?`/apps/access/tty/ws?token=${encodeURIComponent(n)}`:void 0,vncFramePath:"vnc"===i?ih(n,s.access.sessionId,s.session):void 0}}}),e.get("/apps/access/tty/ws",{websocket:!0,config:vm},async(e,n)=>{try{const i=await t.appAccessProxyTarget(nh(n.url),"tty");await t.proxyInstanceWebSocket(i.instance.id,e,i.path,Jg(n.headers),Kg(n.headers))}catch{e.close(1011,"TTY access link is invalid or expired.")}});const n=async(e,n)=>{const i=n.params;try{const s=await t.appAccessProxyTarget(i.token||nh(n.url),"vnc",i["*"]||"");await t.proxyInstanceWebSocket(s.instance.id,e,s.path,Jg(n.headers),Kg(n.headers))}catch{e.close(1011,"VNC access link is invalid or expired.")}};e.route({method:"GET",url:"/apps/access/vnc/proxy/*",config:vm,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(nh(e.url),"vnc",i["*"]||"");return Zg(n,await Yg(t,n,s.instance.id,s.path,{method:e.method,headers:Vg(e.headers)}),s.instance.id,s.path)}}),e.route({method:"GET",url:"/apps/access/vnc/:token/proxy/*",config:vm,wsHandler:n,handler:async(e,n)=>{const i=e.params,s=await t.appAccessProxyTarget(i.token,"vnc",i["*"]||"");return Zg(n,await Yg(t,n,s.instance.id,s.path,{method:e.method,headers:Vg(e.headers)}),s.instance.id,s.path)}}),e.all("/instances/:id",{bodyLimit:67108864},async(e,n)=>{const i=e.params;return"GET"===e.method||"HEAD"===e.method?n.redirect(`${Xg(i.id)}/`):Zg(n,await Yg(t,n,i.id,"/",{method:e.method,headers:Vg(e.headers),body:eh(e.body)}),i.id,"/")}),e.route({method:"GET",url:"/instances/:id/*",wsHandler:async(e,n)=>{const i=n.params,s=i["*"]||"",r=n.url.indexOf("?"),o=r>=0?n.url.slice(r):"";try{await t.proxyInstanceWebSocket(i.id,e,`/${s}${o}`,Jg(n.headers),Kg(n.headers))}catch{e.close(1011,"Instance websocket endpoint is not reachable.")}},handler:async(e,n)=>{const i=e.params,s=i["*"]||"",r=e.url.indexOf("?"),o=`/${s}${r>=0?e.url.slice(r):""}`;return Zg(n,await Yg(t,n,i.id,o,{method:e.method,headers:Vg(e.headers)}),i.id,o)}}),e.route({method:["POST","PUT","PATCH","DELETE","OPTIONS"],url:"/instances/:id/*",bodyLimit:67108864,handler:async(e,n)=>{const i=e.params,s=i["*"]||"",r=e.url.indexOf("?"),o=r>=0?e.url.slice(r):"";return Qg(n,await Yg(t,n,i.id,`/${s}${o}`,{method:e.method,headers:Vg(e.headers),body:eh(e.body)}))}})}({app:c,service:I}),c.get("*",{config:wm},async(e,t)=>n.existsSync(G)?Wy(t,G,"index.html"):t.code(404).send({error:{code:"CONTROL_PLANE_UI_NOT_BUILT",message:"Control plane API is running, but the Web UI static directory was not found."}})),B=setInterval(()=>{F().catch(e=>c.log.warn({error:e},"pending node pairing recovery failed"))},3e4),B.unref(),U=setInterval(()=>{I.runPersistenceMaintenance()},216e5),U.unref(),c}function Xy(e){const t=Number(e);if(!Number.isInteger(t)||t<=0||t>65535)throw new Error("Port must be a valid TCP port.");return t}function Zy(e){if("disabled"!==e&&"password"!==e)throw new Error("Auth mode must be disabled or password.");return e}(async function(){const n=new e.Command;n.name("task-handoff-control-plane").description("Run the TaskHandoff control plane.").version(T("@task-handoff/cli")).option("--host <host>","Control plane host",process.env.TASK_HANDOFF_CONTROL_PLANE_HOST||"127.0.0.1").option("-p, --port <port>","Control plane port",Xy,Number(process.env.TASK_HANDOFF_CONTROL_PLANE_PORT)||8081).option("--data-dir <path>","Control plane data directory").option("--static-dir <path>","Control plane Web UI static directory",process.env.TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR||t.resolve(__dirname,"..","ui")).option("--auth-mode <mode>","Control plane auth mode: disabled or password",Zy,process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"password").action(async e=>{await async function(e){const t=Um(e.dataDir),n=cg(dg(),{dataDir:t.dataDir,host:e.host,port:e.port});try{const t=await Qy(e);t.addHook("onClose",async()=>{n.release()}),await t.listen({host:e.host,port:e.port})}catch(t){if(n.release(),t&&"object"==typeof t&&"EADDRINUSE"===t.code)throw Object.assign(new Error(`Control plane port ${e.host}:${e.port} is already in use.`),{statusCode:409,code:"CONTROL_PLANE_PORT_IN_USE",cause:t});throw t}}({host:e.host,port:e.port,dataDir:e.dataDir,staticDir:e.staticDir,auth:{mode:e.authMode}})}),n.command("credentials").description("Replace the Control Plane administrator username and password while the service is stopped.").requiredOption("--username <username>","New administrator username").requiredOption("--password-stdin","Read the new password from standard input").option("--data-dir <path>","Control plane data directory").action(async e=>{if(process.stdin.isTTY)throw new Error("Pipe the new password to standard input when using --password-stdin.");const t=[];for await(const e of process.stdin)t.push(Buffer.isBuffer(e)?e:Buffer.from(e));const n=Buffer.concat(t).toString("utf8").replace(/\r?\n$/,""),i=await async function(e,t,n={}){const i=Um(e),s=cg(n.lockPath||dg(),{dataDir:i.dataDir});try{const e=new $o(i,{mode:"password"});return e.init(),await e.replaceCredentials(t)}finally{s.release()}}(e.dataDir,{username:e.username,password:n});console.log(`Updated Control Plane credentials for ${i.username}. Existing sessions were revoked.`)}),await n.parseAsync(process.argv)})().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
|
|
223
|
+
`)),l.get("/api/events",{websocket:!0},async(e,t)=>{const n=t.query,s="string"==typeof n.instanceId?n.instanceId.trim():"",i=[];let r=!1;const o={get readyState(){return e.readyState},get bufferedAmount(){return e.bufferedAmount},OPEN:e.OPEN,send(t){r?e.send(t):i.push(t)},on(t,n){e.on(t,n)},close(t,n){e.close(t,n)}};p.connect(o,{instanceIds:s?[s]:void 0,expectsTransientSubscription:"1"===n.aiSessionTransient});const[a,d]=await Promise.all([R.streamDescriptors(),O.streamDescriptors()]);p.send(e,"streams.hello",{protocolVersion:1,streams:[...a,...d].filter(e=>!s||e.instanceId===s)}),r=!0;for(const t of i)e.send(t);for(const t of x.snapshots().filter(e=>!s||e.instanceId===s))p.send(e,"image.pull.snapshot",t,{topic:"instances",scope:{instanceId:t.instanceId}})}),l.get("/api/auth/session",{config:em},async e=>{const t=$f(e);return{data:await v.currentSession(t.token,t.clientType)}}),l.post("/api/auth/bootstrap-admin",{config:em},async(e,t)=>{const n=await v.bootstrapAdmin(e.body);return t.code(201).send({data:n})}),l.post("/api/auth/login",{config:em},async(e,t)=>{const n=await v.login(e.body,{sourceId:e.ip});return t.setCookie(qo,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),l.post("/api/auth/mobile/login",{config:em},async e=>({data:await v.loginMobile(e.body,{sourceId:e.ip})})),l.patch("/api/auth/password",async(e,t)=>{const n=await v.changePassword(e.cookies[qo],e.body,{sourceId:e.ip});return t.setCookie(qo,n.sessionToken,{path:"/",httpOnly:!0,sameSite:"lax",expires:new Date(n.expiresAt)}),{data:{user:n.user}}}),l.post("/api/auth/mobile/logout",async e=>{const t=$f(e);return{data:v.logout("mobile"===t.clientType?t.token:void 0)}}),l.get("/api/auth/mobile/sessions",async(e,t)=>{const n=v.mobileSessions($f(e).token);return n?{data:n}:t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to access mobile sessions."}})}),l.delete("/api/auth/mobile/sessions/:id",async(e,t)=>{const n=d.z.object({id:d.z.string().trim().min(1)}).parse(e.params),s=v.revokeMobileSession($f(e).token,n.id);return void 0===s?t.code(401).send({error:{code:"CONTROL_PLANE_AUTH_REQUIRED",message:"Sign in to revoke mobile sessions."}}):{data:{revoked:s}}}),l.post("/api/auth/logout",{config:em},async(e,t)=>{const n=v.logout(e.cookies[qo]);return t.clearCookie(qo,{path:"/"}),{data:n}}),l.get("/api/control-plane/status",async()=>({data:{protocolVersion:ks,build:jf(),storage:c}})),l.get("/api/control-plane/settings",async()=>({data:b.getSettings()})),l.patch("/api/control-plane/settings",async e=>{const t=b.updateSettings(e.body||{});return h=t.diagnosticLogs,{data:t}}),l.get("/api/control-plane/diagnostic-logs/export",async(e,s)=>{const i=await async function(e){const s=n.mkdtempSync(t.join(f.tmpdir(),"task-handoff-diagnostic-logs-")),i=t.resolve(e.nodeAgentDataDir||t.join(e.dataDir,"node-agent")),r=t.join(i,"local-instances"),o=n.existsSync(r)?n.readdirSync(r,{withFileTypes:!0}).filter(e=>e.isDirectory()&&!e.isSymbolicLink()).map(e=>({label:t.join("local-instances",e.name),root:t.join(r,e.name,"logs")})):[],a=[{label:"control-plane",root:t.join(e.dataDir,"logs")},{label:"desktop",root:t.join(e.dataDir,"log")},{label:"node-agent",root:t.join(i,"logs")},...o],d=[];let c=0;for(const e of a)for(const i of lf(e.root)){if(c>=df)break;const r=t.relative(e.root,i);if(!r||r.startsWith("..")||t.isAbsolute(r))continue;const o=t.join("logs",e.label,r),a=n.statSync(i).size,l=pf(i,t.join(s,o),df-c);l&&(c+=l,d.push({source:i,archivePath:o,bytes:l,originalBytes:a}))}n.writeFileSync(t.join(s,"manifest.json"),`${JSON.stringify({createdAt:(new Date).toISOString(),diagnosticLogsEnabled:e.diagnosticLogsEnabled,limits:{perFileBytes:af,totalBytes:df},files:d.map(({archivePath:e,bytes:t,originalBytes:n})=>({archivePath:e,bytes:t,originalBytes:n,truncated:t<n}))},null,2)}\n`,{mode:384});const l=["manifest.json",...n.existsSync(t.join(s,"logs"))?["logs"]:[]],p=z.create({cwd:s,gzip:!0,portable:!0,noMtime:!0},l),u=()=>n.rmSync(s,{recursive:!0,force:!0});return p.once("close",u),p.once("error",u),{filename:`task-handoff-diagnostic-logs-${(new Date).toISOString().replace(/[:.]/g,"-")}.tar.gz`,stream:p}}({dataDir:c.dataDir,nodeAgentDataDir:process.env.TASK_HANDOFF_DESKTOP_NODE_AGENT_DATA_DIR||process.env.TASK_HANDOFF_NODE_AGENT_DATA_DIR,diagnosticLogsEnabled:h});return s.header("content-type","application/gzip"),s.header("content-disposition",`attachment; filename="${i.filename}"`),s.send(i.stream)}),l.post("/api/ai-session-attachments",{bodyLimit:33554432},async(e,t)=>{try{return t.code(201).send({data:P.upload(e.body)})}catch(e){return t.code(400).send({error:{code:"AI_SESSION_ATTACHMENT_INVALID",message:e instanceof Error?e.message:String(e)}})}}),Dg({app:l,service:b,events:p,appSessionAggregator:O,aiSessionAggregator:R,aiSessionUnread:N,chatGateway:V,aiSessionAttachments:P,aiSessionAttachmentCache:_,nodeAgentTunnel:j,nodeEventSubscriber:K,errorPayload:qf}),function(e){const{app:t,authority:n,resolveTarget:s,projectTarget:i,eventHub:r}=e,o=e.runtime??new Ay,a=new WeakMap,d=(e,t)=>{const n=a.get(e);n&&(a.delete(e),n.tracked.release(),e.raw.removeListener("aborted",n.abort),t.raw.removeListener("close",n.abort))};t.all("/api/node-proxy/bindings/:bindingId/http/*",{config:nm,bodyLimit:o.maxRequestBodyBytes,logLevel:"silent",async onRequest(e,t){try{const s=Oy.parse(e.params).bindingId,i=My(n,s,e),r=function(e){const t=e.raw.url||e.url,n=/^\/api\/node-proxy\/bindings\/[^/]+\/http(\/[^#]*)$/.exec(t);if(!n||/%(?:2f|5c)/i.test(n[1]))throw Uy(rs.RouteInvalid,"Proxy route is invalid.",400);const s=Xn.safeParse(n[1]);if(!s.success)throw Uy(rs.RouteInvalid,s.error.issues[0]?.message||"Proxy route is invalid.",400);return s.data}(e),c=$y(e.headers),l=o.reserveHttp(i.id),p=()=>{l.controller.abort(Object.assign(new Error("Proxy HTTP consumer disconnected."),{name:"AbortError",code:"ABORT_ERR"})),d(e,t)};a.set(e,{binding:i,route:r,forwardedHeaders:c,tracked:l,abort:p,startedAt:performance.now()}),e.raw.once("aborted",p),t.raw.once("close",p)}catch(n){return By(t,n,e)}},async onError(e,t){d(e,t);const n=Wy(e.headers);n&&t.header("x-request-id",n)},async onResponse(e,t){d(e,t)}},async(e,i)=>{try{const o=a.get(e);if(!o)throw Uy(rs.TransportFailed,"Proxy request context is unavailable.",500,!0);const{binding:c,route:l,forwardedHeaders:p,tracked:u,abort:h,startedAt:g}=o;!function(e,t,n){const s=new URL(t,"https://node-agent.invalid").searchParams,i=[s.get("nodeId"),s.get("targetNodeId")];if(n&&"object"==typeof n&&!Array.isArray(n)){const e=n;"string"==typeof e.nodeId&&i.push(e.nodeId),"string"==typeof e.targetNodeId&&i.push(e.targetNodeId)}const r=i.find(t=>null!==t&&t!==e.targetNodeId);if(void 0!==r)throw Uy(rs.TargetMismatch,"Proxy request attempts to select a target outside its binding.",409,!1,{bindingId:e.id,targetNodeId:e.targetNodeId})}(c,l,e.body);const y=null==(r=e.body)?void 0:Buffer.isBuffer(r)?r:r instanceof Uint8Array||"string"==typeof r?Buffer.from(r):Buffer.from(JSON.stringify(r));u.acceptRequestBody(y?.byteLength??0);try{const{node:r,transport:o}=await s(c.targetNodeId);Ly(n,c,e),qy(c,r);const a=await o.requestStream(r,l,{method:e.method,headers:p,...y?{body:y}:{},signal:u.controller.signal}),d=performance.now()-g;return t.log.info({traceId:p[ba],requestId:p["x-request-id"],bindingId:c.id,targetNodeId:c.targetNodeId,routePath:new URL(l,"https://node-agent.invalid").pathname,statusCode:a.status,proxyForwardMs:d},"control-plane proxy request timing"),function(e,t,n,s,i,r,o,a){t.body&&n.beginResponseStream();const d=function(e,t){const n=Object.fromEntries([...es].flatMap(t=>{const n=e.headers.get(t);return null===n?[]:[[t,n]]}));return t&&(n["x-request-id"]=t),n}(t,r);d["server-timing"]=Sa(d["server-timing"],va("proxy_forward",a??0)),o&&!d[ba]&&(d[ba]=o);for(const[t,n]of Object.entries(d))e.header(t,n);const c=()=>{n.release(),i.raw.removeListener("aborted",s),e.raw.removeListener("close",s)};if(!t.body)return c(),e.code(t.status).send();const l=m.Readable.fromWeb(t.body);return n.controller.signal.addEventListener("abort",()=>{const e=n.controller.signal.reason;l.destroy(e instanceof Error?e:new Error("Proxy HTTP stream aborted."))},{once:!0}),l.on("data",e=>{try{n.acceptResponseChunk(e)}catch(e){l.destroy(e)}}),l.once("end",c),l.once("error",c),l.once("close",c),e.raw.once("close",()=>l.destroy()),e.code(t.status).send(l)}(i,a,u,h,e,p["x-request-id"],p[ba],d)}catch(t){throw d(e,i),t}}catch(t){return d(e,i),By(i,t,e)}var r}),t.get("/api/node-proxy/bindings/:bindingId/websocket",{websocket:!0,logLevel:"silent",config:nm},async(e,t)=>{let i;try{const r=Oy.parse(t.params).bindingId,a=My(n,r,t),d=_y.parse(t.query).route,{node:c,transport:l}=await s(a.targetNodeId);Ly(n,a,t),qy(a,c),i=o.openWebSocket(a.id,e),l.proxyWebSocket(c,i,d,function(e){const t=Hy(e,"sec-websocket-protocol").split(",").map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}(t.headers),$y(t.headers))}catch(t){const n=Fy(t);i?.close(1008,n.message),i||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,Gy(n.message))}}),t.get("/api/node-proxy/bindings/:bindingId/snapshot",{config:nm},async(e,t)=>{try{const t=Oy.parse(e.params).bindingId,a=My(n,t,e),{node:d}=await s(a.targetNodeId);Ly(n,a,e),qy(a,d);const c=i(a.targetNodeId);if(!c)throw Uy(rs.TargetUnavailable,"Proxy target no longer exists.",404,!1,{targetNodeId:a.targetNodeId});const l=r.cursor(a.targetNodeId),p=fs.parse({protocolVersion:Wn,binding:a,streamId:l.streamId,revision:l.revision,observedAt:(new Date).toISOString(),target:Ry(c)});if(o=p,Buffer.byteLength(JSON.stringify(o),"utf8")>Dy)throw Uy(rs.ResourceLimit,"Proxy target snapshot byte limit exceeded.",429,!0,{bindingId:a.id,resource:"snapshot-bytes",limit:Dy});return{data:p}}catch(n){return By(t,n,e)}var o}),t.get("/api/node-proxy/bindings/:bindingId/events",{websocket:!0,logLevel:"silent",config:nm},async(e,t)=>{let i,a,d;try{const c=Oy.parse(t.params).bindingId,l=My(n,c,t),p=Py.parse(t.query),{node:u}=await s(l.targetNodeId);Ly(n,l,t),qy(l,u),i=o.openWebSocket(l.id,e,()=>a?.()),i.on("message",()=>i?.close(1008,"Proxy event streams do not accept client messages."));const h=r.subscribe({bindingId:l.id,sourceControlPlaneId:l.sourceControlPlaneId,targetNodeId:l.targetNodeId},p.sinceRevision,e=>{i?.send(JSON.stringify(e))},()=>{i?.close(1011,"Proxy event delivery failed.")});a=h.close,d=o.registerBindingCleanup(l.id,a);const m=()=>{a?.(),d?.()};i.on("close",m),i.on("error",m),"snapshot-required"===h.kind?(a(),i.close(1008,"Proxy target snapshot is required.")):1!==i.readyState&&a()}catch(t){a?.(),d?.();const n=Fy(t);i?.close(1008,n.message),i||e.close(429===n.statusCode?1013:n.statusCode<500?1008:1011,Gy(n.message))}}),t.delete("/api/node-proxy/bindings/:bindingId",{config:nm},async(t,s)=>{try{const s=Oy.parse(t.params).bindingId;My(n,s,t);const i=n.revokeBinding(s),r=o.closeBinding(s);return e.onBindingRevoked?.(i),{data:{binding:i,closed:r}}}catch(e){return By(s,e,t)}})}({app:l,authority:L,resolveTarget:e=>{const t=b.requireNode(e);return{node:t,transport:b.resolveNodeAgentTransport(t)}},projectTarget:M,runtime:$,eventHub:B,onBindingRevoked:e=>p.publish("control-plane-proxy.binding.updated",{binding:e,audit:{action:"binding.revoke",actor:`control-plane:${e.sourceControlPlaneId}`}},{topic:"control-plane-proxy",scope:{nodeId:e.targetNodeId}})}),function(e){const{app:t,service:n,proxy:s,runtime:i,events:r,syncNodeEvents:o,actorId:a}=e;t.get("/api/control-plane-proxy/invites",async()=>({data:s.listInvites()})),t.post("/api/control-plane-proxy/invites",async(e,t)=>{const n=await a(e),i=s.createInvite(e.body,n);return r.publish("control-plane-proxy.invite.created",{invite:i.invite,audit:{action:"invite.create",actor:n}},{topic:"control-plane-proxy",scope:{nodeId:i.invite.targetNodeId}}),t.code(201).send({data:i})}),t.delete("/api/control-plane-proxy/invites/:id",async e=>{const t=await a(e),n=s.revokeInvite(Yy.parse(e.params).id);return r.publish("control-plane-proxy.invite.updated",{invite:n,audit:{action:"invite.revoke",actor:t}},{topic:"control-plane-proxy",scope:{nodeId:n.targetNodeId}}),{data:n}}),t.get("/api/control-plane-proxy/bindings",async()=>({data:s.listBindings()})),t.delete("/api/control-plane-proxy/bindings/:id",async e=>{const t=await a(e),n=Yy.parse(e.params).id,o=s.revokeBinding(n),d=i.closeBinding(n);return r.publish("control-plane-proxy.binding.updated",{binding:o,audit:{action:"binding.revoke",actor:t}},{topic:"control-plane-proxy",scope:{nodeId:o.targetNodeId}}),{data:{binding:o,closed:d}}}),t.get("/api/control-plane-proxy/diagnostics",async()=>({data:i.diagnostics()})),t.post("/api/node-proxy/claims",{config:em},async(e,t)=>{const n=s.claimInvite(e.body);return r.publish("control-plane-proxy.binding.created",{binding:n.binding,audit:{action:"binding.claim",actor:`control-plane:${n.binding.sourceControlPlaneId}`}},{topic:"control-plane-proxy",scope:{nodeId:n.binding.targetNodeId}}),t.code(201).send({data:n})}),t.get("/api/control-plane-proxy/pending-claims",async()=>({data:n.listPendingProxyClaims()})),t.post("/api/control-plane-proxy/claims",async(e,t)=>{const s=await n.claimProxyNode(e.body);return o?.(),r.publish("node.created",{nodeId:s.node.id}),t.code(201).send({data:s})}),t.post("/api/control-plane-proxy/pending-claims/:id/resume",async e=>{const t=Yy.parse(e.params).id;Qy.parse(e.body||{});const s=await n.resumeProxyClaim(t);return o?.(),r.publish("node.created",{nodeId:s.node.id}),{data:s}}),t.delete("/api/control-plane-proxy/pending-claims/:id",async e=>{const t=Xy.parse(e.query||{});return{data:await n.cancelProxyClaim(Yy.parse(e.params).id,"true"===t.force)}})}({app:l,service:b,proxy:L,runtime:$,events:p,syncNodeEvents:()=>K.syncNow(),actorId:async e=>{const t=await Bf(v,$f(e));return t?"user"===t.type?`user:${t.userId}`:"system"===t.type?`system:${t.reason}`:"cloud-account"===t.type?`cloud-account:${t.accountId}:${t.deviceSessionId}`:`chat-bridge:${t.bridgeId}`:"system:unknown"}}),function({app:e,service:t}){!function(e){for(const t of["application/octet-stream","application/x-www-form-urlencoded"])Kg(e,t);Kg(e,/^multipart\/form-data(?:;.*)?$/i)}(e),e.get("/api/app-access/session",{config:em},async e=>{const n=Jg(e.url),s="vnc"===e.query.mode?"vnc":"web"===e.query.mode?"web":"tty",i=await t.appAccessProxyTarget(n,s);return{data:{mode:s,instance:{id:i.instance.id,name:i.instance.name,projectId:i.instance.projectId,projectName:"string"==typeof i.instance.sourceSnapshot.name?i.instance.sourceSnapshot.name:void 0},session:i.session,expiresAt:i.access.expiresAt,ttySocketPath:"tty"===s?`/apps/access/tty/ws?token=${encodeURIComponent(n)}`:void 0,vncFramePath:"vnc"===s?Yg(n,i.access.sessionId,i.session):void 0}}}),e.get("/apps/access/tty/ws",{websocket:!0,config:em},async(e,n)=>{try{const s=await t.appAccessProxyTarget(Jg(n.url),"tty");await t.proxyInstanceWebSocket(s.instance.id,e,s.path,Lg(n.headers),Fg(n.headers))}catch{e.close(1011,"TTY access link is invalid or expired.")}});const n=async(e,n)=>{const s=n.params;try{const i=await t.appAccessProxyTarget(s.token||Jg(n.url),"vnc",s["*"]||"");await t.proxyInstanceWebSocket(i.instance.id,e,i.path,Lg(n.headers),Fg(n.headers))}catch{e.close(1011,"VNC access link is invalid or expired.")}};e.route({method:"GET",url:"/apps/access/vnc/proxy/*",config:em,wsHandler:n,handler:async(e,n)=>{const s=e.params,i=await t.appAccessProxyTarget(Jg(e.url),"vnc",s["*"]||"");return Gg(n,await Ug(t,n,i.instance.id,i.path,{method:e.method,headers:Bg(e.headers)}),i.instance.id,i.path)}}),e.route({method:"GET",url:"/apps/access/vnc/:token/proxy/*",config:em,wsHandler:n,handler:async(e,n)=>{const s=e.params,i=await t.appAccessProxyTarget(s.token,"vnc",s["*"]||"");return Gg(n,await Ug(t,n,i.instance.id,i.path,{method:e.method,headers:Bg(e.headers)}),i.instance.id,i.path)}}),e.all("/instances/:id",{bodyLimit:67108864},async(e,n)=>{const s=e.params;return"GET"===e.method||"HEAD"===e.method?n.redirect(`${Wg(s.id)}/`):Gg(n,await Ug(t,n,s.id,"/",{method:e.method,headers:Bg(e.headers),body:Vg(e.body)}),s.id,"/")}),e.route({method:"GET",url:"/instances/:id/*",wsHandler:async(e,n)=>{const s=n.params,i=s["*"]||"",r=n.url.indexOf("?"),o=r>=0?n.url.slice(r):"";try{await t.proxyInstanceWebSocket(s.id,e,`/${i}${o}`,Lg(n.headers),Fg(n.headers))}catch{e.close(1011,"Instance websocket endpoint is not reachable.")}},handler:async(e,n)=>{const s=e.params,i=s["*"]||"",r=e.url.indexOf("?"),o=`/${i}${r>=0?e.url.slice(r):""}`;return Gg(n,await Ug(t,n,s.id,o,{method:e.method,headers:Bg(e.headers)}),s.id,o)}}),e.route({method:["POST","PUT","PATCH","DELETE","OPTIONS"],url:"/instances/:id/*",bodyLimit:67108864,handler:async(e,n)=>{const s=e.params,i=s["*"]||"",r=e.url.indexOf("?"),o=r>=0?e.url.slice(r):"";return Hg(n,await Ug(t,n,s.id,`/${i}${o}`,{method:e.method,headers:Bg(e.headers),body:Vg(e.body)}))}})}({app:l,service:b}),l.get("*",{config:tm},async(e,t)=>n.existsSync(Y)?Lf(t,Y,"index.html"):t.code(404).send({error:{code:"CONTROL_PLANE_UI_NOT_BUILT",message:"Control plane API is running, but the Web UI static directory was not found."}})),H=setInterval(()=>{G().catch(e=>l.log.warn({error:e},"pending node pairing recovery failed"))},3e4),H.unref(),W=setInterval(()=>{b.runPersistenceMaintenance()},216e5),W.unref(),l}function Wf(e){const t=Number(e);if(!Number.isInteger(t)||t<=0||t>65535)throw new Error("Port must be a valid TCP port.");return t}function Gf(e){if("disabled"!==e&&"password"!==e)throw new Error("Auth mode must be disabled or password.");return e}(async function(){const n=new e.Command;n.name("task-handoff-control-plane").description("Run the TaskHandoff control plane.").version(C("@task-handoff/cli")).option("--host <host>","Control plane host",process.env.TASK_HANDOFF_CONTROL_PLANE_HOST||"127.0.0.1").option("-p, --port <port>","Control plane port",Wf,Number(process.env.TASK_HANDOFF_CONTROL_PLANE_PORT)||8081).option("--data-dir <path>","Control plane data directory").option("--static-dir <path>","Control plane Web UI static directory",process.env.TASK_HANDOFF_CONTROL_PLANE_STATIC_DIR||t.resolve(__dirname,"..","ui")).option("--auth-mode <mode>","Control plane auth mode: disabled or password",Gf,process.env.TASK_HANDOFF_CONTROL_PLANE_AUTH_MODE||"password").action(async e=>{await async function(e){const t=Cm(e.dataDir),n=Ym(Jm(),{dataDir:t.dataDir,host:e.host,port:e.port});try{const t=await Hf(e);t.addHook("onClose",async()=>{n.release()}),await t.listen({host:e.host,port:e.port})}catch(t){if(n.release(),t&&"object"==typeof t&&"EADDRINUSE"===t.code)throw Object.assign(new Error(`Control plane port ${e.host}:${e.port} is already in use.`),{statusCode:409,code:"CONTROL_PLANE_PORT_IN_USE",cause:t});throw t}}({host:e.host,port:e.port,dataDir:e.dataDir,staticDir:e.staticDir,auth:{mode:e.authMode}})}),n.command("credentials").description("Initialize or replace Control Plane administrator credentials while the service is stopped.").requiredOption("--username <username>","New administrator username").requiredOption("--password-stdin","Read the new password from standard input").option("--initialize-if-needed","Create the administrator only when none exists").option("--data-dir <path>","Control plane data directory").action(async e=>{if(process.stdin.isTTY)throw new Error("Pipe the new password to standard input when using --password-stdin.");const t=[];for await(const e of process.stdin)t.push(Buffer.isBuffer(e)?e:Buffer.from(e));const n=Buffer.concat(t).toString("utf8").replace(/\r?\n$/,"");if(e.initializeIfNeeded){const t=await async function(e,t,n={}){const s=Cm(e),i=Ym(n.lockPath||Jm(),{dataDir:s.dataDir});try{const e=new ia(s,{mode:"password"});return e.init(),e.state().requiresBootstrap?{created:!0,user:await e.bootstrapAdmin(t)}:{created:!1}}finally{i.release()}}(e.dataDir,{username:e.username,password:n});return void console.log(t.created?"created":"unchanged")}const s=await async function(e,t,n={}){const s=Cm(e),i=Ym(n.lockPath||Jm(),{dataDir:s.dataDir});try{const e=new ia(s,{mode:"password"});return e.init(),await e.replaceCredentials(t)}finally{i.release()}}(e.dataDir,{username:e.username,password:n});console.log(`Updated Control Plane credentials for ${s.username}. Existing sessions were revoked.`)}),await n.parseAsync(process.argv)})().catch(e=>{console.error(e instanceof Error?e.message:String(e)),process.exitCode=1});
|